Hardware (Windows.plugin) (#20522)
thiagoftsm committed
Jun 23, 2025 at 19:16 UTC
4cd931f5e82eb176425ba5e1ae74a525d1ea35f9
10 files changed
+373
-86
CMakeLists.txt
+3
-1
@@ -1603,6 +1603,7 @@ set(INTERNAL_COLLECTORS_FILES
1603
src/collectors/common-contexts/mem-swap.h
1604
src/collectors/common-contexts/mem-pgfaults.h
1605
src/collectors/common-contexts/mem-available.h
1606
+ src/collectors/common-contexts/power-supply.h
1607
)
1608
1609
set(INTERCOMMUNICATION_COLLECTORS_FILES
@@ -2043,6 +2044,7 @@ set(WINDOWS_PLUGIN_FILES
2044
src/collectors/windows.plugin/GetSystemUptime.c
2045
src/collectors/windows.plugin/GetSystemRAM.c
2046
src/collectors/windows.plugin/GetSystemCPU.c
2047
+ src/collectors/windows.plugin/GetPowerSupply.c
2048
src/collectors/windows.plugin/perflib-adcs.c
2049
src/collectors/windows.plugin/perflib-adfs.c
2050
src/collectors/windows.plugin/perflib-rrd.c
@@ -3200,7 +3202,7 @@ target_link_libraries(netdata PRIVATE
3202
"$<$<BOOL:${ENABLE_WEBRTC}>:LibDataChannel::LibDataChannelStatic>"
3203
"$<$<BOOL:${ENABLE_H2O}>:h2o>"
3204
"$<$<BOOL:${CURL_FOUND}>:PkgConfig::CURL>"
3203
- "$<$<BOOL:${OS_WINDOWS}>:odbc32>"
3205
+ "$<$<BOOL:${OS_WINDOWS}>:odbc32;setupapi>"
3206
)
3207
3208
netdata_add_protobuf(netdata)
src/collectors/common-contexts/common-contexts.h
+1
@@ -35,5 +35,6 @@ typedef void (*instance_labels_cb_t)(RRDSET *st, void *data);
35
#include "disk-await.h"
36
#include "disk-svctm.h"
37
#include "disk-avgsz.h"
38
+#include "power-supply.h"
39
40
#endif //NETDATA_COMMON_CONTEXTS_H
src/collectors/common-contexts/power-supply.h
new
+99
@@ -0,0 +1,99 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_POWER_SUPPLY_H
4
+#define NETDATA_POWER_SUPPLY_H
5
+
6
+#include "common-contexts.h"
7
+
8
+struct ps_property_dim {
9
+ char *name;
10
+ char *filename;
11
+ int fd;
12
+
13
+ RRDDIM *rd;
14
+ unsigned long long value;
15
+ int always_zero;
16
+
17
+ struct ps_property_dim *next;
18
+};
19
+
20
+struct ps_property {
21
+ char *name;
22
+ char *title;
23
+ char *units;
24
+
25
+ long priority;
26
+
27
+ RRDSET *st;
28
+
29
+ struct ps_property_dim *property_dim_root;
30
+
31
+ struct ps_property *next;
32
+};
33
+
34
+struct simple_property {
35
+ char *filename;
36
+ int fd;
37
+
38
+ RRDSET *st;
39
+ RRDDIM *rd;
40
+ bool ok;
41
+ unsigned long long value;
42
+};
43
+
44
+struct power_supply {
45
+ char *name;
46
+ uint32_t hash;
47
+ int found;
48
+
49
+ struct simple_property *capacity, *power;
50
+
51
+ struct ps_property *property_root;
52
+
53
+ struct power_supply *next;
54
+};
55
+
56
+static inline void add_labels_to_power_supply(struct power_supply *ps, RRDSET *st) {
57
+ rrdlabels_add(st->rrdlabels, "device", ps->name, RRDLABEL_SRC_AUTO);
58
+}
59
+
60
+static inline void rrdset_create_simple_prop(
61
+ struct power_supply *ps,
62
+ struct simple_property *prop,
63
+ char *title,
64
+ char *dim,
65
+ collected_number divisor,
66
+ char *units,
67
+ long priority,
68
+ int update_every)
69
+{
70
+ if (unlikely(!prop->st)) {
71
+ char id[RRD_ID_LENGTH_MAX + 1], context[RRD_ID_LENGTH_MAX + 1];
72
+ snprintfz(id, RRD_ID_LENGTH_MAX, "powersupply_%s", dim);
73
+ snprintfz(context, RRD_ID_LENGTH_MAX, "powersupply.%s", dim);
74
+
75
+ prop->st = rrdset_create_localhost(
76
+ id,
77
+ ps->name,
78
+ NULL,
79
+ dim,
80
+ context,
81
+ title,
82
+ units,
83
+ _COMMON_PLUGIN_NAME,
84
+ _COMMON_PLUGIN_MODULE_NAME,
85
+ priority,
86
+ update_every,
87
+ RRDSET_TYPE_LINE);
88
+
89
+ add_labels_to_power_supply(ps, prop->st);
90
+ }
91
+
92
+ if (unlikely(!prop->rd))
93
+ prop->rd = rrddim_add(prop->st, dim, NULL, 1, divisor, RRD_ALGORITHM_ABSOLUTE);
94
+ rrddim_set_by_pointer(prop->st, prop->rd, prop->value);
95
+
96
+ rrdset_done(prop->st);
97
+}
98
+
99
+#endif //NETDATA_POWER_SUPPLY_H
src/collectors/proc.plugin/metadata.yaml
+2
-2
@@ -5008,8 +5008,8 @@ modules:
5008
problems:
5009
list: []
5010
alerts:
5011
- - name: linux_power_supply_capacity
5012
- link: https://github.com/netdata/netdata/blob/master/src/health/health.d/linux_power_supply.conf
5011
+ - name: power_supply_capacity
5012
+ link: https://github.com/netdata/netdata/blob/master/src/health/health.d/power_supply_capacity.conf
5013
metric: powersupply.capacity
5014
info: percentage of remaining power supply capacity
5015
metrics:
src/collectors/proc.plugin/sys_class_power_supply.c
+4
-82
@@ -5,6 +5,10 @@
5
#define PLUGIN_PROC_MODULE_POWER_SUPPLY_NAME "/sys/class/power_supply"
6
#define PROP_VALUE_LENGTH_MAX 30
7
8
+#define _COMMON_PLUGIN_NAME PLUGIN_PROC_NAME
9
+#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_POWER_SUPPLY_NAME
10
+#include "../common-contexts/common-contexts.h"
11
+
12
const char *ps_property_names[] = { "charge", "energy", "voltage"};
13
const char *ps_property_titles[] = {"Battery charge", "Battery energy", "Power supply voltage"};
14
const char *ps_property_units[] = { "Ah", "Wh", "V"};
@@ -20,54 +24,6 @@ const char *ps_property_dim_names[] = {"empty_design", "empty", "now", "full", "
24
"empty_design", "empty", "now", "full", "full_design",
25
"min_design", "min", "now", "max", "max_design"};
26
23
-struct ps_property_dim {
24
- char *name;
25
- char *filename;
26
- int fd;
27
-
28
- RRDDIM *rd;
29
- unsigned long long value;
30
- int always_zero;
31
-
32
- struct ps_property_dim *next;
33
-};
34
-
35
-struct ps_property {
36
- char *name;
37
- char *title;
38
- char *units;
39
-
40
- long priority;
41
-
42
- RRDSET *st;
43
-
44
- struct ps_property_dim *property_dim_root;
45
-
46
- struct ps_property *next;
47
-};
48
-
49
-struct simple_property {
50
- char *filename;
51
- int fd;
52
-
53
- RRDSET *st;
54
- RRDDIM *rd;
55
- bool ok;
56
- unsigned long long value;
57
-};
58
-
59
-struct power_supply {
60
- char *name;
61
- uint32_t hash;
62
- int found;
63
-
64
- struct simple_property *capacity, *power;
65
-
66
- struct ps_property *property_root;
67
-
68
- struct power_supply *next;
69
-};
70
-
27
static struct power_supply *power_supply_root = NULL;
28
static int files_num = 0;
29
@@ -128,10 +84,6 @@ void power_supply_free(struct power_supply *ps) {
84
}
85
}
86
131
-static void add_labels_to_power_supply(struct power_supply *ps, RRDSET *st) {
132
- rrdlabels_add(st->rrdlabels, "device", ps->name, RRDLABEL_SRC_AUTO);
133
-}
134
-
87
static void read_simple_property(struct simple_property *prop, bool keep_fds_open) {
88
char buffer[PROP_VALUE_LENGTH_MAX + 1];
89
@@ -165,36 +117,6 @@ static void read_simple_property(struct simple_property *prop, bool keep_fds_ope
117
return;
118
}
119
168
-static void rrdset_create_simple_prop(struct power_supply *ps, struct simple_property *prop, char *title, char *dim, collected_number divisor, char *units, long priority, int update_every) {
169
- if(unlikely(!prop->st)) {
170
- char id[RRD_ID_LENGTH_MAX + 1], context[RRD_ID_LENGTH_MAX + 1];
171
- snprintfz(id, RRD_ID_LENGTH_MAX, "powersupply_%s", dim);
172
- snprintfz(context, RRD_ID_LENGTH_MAX, "powersupply.%s", dim);
173
-
174
- prop->st = rrdset_create_localhost(
175
- id
176
- , ps->name
177
- , NULL
178
- , dim
179
- , context
180
- , title
181
- , units
182
- , PLUGIN_PROC_NAME
183
- , PLUGIN_PROC_MODULE_POWER_SUPPLY_NAME
184
- , priority
185
- , update_every
186
- , RRDSET_TYPE_LINE
187
- );
188
-
189
- add_labels_to_power_supply(ps, prop->st);
190
- }
191
-
192
- if(unlikely(!prop->rd)) prop->rd = rrddim_add(prop->st, dim, NULL, 1, divisor, RRD_ALGORITHM_ABSOLUTE);
193
- rrddim_set_by_pointer(prop->st, prop->rd, prop->value);
194
-
195
- rrdset_done(prop->st);
196
-}
197
-
120
int do_sys_class_power_supply(int update_every, usec_t dt) {
121
(void)dt;
122
static int do_capacity = -1, do_power = -1, do_property[3] = {-1};
src/collectors/windows.plugin/GetPowerSupply.c
new
+161
@@ -0,0 +1,161 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "windows_plugin.h"
4
+#include "windows-internals.h"
5
+
6
+#define _COMMON_PLUGIN_NAME "windows.plugin"
7
+#define _COMMON_PLUGIN_MODULE_NAME "GetPowerSupply"
8
+#include "../common-contexts/common-contexts.h"
9
+
10
+#define INITGUID
11
+#include <windows.h>
12
+
13
+#include <initguid.h>
14
+#include <devguid.h> // for GUID_DEVCLASS_BATTERY
15
+#include <setupapi.h> // for SetupDi*
16
+#include <batclass.h> // for BATTERY_*
17
+
18
+static struct power_supply *power_supply_root = NULL;
19
+
20
+static inline void netdata_allocate_power_supply(char *path)
21
+{
22
+ power_supply_root = callocz(1, sizeof(struct power_supply));
23
+ power_supply_root->capacity = callocz(1, sizeof(struct simple_property));
24
+}
25
+
26
+static inline void netdata_update_power_supply_values(
27
+ HANDLE hBattery,
28
+ struct simple_property *voltage,
29
+ BATTERY_INFORMATION *bi,
30
+ BATTERY_QUERY_INFORMATION *bqi)
31
+{
32
+ BATTERY_WAIT_STATUS bws = {0};
33
+ bws.BatteryTag = bqi->BatteryTag;
34
+ DWORD dwOut;
35
+
36
+ BATTERY_STATUS bs;
37
+ if (!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL))
38
+ return;
39
+
40
+ if (bs.Capacity != BATTERY_UNKNOWN_CAPACITY) {
41
+ NETDATA_DOUBLE num = bs.Capacity;
42
+ NETDATA_DOUBLE den = bi->FullChargedCapacity;
43
+ num /= den;
44
+
45
+ power_supply_root->capacity->value = (unsigned long long)(num * 100.0);
46
+ }
47
+
48
+ if (bs.Voltage != BATTERY_UNKNOWN_VOLTAGE) {
49
+ voltage->value = bs.Voltage;
50
+ }
51
+}
52
+
53
+static void netdata_power_supply_plot(struct simple_property *voltage, int update_every)
54
+{
55
+ rrdset_create_simple_prop(
56
+ power_supply_root,
57
+ power_supply_root->capacity,
58
+ "Battery capacity",
59
+ "capacity",
60
+ 1,
61
+ "percentage",
62
+ NETDATA_CHART_PRIO_POWER_SUPPLY_CAPACITY,
63
+ update_every);
64
+
65
+ rrdset_create_simple_prop(
66
+ power_supply_root,
67
+ voltage,
68
+ "Power supply voltage",
69
+ "now",
70
+ 1000,
71
+ "v",
72
+ NETDATA_CHART_PRIO_POWER_SUPPLY_VOLTAGE,
73
+ update_every);
74
+}
75
+
76
+int do_GetPowerSupply(int update_every, usec_t dt __maybe_unused)
77
+{
78
+ static struct simple_property voltage;
79
+
80
+ HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
81
+ if (hdev == INVALID_HANDLE_VALUE)
82
+ return 1;
83
+
84
+ SP_DEVICE_INTERFACE_DATA did = {0};
85
+ did.cbSize = sizeof(did);
86
+
87
+ for (LONG i = 0; i < 32 && SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVCLASS_BATTERY, 0, &did); i++) {
88
+ DWORD cbRequired = 0;
89
+ PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = NULL;
90
+ HANDLE hBattery = NULL;
91
+ SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);
92
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
93
+ goto endPowerSupply;
94
+
95
+ pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
96
+ if (!pdidd)
97
+ goto endPowerSupply;
98
+
99
+ pdidd->cbSize = sizeof(*pdidd);
100
+ if (!SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0))
101
+ goto endPowerSupply;
102
+
103
+ hBattery = CreateFile(
104
+ pdidd->DevicePath,
105
+ GENERIC_READ | GENERIC_WRITE,
106
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
107
+ NULL,
108
+ OPEN_EXISTING,
109
+ FILE_ATTRIBUTE_NORMAL,
110
+ NULL);
111
+ if (hBattery == INVALID_HANDLE_VALUE)
112
+ goto endPowerSupply;
113
+
114
+ BATTERY_QUERY_INFORMATION bqi = {0};
115
+
116
+ DWORD dwWait = 0;
117
+ DWORD dwOut;
118
+
119
+ if (!DeviceIoControl(
120
+ hBattery,
121
+ IOCTL_BATTERY_QUERY_TAG,
122
+ &dwWait,
123
+ sizeof(dwWait),
124
+ &bqi.BatteryTag,
125
+ sizeof(bqi.BatteryTag),
126
+ &dwOut,
127
+ NULL) &&
128
+ bqi.BatteryTag)
129
+ goto endPowerSupply;
130
+
131
+ BATTERY_INFORMATION bi = {0};
132
+ bqi.InformationLevel = BatteryInformation;
133
+
134
+ if (!DeviceIoControl(
135
+ hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi, sizeof(bi), &dwOut, NULL))
136
+ goto endPowerSupply;
137
+
138
+ if (!power_supply_root)
139
+ netdata_allocate_power_supply(pdidd->DevicePath);
140
+
141
+ char name[RRD_ID_LENGTH_MAX + 1];
142
+ snprintfz(name, sizeof(name), "BAT%d", i + 1);
143
+
144
+ power_supply_root->name = name;
145
+ power_supply_root->capacity->filename = power_supply_root->name;
146
+
147
+ netdata_update_power_supply_values(hBattery, &voltage, &bi, &bqi);
148
+
149
+ netdata_power_supply_plot(&voltage, update_every);
150
+ endPowerSupply:
151
+ if (hBattery)
152
+ CloseHandle(hBattery);
153
+
154
+ if (pdidd)
155
+ LocalFree(pdidd);
156
+ }
157
+
158
+ SetupDiDestroyDeviceInfoList(hdev);
159
+
160
+ return 0;
161
+}
src/collectors/windows.plugin/metadata.yaml
+93
@@ -985,6 +985,99 @@ modules:
985
chart_type: line
986
dimensions:
987
- name: temperature
988
+ - meta:
989
+ plugin_name: windows.plugin
990
+ module_name: GetPowerSupply
991
+ monitored_instance:
992
+ name: Power supply
993
+ link: "https://learn.microsoft.com/en-us/windows/win32/power/power-management-portal"
994
+ categories:
995
+ - data-collection.windows-systems
996
+ icon_filename: "powersupply.svg"
997
+ related_resources:
998
+ integrations:
999
+ list: []
1000
+ info_provided_to_referring_integrations:
1001
+ description: ""
1002
+ keywords:
1003
+ - power supply
1004
+ most_popular: false
1005
+ overview:
1006
+ data_collection:
1007
+ metrics_description: |
1008
+ This collector monitors power supply statistics on Windows systems.
1009
+ method_description: |
1010
+ It uses Windows Internal API to retrieve available data.
1011
+ supported_platforms:
1012
+ include: ["windows"]
1013
+ exclude: []
1014
+ multi_instance: false
1015
+ additional_permissions:
1016
+ description: ""
1017
+ default_behavior:
1018
+ auto_detection:
1019
+ description: |
1020
+ The collector automatically detects all of the metrics, no further configuration is required.
1021
+ limits:
1022
+ description: ""
1023
+ performance_impact:
1024
+ description: ""
1025
+ setup:
1026
+ prerequisites:
1027
+ list: []
1028
+ configuration:
1029
+ file:
1030
+ section_name: "[plugin:windows]"
1031
+ name: "netdata.conf"
1032
+ description: "The Netdata main configuration file."
1033
+ options:
1034
+ description: ""
1035
+ folding:
1036
+ title: "Config Option"
1037
+ enabled: false
1038
+ list:
1039
+ - name: GetPowerSupply
1040
+ description: An option to enable or disable the data collection.
1041
+ default_value: yes
1042
+ required: false
1043
+ examples:
1044
+ folding:
1045
+ enabled: false
1046
+ title: ""
1047
+ list: []
1048
+ troubleshooting:
1049
+ problems:
1050
+ list: []
1051
+ alerts:
1052
+ - name: power_supply_capacity
1053
+ link: https://github.com/netdata/netdata/blob/master/src/health/health.d/power_supply_capacity.conf
1054
+ metric: powersupply.capacity
1055
+ info: percentage of remaining power supply capacity
1056
+ metrics:
1057
+ folding:
1058
+ title: Metrics
1059
+ enabled: false
1060
+ description: ""
1061
+ availability: []
1062
+ scopes:
1063
+ - name: Power Supply
1064
+ description: "These metrics refer to Power Supply device."
1065
+ labels:
1066
+ - name: device
1067
+ description: Device name delivered as a Windows path.
1068
+ metrics:
1069
+ - name: powersupply.capacity
1070
+ description: Battery capacity
1071
+ unit: "percentage"
1072
+ chart_type: line
1073
+ dimensions:
1074
+ - name: capacity
1075
+ - name: powersupply.voltage
1076
+ description: Power supply voltage
1077
+ unit: "V"
1078
+ chart_type: line
1079
+ dimensions:
1080
+ - name: now
1081
- meta:
1082
plugin_name: windows.plugin
1083
module_name: PerflibWebService
src/collectors/windows.plugin/windows_plugin.c
+5
@@ -24,6 +24,11 @@ static struct proc_module {
24
.enabled = CONFIG_BOOLEAN_YES,
25
.update_every = UPDATE_EVERY_MIN,
26
.func = do_GetSystemRAM},
27
+ {.name = "GetPowerSupply",
28
+ .dim = "GetPowerSupply",
29
+ .enabled = CONFIG_BOOLEAN_YES,
30
+ .update_every = UPDATE_EVERY_MIN,
31
+ .func = do_GetPowerSupply},
32
33
// the same is provided by PerflibProcessor, with more detailed analysis
34
//{.name = "GetSystemCPU", .dim = "GetSystemCPU", .enabled = CONFIG_BOOLEAN_YES,
src/collectors/windows.plugin/windows_plugin.h
+4
@@ -15,9 +15,13 @@ void *win_plugin_main(void *ptr);
15
16
extern char windows_shared_buffer[8192];
17
18
+// Windows API
19
int do_GetSystemUptime(int update_every, usec_t dt);
20
int do_GetSystemRAM(int update_every, usec_t dt);
21
int do_GetSystemCPU(int update_every, usec_t dt);
22
+int do_GetPowerSupply(int update_every, usec_t dt);
23
+
24
+// Perflib
25
int do_PerflibStorage(int update_every, usec_t dt);
26
int do_PerflibNetwork(int update_every, usec_t dt);
27
int do_PerflibProcesses(int update_every, usec_t dt);
src/health/health.d/power_supply_capacity.conf
renamed
+1
-1
@@ -1,6 +1,6 @@
1
# Alert on low battery capacity.
2
3
- template: linux_power_supply_capacity
3
+ template: power_supply_capacity
4
on: powersupply.capacity
5
class: Utilization
6
type: Power Supply