Skip to content

Commit c50e81b

Browse files
committed
in_node_exporter_metrics: Implement metrics of powersupply
Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
1 parent 1e69f37 commit c50e81b

7 files changed

Lines changed: 560 additions & 2 deletions

File tree

plugins/in_node_exporter_metrics/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ set(src
2020
ne_config.c
2121
ne_systemd.c
2222
ne_thermalzone.c
23+
ne_powersupply.c
2324
ne.c
2425
)
2526

plugins/in_node_exporter_metrics/ne.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "ne_nvme.h"
4848
#include "ne_thermalzone.h"
4949
#include "ne_hwmon.h"
50+
#include "ne_powersupply.h"
5051

5152
/*
5253
* Update the metrics, this function is invoked every time 'scrape_interval'
@@ -204,6 +205,7 @@ static int in_ne_init(struct flb_input_instance *in,
204205
mk_list_add(&nvme_collector._head, &ctx->collectors);
205206
mk_list_add(&thermalzone_collector._head, &ctx->collectors);
206207
mk_list_add(&hwmon_collector._head, &ctx->collectors);
208+
mk_list_add(&powersupply_collector._head, &ctx->collectors);
207209

208210
mk_list_foreach(head, &ctx->collectors) {
209211
coll = mk_list_entry(head, struct flb_ne_collector, _head);

plugins/in_node_exporter_metrics/ne.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
/* Default enabled metrics */
3434

3535
#ifdef __linux__
36-
#define NE_DEFAULT_ENABLED_METRICS "cpu,cpufreq,meminfo,diskstats,filesystem,uname,stat,time,loadavg,vmstat,netdev,netstat,sockstat,filefd,systemd,nvme,thermal_zone,hwmon"
36+
#define NE_DEFAULT_ENABLED_METRICS "cpu,cpufreq,meminfo,diskstats,filesystem,uname,stat,time,loadavg,vmstat,netdev,netstat,sockstat,filefd,systemd,nvme,thermal_zone,hwmon,powersupplyclass"
3737
#elif __APPLE__
38-
#define NE_DEFAULT_ENABLED_METRICS "cpu,loadavg,meminfo,diskstats,uname,netdev"
38+
#define NE_DEFAULT_ENABLED_METRICS "cpu,loadavg,meminfo,diskstats,uname,netdev,powersupplyclass"
3939
#endif
4040

