/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Fluent Bit * ========== * Copyright (C) 2015-2022 The Fluent Bit Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Metrics interface is a helper to gather general metrics from the core or * plugins at runtime. */ #include #include #include #include #include #include static int id_exists(int id, struct flb_metrics *metrics) { struct mk_list *head; struct flb_metric *metric; mk_list_foreach(head, &metrics->list) { metric = mk_list_entry(head, struct flb_metric, _head); if (metric->id == id) { return FLB_TRUE; } } return FLB_FALSE; } static int id_get(struct flb_metrics *metrics) { int id; int ret = FLB_FALSE; /* Try to use 'count' as an id */ id = metrics->count; while ((ret = id_exists(id, metrics)) == FLB_TRUE) { id++; } return id; } struct flb_metric *flb_metrics_get_id(int id, struct flb_metrics *metrics) { struct mk_list *head; struct flb_metric *m; mk_list_foreach(head, &metrics->list) { m = mk_list_entry(head, struct flb_metric, _head); if (m->id == id) { return m; } } return NULL; } struct flb_metrics *flb_metrics_create(const char *title) { int ret; struct flb_metrics *metrics; /* Create a metrics parent context */ metrics = flb_malloc(sizeof(struct flb_metrics)); if (!metrics) { flb_errno(); return NULL; } metrics->count = 0; /* Set metrics title */ ret = flb_metrics_title(title, metrics); if (ret == -1) { flb_free(metrics); return NULL; } /* List head for specific metrics under the context */ mk_list_init(&metrics->list); return metrics; } int flb_metrics_title(const char *title, struct flb_metrics *metrics) { int ret; size_t size = sizeof(metrics->title) - 1; ret = snprintf(metrics->title, size, "%s", title); if (ret == -1) { flb_errno(); return -1; } else if (ret >= size){ flb_warn("[%s] title '%s' was truncated", __FUNCTION__, title); } metrics->title_len = strlen(metrics->title); return 0; } int flb_metrics_add(int id, const char *title, struct flb_metrics *metrics) { int ret; struct flb_metric *m; size_t size; /* Create context */ m = flb_malloc(sizeof(struct flb_metric)); if (!m) { flb_errno(); return -1; } m->val = 0; size = sizeof(m->title) - 1; /* Write title */ ret = snprintf(m->title, size, "%s", title); if (ret == -1) { flb_errno(); flb_free(m); return -1; } else if (ret >= size) { flb_warn("[%s] title '%s' was truncated", __FUNCTION__, title); } m->title_len = strlen(m->title); /* Assign an ID */ if (id >= 0) { /* Check this new ID is available */ if (id_exists(id, metrics) == FLB_TRUE) { flb_error("[metrics] id=%i already exists for metric '%s'", id, metrics->title); flb_free(m); return -1; } } else { id = id_get(metrics); } /* Link to parent list */ mk_list_add(&m->_head, &metrics->list); m->id = id; metrics->count++; return id; } int flb_metrics_sum(int id, size_t val, struct flb_metrics *metrics) { struct flb_metric *m; m = flb_metrics_get_id(id, metrics); if (!m) { return -1; } m->val += val; return 0; } int flb_metrics_destroy(struct flb_metrics *metrics) { int count = 0; struct mk_list *tmp; struct mk_list *head; struct flb_metric *m; mk_list_foreach_safe(head, tmp, &metrics->list) { m = mk_list_entry(head, struct flb_metric, _head); mk_list_del(&m->_head); flb_free(m); count++; } flb_free(metrics); return count; } int flb_metrics_print(struct flb_metrics *metrics) { struct mk_list *head; struct flb_metric *m; printf("[metric dump] title => '%s'", metrics->title); mk_list_foreach(head, &metrics->list) { m = mk_list_entry(head, struct flb_metric, _head); printf(", '%s' => %lu", m->title, m->val); } printf("\n"); return 0; } /* Write metrics in messagepack format */ int flb_metrics_dump_values(char **out_buf, size_t *out_size, struct flb_metrics *me) { struct mk_list *head; struct flb_metric *m; msgpack_sbuffer mp_sbuf; msgpack_packer mp_pck; /* Prepare new outgoing buffer */ msgpack_sbuffer_init(&mp_sbuf); msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); msgpack_pack_map(&mp_pck, me->count); mk_list_foreach(head, &me->list) { m = mk_list_entry(head, struct flb_metric, _head); msgpack_pack_str(&mp_pck, m->title_len); msgpack_pack_str_body(&mp_pck, m->title, m->title_len); msgpack_pack_uint64(&mp_pck, m->val); } *out_buf = mp_sbuf.data; *out_size = mp_sbuf.size; return 0; } static int attach_uptime(struct flb_config *ctx, struct cmt *cmt, uint64_t ts, char *hostname) { double uptime; struct cmt_counter *c; /* uptime */ c = cmt_counter_create(cmt, "fluentbit", "", "uptime", "Number of seconds that Fluent Bit has been running.", 1, (char *[]) {"hostname"}); if (!c) { return -1; } uptime = time(NULL) - ctx->init_time; cmt_counter_set(c, ts, uptime, 1, (char *[]) {hostname}); return 0; } static int attach_process_start_time_seconds(struct flb_config *ctx, struct cmt *cmt, uint64_t ts, char *hostname) { double val; struct cmt_gauge *g; g = cmt_gauge_create(cmt, "fluentbit", "", "process_start_time_seconds", "Start time of the process since unix epoch in seconds.", 1, (char *[]) {"hostname"}); if (!g) { return -1; } val = (double) ctx->init_time; cmt_gauge_set(g, ts, val, 1, (char *[]) {hostname}); return 0; } static char *get_os_name() { #ifdef _WIN64 return "win64"; #elif _WIN32 return "win32"; #elif __APPLE__ || __MACH__ return "macos"; #elif __linux__ return "linux"; #elif __FreeBSD__ return "freebsd"; #elif __unix || __unix__ return "unix"; #else return "other"; #endif } static int attach_build_info(struct flb_config *ctx, struct cmt *cmt, uint64_t ts, char *hostname) { double val; char *os; struct cmt_gauge *g; g = cmt_gauge_create(cmt, "fluentbit", "build", "info", "Build version information.", 3, (char *[]) {"hostname", "version", "os"}); if (!g) { return -1; } val = (double) ctx->init_time; os = get_os_name(); cmt_gauge_set(g, ts, val, 3, (char *[]) {hostname, FLB_VERSION_STR, os}); return 0; } static int attach_hot_reload_info(struct flb_config *ctx, struct cmt *cmt, uint64_t ts, char *hostname) { double val; struct cmt_gauge *g; g = cmt_gauge_create(cmt, "fluentbit", "", "hot_reloaded_times", "Collect the count of hot reloaded times.", 1, (char *[]) {"hostname"}); if (!g) { return -1; } val = (double) ctx->hot_reloaded_count; cmt_gauge_set(g, ts, val, 1, (char *[]) {hostname}); return 0; } /* Append internal Fluent Bit metrics to context */ int flb_metrics_fluentbit_add(struct flb_config *ctx, struct cmt *cmt) { int ret; size_t ts; char hostname[128]; /* current timestamp */ ts = cfl_time_now(); /* get hostname */ ret = gethostname(hostname, sizeof(hostname) - 1); if (ret == -1) { strcpy(hostname, "unknown"); } /* Attach metrics to cmetrics context */ attach_uptime(ctx, cmt, ts, hostname); attach_process_start_time_seconds(ctx, cmt, ts, hostname); attach_build_info(ctx, cmt, ts, hostname); attach_hot_reload_info(ctx, cmt, ts, hostname); return 0; }