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