From 8004a97d0179978056a164dfac4355d0836227d0 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Sat, 23 Feb 2008 17:08:57 +0100 Subject: [PATCH] src/utils_logtail.[ch]: Implement a module that parses logfiles using the `utils_tail' and `utils_match' modules. --- src/utils_logtail.c | 473 +++++++++++++------------------------------- src/utils_logtail.h | 149 +++++--------- src/utils_match.c | 4 +- src/utils_match.h | 4 +- src/utils_tail.c | 2 +- src/utils_tail.h | 4 +- 6 files changed, 198 insertions(+), 438 deletions(-) diff --git a/src/utils_logtail.c b/src/utils_logtail.c index 2b69ba65..94fdb790 100644 --- a/src/utils_logtail.c +++ b/src/utils_logtail.c @@ -1,6 +1,7 @@ /* * collectd - src/utils_logtail.c * Copyright (C) 2007-2008 C-Ware, Inc. + * Copyright (C) 2008 Florian Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,6 +18,7 @@ * * Author: * Luke Heberling + * Florian Forster * * Description: * Encapsulates useful code to plugins which must parse a log file. @@ -25,404 +27,207 @@ #include "collectd.h" #include "common.h" #include "plugin.h" +#include "utils_match.h" #include "utils_tail.h" -#include "utils_llist.h" -#include "utils_avltree.h" +#include "utils_logtail.h" -struct logtail_instance_s +struct cu_logtail_match_s { - char *name; + cu_match_t *match; + void *user_data; + int (*submit) (cu_match_t *match, void *user_data); + void (*free) (void *user_data); +}; +typedef struct cu_logtail_match_s cu_logtail_match_t; + +struct cu_logtail_s +{ + int flags; cu_tail_t *tail; - c_avl_tree_t *tree; - llist_t *list; - uint cache_size; - unsigned long *counters; + + cu_logtail_match_t *matches; + size_t matches_num; }; -typedef struct logtail_instance_s logtail_instance_t; -static void submit (const char *plugin, const char *plugin_instance, - const char *name, value_t value) +/* + * Private functions + */ +static int simple_submit_match (cu_match_t *match, void *user_data) { + cu_logtail_simple_t *data = (cu_logtail_simple_t *) user_data; + cu_match_value_t *match_value; value_list_t vl = VALUE_LIST_INIT; value_t values[1]; - values[0] = value; + match_value = (cu_match_value_t *) match_get_user_data (match); + if (match_value == NULL) + return (-1); + + values[0] = match_value->value; vl.values = values; vl.values_len = 1; vl.time = time (NULL); sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, plugin, sizeof (vl.plugin)); - sstrncpy (vl.type_instance, "", sizeof (vl.type_instance)); - sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); - - plugin_dispatch_values (name, &vl); -} /* static void submit */ + sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, data->plugin_instance, + sizeof (vl.plugin_instance)); + sstrncpy (vl.type_instance, data->type_instance, + sizeof (vl.type_instance)); -static int destroy_instance (logtail_instance_t *inst) -{ - if (inst == NULL) - return (-1); - - sfree (inst->name); - if (inst->tail != NULL) - { - cu_tail_destroy (inst->tail); - inst->tail = NULL; - } - if (inst->tree != NULL) - { - c_avl_destroy (inst->tree); - inst->tree = NULL; - } - assert ((inst->list == NULL) || (llist_size (inst->list) == 0)); - if (inst->list != NULL) - { - llist_destroy (inst->list); - inst->list = NULL; - } - - sfree (inst->counters); - sfree (inst); + plugin_dispatch_values (data->type, &vl); return (0); -} /* int destroy_instance */ +} /* int simple_submit_match */ -int logtail_term (llist_t **instances) +static int tail_callback (void *data, char *buf, int buflen) { - llentry_t *entry; - llentry_t *prev; - - llentry_t *lentry; - llentry_t *lprev; - - logtail_instance_t *instance; - - if (*instances != NULL) - { - entry = llist_head (*instances); - while (entry) - { - prev = entry; - entry = entry->next; - - instance = prev->value; - if (instance->list != NULL) - { - lentry = llist_head (instance->list); - while (lentry) - { - lprev = lentry; - lentry = lentry->next; - if (lprev->key != NULL) - free (lprev->key); - if (lprev->value != NULL) - free (lprev->value); - llist_remove (instance->list, lprev); - llentry_destroy (lprev); - } - } - - llist_remove (*instances, prev); - llentry_destroy (prev); - destroy_instance (instance); - } + cu_logtail_t *obj = (cu_logtail_t *) data; + int i; - llist_destroy (*instances); - *instances = NULL; - } + for (i = 0; i < obj->matches_num; i++) + match_apply (obj->matches[i].match, buf); return (0); -} /* int logtail_term */ +} /* int tail_callback */ -int logtail_init (llist_t **instances) +/* + * Public functions + */ +cu_logtail_t *logtail_create (const char *filename) { - if (*instances == NULL) - *instances = llist_create(); + cu_logtail_t *obj; - return (*instances == NULL); -} /* int logtail_init */ + obj = (cu_logtail_t *) malloc (sizeof (cu_logtail_t)); + if (obj == NULL) + return (NULL); + memset (obj, '\0', sizeof (cu_logtail_t)); -int logtail_read (llist_t **instances, tailfunc *func, char *plugin, - char **counter_instances) -{ - llentry_t *entry; - char buffer[2048]; - int status; - int i; - - for (entry = llist_head (*instances); entry != NULL; entry = entry->next ) + obj->tail = cu_tail_create (filename); + if (obj->tail == NULL) { - logtail_instance_t *instance = (logtail_instance_t *) entry->value; - - status = cu_tail_read (instance->tail, buffer, sizeof (buffer), - func, instance); - if (status != 0) - continue; - - for (i = 0; counter_instances[i] != NULL; i++) - { - char *name = counter_instances[i]; - value_t value; - - value.counter = (counter_t) instance->counters[i]; - - submit (plugin, instance->name, name, value); - } + sfree (obj); + return (NULL); } - return (0); -} /* int logtail_read */ + return (obj); +} /* cu_logtail_t *logtail_create */ -int logtail_config (llist_t **instances, oconfig_item_t *ci, char *plugin, - char **names, char *default_file, int default_cache_size) +void logtail_destroy (cu_logtail_t *obj) { - int counterslen = 0; - logtail_instance_t *instance; - - llentry_t *entry; - char *tail_file; - - oconfig_item_t *gchild; - int gchildren; - - oconfig_item_t *child = ci->children; - int children = ci->children_num; + int i; - while (*(names++) != NULL) - counterslen += sizeof (unsigned long); + if (obj == NULL) + return; - if (*instances == NULL) + if (obj->tail != NULL) { - *instances = llist_create(); - if (*instances == NULL) - return 1; + cu_tail_destroy (obj->tail); + obj->tail = NULL; } - - for (; children; --children, ++child) + for (i = 0; i < obj->matches_num; i++) { - tail_file = NULL; - - if (strcmp (child->key, "Instance") != 0) - { - WARNING ("%s plugin: Ignoring unknown" - " config option `%s'.", plugin, child->key); - continue; - } - - if ((child->values_num != 1) || - (child->values[0].type != OCONFIG_TYPE_STRING)) + cu_logtail_match_t *match = obj->matches + i; + if (match->match != NULL) { - WARNING ("%s plugin: `Instance' needs exactly" - " one string argument.", plugin); - continue; + match_destroy (match->match); + match->match = NULL; } - instance = malloc (sizeof (logtail_instance_t)); - if (instance == NULL) - { - ERROR ("%s plugin: `malloc' failed.", plugin); - return 1; - } - memset (instance, '\0', sizeof (logtail_instance_t)); - - instance->counters = malloc (counterslen); - if (instance->counters == NULL) - { - ERROR ("%s plugin: `malloc' failed.", plugin); - destroy_instance (instance); - return 1; - } - memset (instance->counters, '\0', counterslen); - - instance->name = strdup (child->values[0].value.string); - if (instance->name == NULL) - { - ERROR ("%s plugin: `strdup' failed.", plugin); - destroy_instance (instance); - return 1; - } - - instance->list = llist_create(); - if (instance->list == NULL) - { - ERROR ("%s plugin: `llist_create' failed.", plugin); - destroy_instance (instance); - return 1; - } - - instance->tree = c_avl_create ((void *)strcmp); - if (instance->tree == NULL) - { - ERROR ("%s plugin: `c_avl_create' failed.", plugin); - destroy_instance (instance); - return 1; - } - - entry = llentry_create (instance->name, instance); - if (entry == NULL) - { - ERROR ("%s plugin: `llentry_create' failed.", plugin); - destroy_instance (instance); - return 1; - } + if ((match->user_data != NULL) + && (match->free != NULL)) + (*match->free) (match->user_data); + match->user_data = NULL; + } - gchild = child->children; - gchildren = child->children_num; + sfree (obj->matches); + sfree (obj); +} /* void logtail_destroy */ - for (; gchildren; --gchildren, ++gchild) - { - if (strcmp (gchild->key, "LogFile") == 0) - { - if (gchild->values_num != 1 || - gchild->values[0].type != OCONFIG_TYPE_STRING) - { - WARNING ("%s plugin: config option `%s'" - " should have exactly one string value.", - plugin, gchild->key); - continue; - } - if (tail_file != NULL) - { - WARNING ("%s plugin: ignoring extraneous" - " `LogFile' config option.", plugin); - continue; - } - tail_file = gchild->values[0].value.string; - } - else if (strcmp (gchild->key, "CacheSize") == 0) - { - if (gchild->values_num != 1 - || gchild->values[0].type != OCONFIG_TYPE_NUMBER) - { - WARNING ("%s plugin: config option `%s'" - " should have exactly one numerical value.", - plugin, gchild->key); - continue; - } - if (instance->cache_size) - { - WARNING ("%s plugin: ignoring extraneous" - " `CacheSize' config option.", plugin); - continue; - } - instance->cache_size = gchild->values[0].value.number; - } - else - { - WARNING ("%s plugin: Ignoring unknown config option" - " `%s'.", plugin, gchild->key); - continue; - } - - if (gchild->children_num) - { - WARNING ("%s plugin: config option `%s' should not" - " have children.", plugin, gchild->key); - } - } +int logtail_add_match (cu_logtail_t *obj, cu_match_t *match, + int (*submit_match) (cu_match_t *match, void *user_data), + void *user_data, + void (*free_user_data) (void *user_data)) +{ + cu_logtail_match_t *temp; - if (tail_file == NULL) - tail_file = default_file; - instance->tail = cu_tail_create (tail_file); - if (instance->tail == NULL) - { - ERROR ("%s plugin: `cu_tail_create' failed.", plugin); - destroy_instance (instance); + temp = (cu_logtail_match_t *) realloc (obj->matches, + sizeof (cu_logtail_match_t) * (obj->matches_num + 1)); + if (temp == NULL) + return (-1); - llentry_destroy (entry); - return 1; - } + obj->matches = temp; + obj->matches_num++; - if (instance->cache_size == 0) - instance->cache_size = default_cache_size; + temp = obj->matches + (obj->matches_num - 1); - llist_append (*instances, entry); - } + temp->match = match; + temp->user_data = user_data; + temp->submit = submit_match; + temp->free = free_user_data; - return 0; -} /* int logtail_config */ - -unsigned long *logtail_counters (logtail_instance_t *instance) -{ - return instance->counters; -} /* unsigned log *logtail_counters */ + return (0); +} /* int logtail_add_match */ -int logtail_cache (logtail_instance_t *instance, char *plugin, char *key, void **data, int len) +int logtail_add_match_simple (cu_logtail_t *obj, + const char *regex, int ds_type, + const char *plugin, const char *plugin_instance, + const char *type, const char *type_instance) { - llentry_t *entry = NULL; - - if (c_avl_get (instance->tree, key, (void*)&entry) == 0) - { - *data = entry->value; - return (0); - } + cu_match_t *match; + cu_logtail_simple_t *user_data; + int status; - if ((key = strdup (key)) == NULL) - { - ERROR ("%s plugin: `strdup' failed.", plugin); - return (0); - } + match = match_create_simple (regex, ds_type); + if (match == NULL) + return (-1); - if (data != NULL && (*data = malloc (len)) == NULL) + user_data = (cu_logtail_simple_t *) malloc (sizeof (cu_logtail_simple_t)); + if (user_data == NULL) { - ERROR ("%s plugin: `malloc' failed.", plugin); - free (key); - return (0); + match_destroy (match); + return (-1); } - if (data != NULL) - memset (*data, '\0', len); + sstrncpy (user_data->plugin, plugin, sizeof (user_data->plugin)); + sstrncpy (user_data->plugin_instance, plugin_instance, + sizeof (user_data->plugin_instance)); + sstrncpy (user_data->type, type, sizeof (user_data->type)); + sstrncpy (user_data->type_instance, type_instance, + sizeof (user_data->type_instance)); - entry = llentry_create (key, data == NULL ? NULL : *data); - if (entry == NULL) - { - ERROR ("%s plugin: `llentry_create' failed.", plugin); - free (key); - if (data !=NULL) - free (*data); - return (0); - } + status = logtail_add_match (obj, match, simple_submit_match, + user_data, free); - if (c_avl_insert (instance->tree, key, entry) != 0) + if (status != 0) { - ERROR ("%s plugin: `c_avl_insert' failed.", plugin); - llentry_destroy (entry); - free (key); - if (data != NULL) - free (*data); - return (0); + match_destroy (match); + sfree (user_data); } - llist_prepend (instance->list, entry); + return (status); +} /* int logtail_add_match_simple */ - while (llist_size (instance->list) > instance->cache_size && - (entry = llist_tail (instance->list)) != NULL ) - { - c_avl_remove (instance->tree, entry->key, NULL, NULL); - llist_remove (instance->list, entry); - free (entry->key); - if (entry->value != NULL) - free (entry->value); - llentry_destroy (entry); - } +int logtail_read (cu_logtail_t *obj) +{ + char buffer[4096]; + int status; + int i; - return (1); -} + status = cu_tail_read (obj->tail, buffer, sizeof (buffer), tail_callback, + (void *) obj); + if (status != 0) + return (status); -void logtail_decache (logtail_instance_t *instance, char *key) -{ - llentry_t *entry = NULL; - if (c_avl_remove (instance->tree, key, NULL, (void*)&entry)) - return; + for (i = 0; i < obj->matches_num; i++) + { + cu_logtail_match_t *lt_match = obj->matches + i; - llist_remove (instance->list, entry); - free (entry->key); - if (entry->value != NULL) - free (entry->value); + (*lt_match->submit) (lt_match->match, lt_match->user_data); + } - llentry_destroy (entry); -} + return (0); +} /* int logtail_read */ /* vim: set sw=2 sts=2 ts=8 : */ diff --git a/src/utils_logtail.h b/src/utils_logtail.h index 2324d7e8..8b193408 100644 --- a/src/utils_logtail.h +++ b/src/utils_logtail.h @@ -1,6 +1,7 @@ /* * collectd - src/utils_logtail.h * Copyright (C) 2007-2008 C-Ware, Inc. + * Copyright (C) 2008 Florian Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -15,154 +16,108 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * Author: + * Authors: * Luke Heberling + * Florian Forster * * Description: * Encapsulates useful code to plugins which must parse a log file. * */ -#include "utils_llist.h" -#include "utils_tail.h" +#include "utils_match.h" -struct logtail_instance_s; -typedef struct logtail_instance_s logtail_instance_t; +struct cu_logtail_s; +typedef struct cu_logtail_s cu_logtail_t; + +struct cu_logtail_simple_s +{ + char plugin[DATA_MAX_NAME_LEN]; + char plugin_instance[DATA_MAX_NAME_LEN]; + char type[DATA_MAX_NAME_LEN]; + char type_instance[DATA_MAX_NAME_LEN]; +}; +typedef struct cu_logtail_simple_s cu_logtail_simple_t; /* * NAME - * logtail_term + * logtail_create * * DESCRIPTION - * Call to release resources associated with the plugin. + * Allocates, initializes and returns a new `cu_logtail_t' object. * * PARAMETERS - * `instances' The handle used to identify the plugin. + * `filename' The name to read data from. + * `plugin' The plugin name to use when dispatching values. * * RETURN VALUE - * Zero on success, nonzero on failure. + * Returns NULL upon failure, non-NULL otherwise. */ -int logtail_term (llist_t **instances); +cu_logtail_t *logtail_create (const char *filename); /* * NAME - * logtail_init + * logtail_destroy * * DESCRIPTION - * Call to initialize the plugin + * Releases resources used by the `cu_logtail_t' object. * * PARAMETERS - * `instances' The handle used to identify the plugin. - * - * RETURN VALUE - * Zero on success, nonzero on failure. + * The object to destroy. */ -int logtail_init (llist_t **instances); +void logtail_destroy (cu_logtail_t *obj); /* * NAME - * logtail_read + * logtail_add_match_simple * * DESCRIPTION - * Looks for more data in the log file, sends each line - * through the given function, and submits the counters to - * collectd. + * Adds a match, in form of a regular expression, to the `cu_logtail_t' + * object. The values matched by that regular expression are dispatched to + * the daemon using the supplied `type' and `type_instance' fields. * * PARAMETERS - * `instances' The handle used to identify the plugin. - * - * `func' The function used to parse each line from the log. - * - * `plugin' The name of the plugin. - * - * `names' An array of counter names in the same order as the - * counters themselves. + * `obj' + * `type' + * `type_instance' + * `match_ds_type' + * `regex' * * RETURN VALUE - * Zero on success, nonzero on failure. + * Zero upon success, non-zero otherwise. */ -int logtail_read (llist_t **instances, tailfunc *func, char *plugin, - char **names); +int logtail_add_match (cu_logtail_t *obj, cu_match_t *match, + int (*submit_match) (cu_match_t *match, void *user_data), + void *user_data, + void (*free_user_data) (void *user_data)); + +int logtail_add_match_simple (cu_logtail_t *obj, + const char *regex, int ds_type, + const char *plugin, const char *plugin_instance, + const char *type, const char *type_instance); /* * NAME - * logtail_config + * logtail_read * * DESCRIPTION - * Configures the logtail instance for the given plugin. + * Looks for more data in the log file, sends each line + * through the given function, and submits the counters to + * collectd. * * PARAMETERS * `instances' The handle used to identify the plugin. * - * `ci' The configuration item from collectd. + * `func' The function used to parse each line from the log. * * `plugin' The name of the plugin. * * `names' An array of counter names in the same order as the * counters themselves. * - * `default_file' The default log file if none is found in the - * configuration. - * - * `default_cache_size' The default cache size if none is found in the - * configuration. - * * RETURN VALUE * Zero on success, nonzero on failure. - */ -int logtail_config (llist_t **instances, oconfig_item_t *ci, char *plugin, - char **names, char *default_file, - int default_cache_size); - -/* - * NAME - * logtail_counters - * - * DESCRIPTION - * Returns the counters maintained for the plugin. - * - * PARAMETERS - * `instance' The handle used to identify the logtail instance. - * - */ -unsigned long *logtail_counters (logtail_instance_t *instance); - -/* - * NAME - * logtail_cache - * - * DESCRIPTION - * Stores the data in the cache. - * - * PARAMETERS - * `instance' The handle used to identify the logtail instance. - * - * `plugin' The name of the plugin. - * - * `key' The key to identify the cached data. - * - * `data' The data to cache. - * - * `len' The length of the data to cache. - * - * RETURN VALUE - * Zero on success, nonzero on failure. - */ -int logtail_cache (logtail_instance_t *instance, char *plugin, char *key, - void **data, int len); - -/* - * NAME - * logtail_decache - * - * DESCRIPTION - * Removes the data from the cache. - * - * PARAMETERS - * `instance' The handle used to identify the logtail instance. - * - * `key' The key to identify the cached data. - * - */ -void logtail_decache (logtail_instance_t *instance, char *key); +*/ +int logtail_read (cu_logtail_t *obj); +/* vim: set sw=2 sts=2 ts=8 : */ diff --git a/src/utils_match.c b/src/utils_match.c index 23bedb1b..b4d50a58 100644 --- a/src/utils_match.c +++ b/src/utils_match.c @@ -113,7 +113,7 @@ cu_match_t *match_create_callback (const char *regex, return (obj); } /* cu_match_t *match_create_callback */ -cu_match_t *match_create_default (const char *regex, int match_ds_type) +cu_match_t *match_create_simple (const char *regex, int match_ds_type) { cu_match_value_t *user_data; cu_match_t *obj; @@ -133,7 +133,7 @@ cu_match_t *match_create_default (const char *regex, int match_ds_type) obj->flags |= UTILS_MATCH_FLAGS_FREE_USER_DATA; return (obj); -} /* cu_match_t *match_create_default */ +} /* cu_match_t *match_create_simple */ void match_destroy (cu_match_t *obj) { diff --git a/src/utils_match.h b/src/utils_match.h index 5098e970..5108e966 100644 --- a/src/utils_match.h +++ b/src/utils_match.h @@ -71,7 +71,7 @@ cu_match_t *match_create_callback (const char *regex, /* * NAME - * match_create_callback + * match_create_simple * * DESCRIPTION * Creates a new `cu_match_t' with a default callback. The user data for that @@ -93,7 +93,7 @@ cu_match_t *match_create_callback (const char *regex, * The function will not search for anything in the string and increase * value.counter by one. */ -cu_match_t *match_create_default (const char *regex, int ds_type); +cu_match_t *match_create_simple (const char *regex, int ds_type); /* * NAME diff --git a/src/utils_tail.c b/src/utils_tail.c index 2ac478f0..b73c1f99 100644 --- a/src/utils_tail.c +++ b/src/utils_tail.c @@ -137,7 +137,7 @@ int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen) return (status); } /* int cu_tail_readline */ -int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc *callback, +int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback, void *data) { int status; diff --git a/src/utils_tail.h b/src/utils_tail.h index 9535dae4..c4793197 100644 --- a/src/utils_tail.h +++ b/src/utils_tail.h @@ -30,7 +30,7 @@ struct cu_tail_s; typedef struct cu_tail_s cu_tail_t; -typedef int tailfunc(void *data, char *buf, int buflen); +typedef int tailfunc_t(void *data, char *buf, int buflen); /* * NAME @@ -77,7 +77,7 @@ int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen); * * Returns 0 when successful and non-zero otherwise. */ -int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc *callback, +int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback, void *data); #endif /* UTILS_TAIL_H */ -- 2.30.2