Coverage Report

Created: 2023-01-10 07:10

/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
}