summaryrefslogtreecommitdiffstats
path: root/fluent-bit/plugins/in_thermal/in_thermal.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/plugins/in_thermal/in_thermal.c')
-rw-r--r--fluent-bit/plugins/in_thermal/in_thermal.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/fluent-bit/plugins/in_thermal/in_thermal.c b/fluent-bit/plugins/in_thermal/in_thermal.c
new file mode 100644
index 000000000..2eb9267de
--- /dev/null
+++ b/fluent-bit/plugins/in_thermal/in_thermal.c
@@ -0,0 +1,372 @@
+/* -*- 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.
+ */
+
+#include <fluent-bit/flb_input_plugin.h>
+#include <fluent-bit/flb_config.h>
+#include <fluent-bit/flb_pack.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <msgpack.h>
+
+#include "in_thermal.h"
+
+struct flb_input_plugin in_thermal_plugin;
+
+/* Default collection time: every 1 second (0 nanoseconds) */
+#define DEFAULT_INTERVAL_SEC "1"
+#define DEFAULT_INTERVAL_NSEC "0"
+
+#define IN_THERMAL_N_MAX 32
+#define IN_THERMAL_FILENAME_LEN 1024
+#define IN_THERMAL_TYPE_LEN 256
+
+struct temp_info
+{
+ char name[IN_THERMAL_FILENAME_LEN]; /* .../thermal_zoneX/... */
+ char type[IN_THERMAL_TYPE_LEN]; /* from /sys/class/thermal/thermal_zoneX/type */
+ double temp; /* from /sys/class/thermal/thermal_zoneX/temp */
+};
+
+/* Retrieve temperature(s) from the system (via /sys/class/thermal) */
+static inline int proc_temperature(struct flb_in_thermal_config *ctx,
+ struct temp_info *info, int n)
+{
+ int i, j;
+ DIR *d;
+ struct dirent *e;
+ char filename[IN_THERMAL_FILENAME_LEN];
+ FILE *f;
+ int temp;
+
+ d = opendir("/sys/class/thermal");
+ if (d == NULL) {
+ return -1;
+ }
+
+ i = 0;
+ while (i<n && (e = readdir(d))) {
+ if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) {
+ continue;
+ }
+
+ if (e->d_type == DT_REG) {
+ continue;
+ }
+
+#ifdef FLB_HAVE_REGEX
+ if (ctx->name_regex && !flb_regex_match(ctx->name_regex,
+ (unsigned char *) e->d_name,
+ strlen(e->d_name))) {
+ continue;
+ }
+#endif
+
+ if (!strncmp(e->d_name, "thermal_zone", 12)) {
+ strncpy(info[i].name, e->d_name, IN_THERMAL_FILENAME_LEN);
+ if (snprintf(filename, IN_THERMAL_FILENAME_LEN,
+ "/sys/class/thermal/%s/type", e->d_name) <=0 ) {
+ continue;
+ }
+
+ f = fopen(filename, "r");
+ if (!f) {
+ flb_errno();
+ flb_error("[in_thermal] cannot read %s", filename);
+ continue;
+ }
+
+ if (f && fgets(info[i].type, IN_THERMAL_TYPE_LEN, f) &&
+ strlen(info[i].type) > 1) {
+ /* Remove trailing \n */
+ for (j = 0; info[i].type[j]; ++j) {
+ if (info[i].type[j] == '\n') {
+ info[i].type[j] = 0;
+ break;
+ }
+ }
+ fclose(f);
+
+#ifdef FLB_HAVE_REGEX
+ if (ctx->type_regex &&
+ !flb_regex_match(ctx->type_regex,
+ (unsigned char *) info[i].type,
+ strlen(info[i].type))) {
+ continue;
+ }
+#endif
+
+ if (snprintf(filename, IN_THERMAL_FILENAME_LEN,
+ "/sys/class/thermal/%s/temp", e->d_name) <= 0) {
+ continue;
+ }
+ f = fopen(filename, "r");
+ if (f && fscanf(f, "%d", &temp) == 1) {
+ info[i].temp = temp/1000.0;
+ ++i;
+ }
+ }
+
+ if (f) {
+ fclose(f);
+ }
+ }
+ }
+
+ closedir(d);
+ return i;
+}
+
+/* Init temperature input */
+static int in_thermal_init(struct flb_input_instance *in,
+ struct flb_config *config, void *data)
+{
+ int ret;
+ struct flb_in_thermal_config *ctx;
+ struct temp_info info[IN_THERMAL_N_MAX];
+ (void) data;
+
+ /* Allocate space for the configuration */
+ ctx = flb_calloc(1, sizeof(struct flb_in_thermal_config));
+ if (!ctx) {
+ flb_errno();
+ return -1;
+ }
+ ctx->ins = in;
+
+ ctx->log_encoder = flb_log_event_encoder_create(FLB_LOG_EVENT_FORMAT_DEFAULT);
+
+ if (ctx->log_encoder == NULL) {
+ flb_plg_error(in, "could not initialize event encoder");
+ flb_free(ctx);
+
+ return -1;
+ }
+
+ /* Load the config map */
+ ret = flb_input_config_map_set(in, (void *)ctx);
+ if (ret == -1) {
+ flb_log_event_encoder_destroy(ctx->log_encoder);
+ flb_free(ctx);
+ flb_plg_error(in, "unable to load configuration");
+ return -1;
+ }
+
+ /* Collection time setting */
+ if (ctx->interval_sec <= 0 && ctx->interval_nsec <= 0) {
+ /* Illegal settings. Override them. */
+ ctx->interval_sec = atoi(DEFAULT_INTERVAL_SEC);
+ ctx->interval_nsec = atoi(DEFAULT_INTERVAL_NSEC);
+ }
+
+#ifdef FLB_HAVE_REGEX
+ if (ctx->name_rgx && strcmp(ctx->name_rgx, "") != 0) {
+ ctx->name_regex = flb_regex_create(ctx->name_rgx);
+ if (!ctx->name_regex) {
+ flb_plg_error(ctx->ins, "invalid 'name_regex' config value");
+ }
+ }
+
+ if (ctx->type_rgx && strcmp(ctx->type_rgx, "") != 0) {
+ ctx->type_regex = flb_regex_create(ctx->type_rgx);
+ if (!ctx->type_regex) {
+ flb_plg_error(ctx->ins, "invalid 'type_regex' config value");
+ }
+ }
+#endif
+
+ ctx->prev_device_num = proc_temperature(ctx, info, IN_THERMAL_N_MAX);
+ if (!ctx->prev_device_num) {
+ flb_plg_warn(ctx->ins, "thermal device file not found");
+ }
+
+ /* Set the context */
+ flb_input_set_context(in, ctx);
+
+ /* Set our collector based on time, temperature every 1 second */
+ ret = flb_input_set_collector_time(in,
+ in_thermal_collect,
+ ctx->interval_sec,
+ ctx->interval_nsec,
+ config);
+ if (ret == -1) {
+ flb_plg_error(ctx->ins,
+ "Could not set collector for temperature input plugin");
+
+ flb_log_event_encoder_destroy(ctx->log_encoder);
+ flb_free(ctx);
+
+ return -1;
+ }
+ ctx->coll_fd = ret;
+
+ return 0;
+}
+
+/* Callback to gather temperature */
+int in_thermal_collect(struct flb_input_instance *i_ins,
+ struct flb_config *config, void *in_context)
+{
+ int n;
+ int i;
+ int ret;
+ struct temp_info info[IN_THERMAL_N_MAX];
+ struct flb_in_thermal_config *ctx = in_context;
+
+ (void) config;
+
+ /* Get the current temperature(s) */
+ n = proc_temperature(ctx, info, IN_THERMAL_N_MAX);
+ if (n != ctx->prev_device_num) {
+ flb_plg_info(ctx->ins, "the number of thermal devices changed %d -> %d",
+ ctx->prev_device_num, n);
+ }
+ ctx->prev_device_num = n;
+ if (!n) {
+ return 0;
+ }
+
+ /*
+ * Store the new data into the MessagePack buffer
+ */
+
+ for (i = 0; i < n; ++i) {
+ ret = flb_log_event_encoder_begin_record(ctx->log_encoder);
+
+ if (ret == FLB_EVENT_ENCODER_SUCCESS) {
+ ret = flb_log_event_encoder_set_current_timestamp(ctx->log_encoder);
+ }
+
+ if (ret == FLB_EVENT_ENCODER_SUCCESS) {
+ ret = flb_log_event_encoder_append_body_values(
+ ctx->log_encoder,
+ FLB_LOG_EVENT_CSTRING_VALUE("name"),
+ FLB_LOG_EVENT_CSTRING_VALUE(info[i].name),
+
+ FLB_LOG_EVENT_CSTRING_VALUE("type"),
+ FLB_LOG_EVENT_CSTRING_VALUE(info[i].type),
+
+ FLB_LOG_EVENT_CSTRING_VALUE("temp"),
+ FLB_LOG_EVENT_DOUBLE_VALUE(info[i].temp));
+ }
+
+ if (ret == FLB_EVENT_ENCODER_SUCCESS) {
+ ret = flb_log_event_encoder_commit_record(ctx->log_encoder);
+ }
+
+ flb_plg_trace(ctx->ins, "%s temperature %0.2f", info[i].name, info[i].temp);
+ }
+
+ if (ret == FLB_EVENT_ENCODER_SUCCESS) {
+ flb_input_log_append(ctx->ins, NULL, 0,
+ ctx->log_encoder->output_buffer,
+ ctx->log_encoder->output_length);
+ ret = 0;
+ }
+ else {
+ flb_plg_error(ctx->ins, "log event encoding error : %d", ret);
+
+ ret = -1;
+ }
+
+ flb_log_event_encoder_reset(ctx->log_encoder);
+
+ return 0;
+}
+
+static void in_thermal_pause(void *data, struct flb_config *config)
+{
+ struct flb_in_thermal_config *ctx = data;
+ flb_input_collector_pause(ctx->coll_fd, ctx->ins);
+}
+
+static void in_thermal_resume(void *data, struct flb_config *config)
+{
+ struct flb_in_thermal_config *ctx = data;
+ flb_input_collector_resume(ctx->coll_fd, ctx->ins);
+}
+
+static int in_thermal_exit(void *data, struct flb_config *config)
+{
+ (void) *config;
+ struct flb_in_thermal_config *ctx = data;
+
+ if (ctx->log_encoder != NULL) {
+ flb_log_event_encoder_destroy(ctx->log_encoder);
+ }
+
+#ifdef FLB_HAVE_REGEX
+ if (ctx && ctx->name_regex) {
+ flb_regex_destroy(ctx->name_regex);
+ }
+ if (ctx && ctx->type_regex) {
+ flb_regex_destroy(ctx->type_regex);
+ }
+#endif
+
+ flb_free(ctx);
+
+ return 0;
+}
+
+static struct flb_config_map config_map[] = {
+ {
+ FLB_CONFIG_MAP_INT, "interval_sec", DEFAULT_INTERVAL_SEC,
+ 0, FLB_TRUE, offsetof(struct flb_in_thermal_config, interval_sec),
+ "Set the collector interval"
+ },
+ {
+ FLB_CONFIG_MAP_INT, "interval_nsec", DEFAULT_INTERVAL_NSEC,
+ 0, FLB_TRUE, offsetof(struct flb_in_thermal_config, interval_nsec),
+ "Set the collector interval (nanoseconds)"
+ },
+#ifdef FLB_HAVE_REGEX
+ {
+ FLB_CONFIG_MAP_STR, "name_regex", NULL,
+ 0, FLB_TRUE, offsetof(struct flb_in_thermal_config, name_rgx),
+ "Set thermal name regular expression filter"
+ },
+ {
+ FLB_CONFIG_MAP_STR, "type_regex", NULL,
+ 0, FLB_TRUE, offsetof(struct flb_in_thermal_config, type_rgx),
+ "Set thermal type regular expression filter"
+ },
+#endif /* FLB_HAVE_REGEX */
+ /* EOF */
+ {0}
+};
+
+/* Plugin reference */
+struct flb_input_plugin in_thermal_plugin = {
+ .name = "thermal",
+ .description = "Thermal",
+ .cb_init = in_thermal_init,
+ .cb_pre_run = NULL,
+ .cb_collect = in_thermal_collect,
+ .cb_flush_buf = NULL,
+ .cb_pause = in_thermal_pause,
+ .cb_resume = in_thermal_resume,
+ .cb_exit = in_thermal_exit,
+ .config_map = config_map
+};