@cryptotaxi247 / netdata / commits / 4cd931f5e

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