/src/fluent-bit/src/flb_metrics.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2015-2022 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 | | /* |
21 | | * Metrics interface is a helper to gather general metrics from the core or |
22 | | * plugins at runtime. |
23 | | */ |
24 | | |
25 | | #include <fluent-bit/flb_info.h> |
26 | | #include <fluent-bit/flb_mem.h> |
27 | | #include <fluent-bit/flb_version.h> |
28 | | #include <fluent-bit/flb_utils.h> |
29 | | #include <fluent-bit/flb_metrics.h> |
30 | | #include <msgpack.h> |
31 | | |
32 | | static int id_exists(int id, struct flb_metrics *metrics) |
33 | 1.02k | { |
34 | 1.02k | struct mk_list *head; |
35 | 1.02k | struct flb_metric *metric; |
36 | | |
37 | 2.49k | mk_list_foreach(head, &metrics->list) { |
38 | 2.49k | metric = mk_list_entry(head, struct flb_metric, _head); |
39 | 2.49k | if (metric->id == id) { |
40 | 0 | return FLB_TRUE; |
41 | 0 | } |
42 | 2.49k | } |
43 | | |
44 | 1.02k | return FLB_FALSE; |
45 | 1.02k | } |
46 | | |
47 | | static int id_get(struct flb_metrics *metrics) |
48 | 0 | { |
49 | 0 | int id; |
50 | 0 | int ret = FLB_FALSE; |
51 | | |
52 | | /* Try to use 'count' as an id */ |
53 | 0 | id = metrics->count; |
54 | |
|
55 | 0 | while ((ret = id_exists(id, metrics)) == FLB_TRUE) { |
56 | 0 | id++; |
57 | 0 | } |
58 | |
|
59 | 0 | return id; |
60 | 0 | } |
61 | | |
62 | | struct flb_metric *flb_metrics_get_id(int id, struct flb_metrics *metrics) |
63 | 79.8k | { |
64 | 79.8k | struct mk_list *head; |
65 | 79.8k | struct flb_metric *m; |
66 | | |
67 | 119k | mk_list_foreach(head, &metrics->list) { |
68 | 119k | m = mk_list_entry(head, struct flb_metric, _head); |
69 | 119k | if (m->id == id) { |
70 | 79.8k | return m; |
71 | 79.8k | } |
72 | 119k | } |
73 | | |
74 | 0 | return NULL; |
75 | 79.8k | } |
76 | | |
77 | | struct flb_metrics *flb_metrics_create(const char *title) |
78 | 227 | { |
79 | 227 | int ret; |
80 | 227 | struct flb_metrics *metrics; |
81 | | |
82 | | /* Create a metrics parent context */ |
83 | 227 | metrics = flb_malloc(sizeof(struct flb_metrics)); |
84 | 227 | if (!metrics) { |
85 | 0 | flb_errno(); |
86 | 0 | return NULL; |
87 | 0 | } |
88 | 227 | metrics->count = 0; |
89 | | |
90 | | /* Set metrics title */ |
91 | 227 | ret = flb_metrics_title(title, metrics); |
92 | 227 | if (ret == -1) { |
93 | 0 | flb_free(metrics); |
94 | 0 | return NULL; |
95 | 0 | } |
96 | | |
97 | | /* List head for specific metrics under the context */ |
98 | 227 | mk_list_init(&metrics->list); |
99 | 227 | return metrics; |
100 | 227 | } |
101 | | |
102 | | int flb_metrics_title(const char *title, struct flb_metrics *metrics) |
103 | 227 | { |
104 | 227 | int ret; |
105 | 227 | size_t size = sizeof(metrics->title) - 1; |
106 | | |
107 | 227 | ret = snprintf(metrics->title, size, "%s", title); |
108 | 227 | if (ret == -1) { |
109 | 0 | flb_errno(); |
110 | 0 | return -1; |
111 | 0 | } |
112 | 227 | else if (ret >= size){ |
113 | 0 | flb_warn("[%s] title '%s' was truncated", __FUNCTION__, title); |
114 | 0 | } |
115 | 227 | metrics->title_len = strlen(metrics->title); |
116 | 227 | return 0; |
117 | 227 | } |
118 | | |
119 | | int flb_metrics_add(int id, const char *title, struct flb_metrics *metrics) |
120 | 1.02k | { |
121 | 1.02k | int ret; |
122 | 1.02k | struct flb_metric *m; |
123 | 1.02k | size_t size; |
124 | | |
125 | | /* Create context */ |
126 | 1.02k | m = flb_malloc(sizeof(struct flb_metric)); |
127 | 1.02k | if (!m) { |
128 | 0 | flb_errno(); |
129 | 0 | return -1; |
130 | 0 | } |
131 | 1.02k | m->val = 0; |
132 | 1.02k | size = sizeof(m->title) - 1; |
133 | | |
134 | | /* Write title */ |
135 | 1.02k | ret = snprintf(m->title, size, "%s", title); |
136 | 1.02k | if (ret == -1) { |
137 | 0 | flb_errno(); |
138 | 0 | flb_free(m); |
139 | 0 | return -1; |
140 | 0 | } |
141 | 1.02k | else if (ret >= size) { |
142 | 0 | flb_warn("[%s] title '%s' was truncated", __FUNCTION__, title); |
143 | 0 | } |
144 | | |
145 | 1.02k | m->title_len = strlen(m->title); |
146 | | |
147 | | /* Assign an ID */ |
148 | 1.02k | if (id >= 0) { |
149 | | /* Check this new ID is available */ |
150 | 1.02k | if (id_exists(id, metrics) == FLB_TRUE) { |
151 | 0 | flb_error("[metrics] id=%i already exists for metric '%s'", |
152 | 0 | id, metrics->title); |
153 | 0 | flb_free(m); |
154 | 0 | return -1; |
155 | 0 | } |
156 | 1.02k | } |
157 | 0 | else { |
158 | 0 | id = id_get(metrics); |
159 | 0 | } |
160 | | |
161 | | /* Link to parent list */ |
162 | 1.02k | mk_list_add(&m->_head, &metrics->list); |
163 | 1.02k | m->id = id; |
164 | 1.02k | metrics->count++; |
165 | | |
166 | 1.02k | return id; |
167 | 1.02k | } |
168 | | |
169 | | int flb_metrics_sum(int id, size_t val, struct flb_metrics *metrics) |
170 | 79.8k | { |
171 | 79.8k | struct flb_metric *m; |
172 | | |
173 | 79.8k | m = flb_metrics_get_id(id, metrics); |
174 | 79.8k | if (!m) { |
175 | 0 | return -1; |
176 | 0 | } |
177 | | |
178 | 79.8k | m->val += val; |
179 | 79.8k | return 0; |
180 | 79.8k | } |
181 | | |
182 | | int flb_metrics_destroy(struct flb_metrics *metrics) |
183 | 224 | { |
184 | 224 | int count = 0; |
185 | 224 | struct mk_list *tmp; |
186 | 224 | struct mk_list *head; |
187 | 224 | struct flb_metric *m; |
188 | | |
189 | 1.00k | mk_list_foreach_safe(head, tmp, &metrics->list) { |
190 | 1.00k | m = mk_list_entry(head, struct flb_metric, _head); |
191 | 1.00k | mk_list_del(&m->_head); |
192 | 1.00k | flb_free(m); |
193 | 1.00k | count++; |
194 | 1.00k | } |
195 | | |
196 | 224 | flb_free(metrics); |
197 | 224 | return count; |
198 | 224 | } |
199 | | |
200 | | int flb_metrics_print(struct flb_metrics *metrics) |
201 | 0 | { |
202 | 0 | struct mk_list *head; |
203 | 0 | struct flb_metric *m; |
204 | |
|
205 | 0 | printf("[metric dump] title => '%s'", metrics->title); |
206 | |
|
207 | 0 | mk_list_foreach(head, &metrics->list) { |
208 | 0 | m = mk_list_entry(head, struct flb_metric, _head); |
209 | 0 | printf(", '%s' => %lu", m->title, m->val); |
210 | 0 | } |
211 | 0 | printf("\n"); |
212 | |
|
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | | /* Write metrics in messagepack format */ |
217 | | int flb_metrics_dump_values(char **out_buf, size_t *out_size, |
218 | | struct flb_metrics *me) |
219 | 244 | { |
220 | 244 | struct mk_list *head; |
221 | 244 | struct flb_metric *m; |
222 | 244 | msgpack_sbuffer mp_sbuf; |
223 | 244 | msgpack_packer mp_pck; |
224 | | |
225 | | /* Prepare new outgoing buffer */ |
226 | 244 | msgpack_sbuffer_init(&mp_sbuf); |
227 | 244 | msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); |
228 | | |
229 | 244 | msgpack_pack_map(&mp_pck, me->count); |
230 | | |
231 | 1.09k | mk_list_foreach(head, &me->list) { |
232 | 1.09k | m = mk_list_entry(head, struct flb_metric, _head); |
233 | 1.09k | msgpack_pack_str(&mp_pck, m->title_len); |
234 | 1.09k | msgpack_pack_str_body(&mp_pck, m->title, m->title_len); |
235 | 1.09k | msgpack_pack_uint64(&mp_pck, m->val); |
236 | 1.09k | } |
237 | | |
238 | 244 | *out_buf = mp_sbuf.data; |
239 | 244 | *out_size = mp_sbuf.size; |
240 | | |
241 | 244 | return 0; |
242 | 244 | } |
243 | | |
244 | | static int attach_uptime(struct flb_config *ctx, struct cmt *cmt, |
245 | | uint64_t ts, char *hostname) |
246 | 0 | { |
247 | 0 | double uptime; |
248 | 0 | struct cmt_counter *c; |
249 | | |
250 | | /* uptime */ |
251 | 0 | c = cmt_counter_create(cmt, "fluentbit", "", "uptime", |
252 | 0 | "Number of seconds that Fluent Bit has been running.", |
253 | 0 | 1, (char *[]) {"hostname"}); |
254 | 0 | if (!c) { |
255 | 0 | return -1; |
256 | 0 | } |
257 | | |
258 | 0 | uptime = time(NULL) - ctx->init_time; |
259 | |
|
260 | 0 | cmt_counter_set(c, ts, uptime, 1, (char *[]) {hostname}); |
261 | 0 | return 0; |
262 | 0 | } |
263 | | |
264 | | static int attach_process_start_time_seconds(struct flb_config *ctx, |
265 | | struct cmt *cmt, |
266 | | uint64_t ts, char *hostname) |
267 | 0 | { |
268 | 0 | double val; |
269 | 0 | struct cmt_gauge *g; |
270 | |
|
271 | 0 | g = cmt_gauge_create(cmt, "fluentbit", "", "process_start_time_seconds", |
272 | 0 | "Start time of the process since unix epoch in seconds.", |
273 | 0 | 1, (char *[]) {"hostname"}); |
274 | 0 | if (!g) { |
275 | 0 | return -1; |
276 | 0 | } |
277 | | |
278 | 0 | val = (double) ctx->init_time; |
279 | 0 | cmt_gauge_set(g, ts, val, 1, (char *[]) {hostname}); |
280 | 0 | return 0; |
281 | 0 | } |
282 | | |
283 | | static char *get_os_name() |
284 | 0 | { |
285 | | #ifdef _WIN64 |
286 | | return "win64"; |
287 | | #elif _WIN32 |
288 | | return "win32"; |
289 | | #elif __APPLE__ || __MACH__ |
290 | | return "macos"; |
291 | | #elif __linux__ |
292 | 0 | return "linux"; |
293 | | #elif __FreeBSD__ |
294 | | return "freebsd"; |
295 | | #elif __unix || __unix__ |
296 | | return "unix"; |
297 | | #else |
298 | | return "other"; |
299 | | #endif |
300 | 0 | } |
301 | | |
302 | | static int attach_build_info(struct flb_config *ctx, struct cmt *cmt, uint64_t ts, |
303 | | char *hostname) |
304 | 0 | { |
305 | 0 | double val; |
306 | 0 | char *os; |
307 | 0 | struct cmt_gauge *g; |
308 | |
|
309 | 0 | g = cmt_gauge_create(cmt, "fluentbit", "build", "info", |
310 | 0 | "Build version information.", |
311 | 0 | 3, (char *[]) {"hostname", "version", "os"}); |
312 | 0 | if (!g) { |
313 | 0 | return -1; |
314 | 0 | } |
315 | | |
316 | 0 | val = (double) ctx->init_time; |
317 | 0 | os = get_os_name(); |
318 | |
|
319 | 0 | cmt_gauge_set(g, ts, val, 3, (char *[]) {hostname, FLB_VERSION_STR, os}); |
320 | 0 | return 0; |
321 | 0 | } |
322 | | |
323 | | /* Append internal Fluent Bit metrics to context */ |
324 | | int flb_metrics_fluentbit_add(struct flb_config *ctx, struct cmt *cmt) |
325 | 0 | { |
326 | 0 | int ret; |
327 | 0 | size_t ts; |
328 | 0 | char hostname[128]; |
329 | | |
330 | | /* current timestamp */ |
331 | 0 | ts = cfl_time_now(); |
332 | | |
333 | | /* get hostname */ |
334 | 0 | ret = gethostname(hostname, sizeof(hostname) - 1); |
335 | 0 | if (ret == -1) { |
336 | 0 | strcpy(hostname, "unknown"); |
337 | 0 | } |
338 | | |
339 | | /* Attach metrics to cmetrics context */ |
340 | 0 | attach_uptime(ctx, cmt, ts, hostname); |
341 | 0 | attach_process_start_time_seconds(ctx, cmt, ts, hostname); |
342 | 0 | attach_build_info(ctx, cmt, ts, hostname); |
343 | |
|
344 | 0 | return 0; |
345 | 0 | } |