4141
/* filesystem: regex for ignoring mount points and filesystem types */
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2015-2026 The Fluent Bit Authors
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
#ifdef __linux__
21+
#include "ne_powersupply_linux.c"
22+
#elif __APPLE__
23+
#include "ne_powersupply_darwin.c"
24+
#else
25+
26+
#include "ne.h"
27+
28+
struct flb_ne_collector powersupply_collector = {
29+
.name = "powersupplyclass",
30+
.cb_init = NULL,
31+
.cb_update = NULL,
32+
.cb_exit = NULL
33+
};
34+
35+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2015-2026 The Fluent Bit Authors
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
#ifndef FLB_IN_NE_POWERSUPPLY_H
21+
#define FLB_IN_NE_POWERSUPPLY_H
22+
23+
#include "ne.h"
24+
25+
extern struct flb_ne_collector powersupply_collector;
26+
27+
#endif
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2+
3+
/* Fluent Bit
4+
* ==========
5+
* Copyright (C) 2015-2026 The Fluent Bit Authors
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
#include <CoreFoundation/CoreFoundation.h>
21+
#include <IOKit/ps/IOPowerSources.h>
22+
#include <IOKit/ps/IOPSKeys.h>
23+
24+
#include "ne.h"
25+
26+
static struct cmt_gauge *ps_current_capacity;
27+
static struct cmt_gauge *ps_max_capacity;
28+
static struct cmt_gauge *ps_design_capacity;
29+
static struct cmt_gauge *ps_nominal_capacity;
30+
static struct cmt_gauge *ps_time_to_empty;
31+
static struct cmt_gauge *ps_time_to_full;
32+
static struct cmt_gauge *ps_voltage;
33+
static struct cmt_gauge *ps_current;
34+
static struct cmt_gauge *ps_temperature;
35+
static struct cmt_gauge *ps_present;
36+
static struct cmt_gauge *ps_charging;
37+
static struct cmt_gauge *ps_charged;
38+
static struct cmt_gauge *ps_internal_failure;
39+
static struct cmt_gauge *ps_battery_health;
40+
41+
static int cf_number_to_double(CFTypeRef value, double *out)
42+
{
43+
if (value == NULL || CFGetTypeID(value) != CFNumberGetTypeID()) {
44+
return -1;
45+
}
46+
47+
if (!CFNumberGetValue((CFNumberRef) value, kCFNumberDoubleType, out)) {
48+
return -1;
49+
}
50+
51+
return 0;
52+
}
53+
54+
static int cf_boolean_to_double(CFTypeRef value, double *out)
55+
{
56+
if (value == NULL || CFGetTypeID(value) != CFBooleanGetTypeID()) {
57+
return -1;
58+
}
59+
60+
*out = CFBooleanGetValue((CFBooleanRef) value) ? 1.0 : 0.0;
61+
return 0;
62+
}
63+
64+
static int set_numeric_metric(struct cmt_gauge *gauge,
65+
CFDictionaryRef description,
66+
CFStringRef key,
67+
uint64_t ts,
68+
const char *name,
69+
double divisor)
70+
{
71+
CFTypeRef value;
72+
double out;
73+
char *labels[] = {(char *) name};
74+
75+
value = CFDictionaryGetValue(description, key);
76+
if (cf_number_to_double(value, &out) == -1) {
77+
return -1;
78+
}
79+
80+
cmt_gauge_set(gauge, ts, out / divisor, 1, (char const * const *) labels);
81+
return 0;
82+
}
83+
84+
static int set_boolean_metric(struct cmt_gauge *gauge,
85+
CFDictionaryRef description,
86+
CFStringRef key,
87+
uint64_t ts,
88+
const char *name)
89+
{
90+
CFTypeRef value;
91+
double out;
92+
char *labels[] = {(char *) name};
93+
94+
value = CFDictionaryGetValue(description, key);
95+
if (cf_boolean_to_double(value, &out) == -1) {
96+
return -1;
97+
}
98+
99+
cmt_gauge_set(gauge, ts, out, 1, (char const * const *) labels);
100+
return 0;
101+
}
102+
103+
static int update_power_source(struct flb_ne *ctx,
104+
CFTypeRef source,
105+
CFTypeRef info,
106+
uint64_t ts)
107+
{
108+
CFDictionaryRef description;
109+
CFTypeRef name_value;
110+
char name[128];
111+
CFTypeRef battery_health_value;
112+
char battery_health[64];
113+
char *health_labels_good[] = {name, "Good"};
114+
char *health_labels_fair[] = {name, "Fair"};
115+
char *health_labels_poor[] = {name, "Poor"};
116+
117+
(void) ctx;
118+
119+
description = IOPSGetPowerSourceDescription(info, source);
120+
if (description == NULL) {
121+
return -1;
122+
}
123+
124+
name_value = CFDictionaryGetValue(description, CFSTR(kIOPSNameKey));
125+
if (name_value == NULL || CFGetTypeID(name_value) != CFStringGetTypeID()) {
126+
return -1;
127+
}
128+
129+
if (!CFStringGetCString((CFStringRef) name_value, name,
130+
sizeof(name), kCFStringEncodingUTF8)) {
131+
return -1;
132+
}
133+
134+
set_numeric_metric(ps_current_capacity, description, CFSTR(kIOPSCurrentCapacityKey), ts, name, 1.0);
135+
set_numeric_metric(ps_max_capacity, description, CFSTR(kIOPSMaxCapacityKey), ts, name, 1.0);
136+
set_numeric_metric(ps_design_capacity, description, CFSTR(kIOPSDesignCapacityKey), ts, name, 1.0);
137+
set_numeric_metric(ps_nominal_capacity, description, CFSTR(kIOPSNominalCapacityKey), ts, name, 1.0);
138+
set_numeric_metric(ps_time_to_empty, description, CFSTR(kIOPSTimeToEmptyKey), ts, name, 60.0);
139+
set_numeric_metric(ps_time_to_full, description, CFSTR(kIOPSTimeToFullChargeKey), ts, name, 60.0);
140+
set_numeric_metric(ps_voltage, description, CFSTR(kIOPSVoltageKey), ts, name, 1000.0);
141+
set_numeric_metric(ps_current, description, CFSTR(kIOPSCurrentKey), ts, name, 1000.0);
142+
set_numeric_metric(ps_temperature, description, CFSTR(kIOPSTemperatureKey), ts, name, 1.0);
143+
144+
set_boolean_metric(ps_present, description, CFSTR(kIOPSIsPresentKey), ts, name);
145+
set_boolean_metric(ps_charging, description, CFSTR(kIOPSIsChargingKey), ts, name);
146+
set_boolean_metric(ps_charged, description, CFSTR(kIOPSIsChargedKey), ts, name);
147+
set_boolean_metric(ps_internal_failure, description, CFSTR(kIOPSInternalFailureKey), ts, name);
148+
149+
battery_health_value = CFDictionaryGetValue(description, CFSTR(kIOPSBatteryHealthKey));
150+
if (battery_health_value != NULL &&
151+
CFGetTypeID(battery_health_value) == CFStringGetTypeID() &&
152+
CFStringGetCString((CFStringRef) battery_health_value, battery_health,
153+
sizeof(battery_health), kCFStringEncodingUTF8)) {
154+
cmt_gauge_set(ps_battery_health, ts, strcmp(battery_health, "Good") == 0 ? 1.0 : 0.0,
155+
2, (char const * const *) health_labels_good);
156+
cmt_gauge_set(ps_battery_health, ts, strcmp(battery_health, "Fair") == 0 ? 1.0 : 0.0,
157+
2, (char const * const *) health_labels_fair);
158+
cmt_gauge_set(ps_battery_health, ts, strcmp(battery_health, "Poor") == 0 ? 1.0 : 0.0,
159+
2, (char const * const *) health_labels_poor);
160+
}
161+
162+
return 0;
163+
}
164+
165+
static int ne_powersupply_init(struct flb_ne *ctx)
166+
{
167+
char *label[] = {"power_supply"};
168+
169+
ps_current_capacity = cmt_gauge_create(ctx->cmt, "node", "powersupply", "current_capacity",
170+
"Current battery capacity.", 1, label);
171+
ps_max_capacity = cmt_gauge_create(ctx->cmt, "node", "powersupply", "max_capacity",
172+
"Maximum battery capacity.", 1, label);
173+
ps_design_capacity = cmt_gauge_create(ctx->cmt, "node", "powersupply", "design_capacity",
174+
"Design battery capacity.", 1, label);
175+
ps_nominal_capacity = cmt_gauge_create(ctx->cmt, "node", "powersupply", "nominal_capacity",
176+
"Nominal battery capacity.", 1, label);
177+
ps_time_to_empty = cmt_gauge_create(ctx->cmt, "node", "powersupply", "time_to_empty_seconds",
178+
"Estimated time to empty in seconds.", 1, label);
179+
ps_time_to_full = cmt_gauge_create(ctx->cmt, "node", "powersupply", "time_to_full_seconds",
180+
"Estimated time to full charge in seconds.", 1, label);
181+
ps_voltage = cmt_gauge_create(ctx->cmt, "node", "powersupply", "voltage_volt",
182+
"Battery voltage in volts.", 1, label);
183+
ps_current = cmt_gauge_create(ctx->cmt, "node", "powersupply", "current_ampere",
184+
"Battery current in amperes.", 1, label);
185+
ps_temperature = cmt_gauge_create(ctx->cmt, "node", "powersupply", "temp_celsius",
186+
"Battery temperature in celsius.", 1, label);
187+
188+
ps_present = cmt_gauge_create(ctx->cmt, "node", "powersupply", "present",
189+
"Power supply present status.", 1, label);
190+
ps_charging = cmt_gauge_create(ctx->cmt, "node", "powersupply", "charging",
191+
"Power supply charging status.", 1, label);
192+
ps_charged = cmt_gauge_create(ctx->cmt, "node", "powersupply", "charged",
193+
"Power supply charged status.", 1, label);
194+
ps_internal_failure = cmt_gauge_create(ctx->cmt, "node", "powersupply", "internal_failure",
195+
"Power supply internal failure status.", 1, label);
196+
ps_battery_health = cmt_gauge_create(ctx->cmt, "node", "powersupply", "battery_health",
197+
"Power supply battery health status.", 2,
198+
(char *[]) {"power_supply", "state"});
199+
200+
return 0;
201+
}
202+
203+
static int ne_powersupply_update(struct flb_input_instance *ins,
204+
struct flb_config *config, void *in_context)
205+
{
206+
struct flb_ne *ctx;
207+
uint64_t ts;
208+
CFTypeRef info;
209+
CFArrayRef list;
210+
CFIndex i;
211+
212+
(void) ins;
213+
(void) config;
214+
215+
ctx = in_context;
216+
ts = cfl_time_now();
217+
218+
info = IOPSCopyPowerSourcesInfo();
219+
if (info == NULL) {
220+
return -1;
221+
}
222+
223+
list = IOPSCopyPowerSourcesList(info);
224+
if (list == NULL) {
225+
CFRelease(info);
226+
return -1;
227+
}
228+
229+
for (i = 0; i < CFArrayGetCount(list); i++) {
230+
update_power_source(ctx, CFArrayGetValueAtIndex(list, i), info, ts);
231+
}
232+
233+
CFRelease(list);
234+
CFRelease(info);
235+
236+
return 0;
237+
}
238+
239+
struct flb_ne_collector powersupply_collector = {
240+
.name = "powersupplyclass",
241+
.cb_init = ne_powersupply_init,
242+
.cb_update = ne_powersupply_update,
243+
.cb_exit = NULL
244+
};

0 commit comments

Comments
 (0)