2 * collectd - src/utils_logtail.c
3 * Copyright (C) 2007-2008 C-Ware, Inc.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Luke Heberling <lukeh at c-ware.com>
22 * Encapsulates useful code to plugins which must parse a log file.
27 #include "utils_tail.h"
28 #include "utils_llist.h"
29 #include "utils_avltree.h"
31 #define DESTROY_INSTANCE(inst) \
35 if (inst->name != NULL) \
37 if (inst->tail != NULL) \
38 cu_tail_destroy (inst->tail); \
39 if (inst->tree != NULL) \
40 c_avl_destroy (inst->tree); \
41 assert (inst->list == NULL || \
42 llist_size (inst->list) == 0); \
43 if (inst->list != NULL) \
44 llist_destroy (inst->list); \
45 if (inst->counters != NULL) \
46 free (inst->counters); \
51 struct logtail_instance_s
58 unsigned long *counters;
60 typedef struct logtail_instance_s logtail_instance_t;
62 static void submit (const char *plugin, const char *instance,
63 const char *name, unsigned long value)
65 value_list_t vl = VALUE_LIST_INIT;
69 ds = plugin_get_ds (name);
73 if (ds->ds->type == DS_TYPE_GAUGE)
74 values[0].gauge = (float)value;
76 values[0].counter = value;
80 vl.time = time (NULL);
81 strncpy (vl.host, hostname_g, sizeof (vl.host));
82 strncpy (vl.plugin, plugin, sizeof (vl.plugin));
83 strncpy (vl.type_instance, "", sizeof (vl.type_instance));
84 strncpy (vl.plugin_instance, instance, sizeof (vl.plugin_instance));
86 plugin_dispatch_values (name, &vl);
87 } /* static void submit */
89 int logtail_term (llist_t **instances)
97 logtail_instance_t *instance;
99 if (*instances != NULL)
101 entry = llist_head (*instances);
107 instance = prev->value;
108 if (instance->list != NULL)
110 lentry = llist_head (instance->list);
114 lentry = lentry->next;
115 if (lprev->key != NULL)
117 if (lprev->value != NULL)
119 llist_remove (instance->list, lprev);
120 llentry_destroy (lprev);
124 llist_remove (*instances, prev);
125 llentry_destroy (prev);
126 DESTROY_INSTANCE (instance);
129 llist_destroy (*instances);
134 } /* int logtail_term */
136 int logtail_init (llist_t **instances)
138 if (*instances == NULL)
139 *instances = llist_create();
141 return (*instances == NULL);
142 } /* int logtail_init */
144 int logtail_read (llist_t **instances, tailfunc *func, char *plugin, char **names)
147 logtail_instance_t *instance;
150 unsigned long *counter;
152 for (entry = llist_head (*instances); entry != NULL; entry = entry->next )
154 instance = (logtail_instance_t *)entry->value;
155 cu_tail_read (instance->tail, buffer,
156 sizeof (buffer), func, instance);
158 for (name = names, counter = instance->counters;
159 *name != NULL; ++name, ++counter)
160 submit (plugin, instance->name, *name, *counter);
164 } /* int logtail_read */
166 int logtail_config (llist_t **instances, oconfig_item_t *ci, char *plugin,
167 char **names, char *default_file, int default_cache_size)
170 logtail_instance_t *instance;
175 oconfig_item_t *gchild;
178 oconfig_item_t *child = ci->children;
179 int children = ci->children_num;
181 while (*(names++) != NULL)
182 counterslen += sizeof (unsigned long);
184 if (*instances == NULL)
186 *instances = llist_create();
187 if (*instances == NULL)
192 for (; children; --children, ++child)
196 if (strcmp (child->key, "Instance") != 0)
198 WARNING ("%s plugin: Ignoring unknown"
199 " config option `%s'.", plugin, child->key);
203 if ((child->values_num != 1) ||
204 (child->values[0].type != OCONFIG_TYPE_STRING))
206 WARNING ("%s plugin: `Instance' needs exactly"
207 " one string argument.", plugin);
211 instance = malloc (sizeof (logtail_instance_t));
212 if (instance == NULL)
214 ERROR ("%s plugin: `malloc' failed.", plugin);
217 memset (instance, '\0', sizeof (logtail_instance_t));
219 instance->counters = malloc (counterslen);
220 if (instance->counters == NULL)
222 ERROR ("%s plugin: `malloc' failed.", plugin);
223 DESTROY_INSTANCE (instance);
226 memset (instance->counters, '\0', counterslen);
228 instance->name = strdup (child->values[0].value.string);
229 if (instance->name == NULL)
231 ERROR ("%s plugin: `strdup' failed.", plugin);
232 DESTROY_INSTANCE (instance);
236 instance->list = llist_create();
237 if (instance->list == NULL)
239 ERROR ("%s plugin: `llist_create' failed.", plugin);
240 DESTROY_INSTANCE (instance);
244 instance->tree = c_avl_create ((void *)strcmp);
245 if (instance->tree == NULL)
247 ERROR ("%s plugin: `c_avl_create' failed.", plugin);
248 DESTROY_INSTANCE (instance);
252 entry = llentry_create (instance->name, instance);
255 ERROR ("%s plugin: `llentry_create' failed.", plugin);
256 DESTROY_INSTANCE (instance);
260 gchild = child->children;
261 gchildren = child->children_num;
263 for (; gchildren; --gchildren, ++gchild)
265 if (strcmp (gchild->key, "LogFile") == 0)
267 if (gchild->values_num != 1 ||
268 gchild->values[0].type != OCONFIG_TYPE_STRING)
270 WARNING ("%s plugin: config option `%s'"
271 " should have exactly one string value.",
272 plugin, gchild->key);
275 if (tail_file != NULL)
277 WARNING ("%s plugin: ignoring extraneous"
278 " `LogFile' config option.", plugin);
281 tail_file = gchild->values[0].value.string;
283 else if (strcmp (gchild->key, "CacheSize") == 0)
285 if (gchild->values_num != 1
286 || gchild->values[0].type != OCONFIG_TYPE_NUMBER)
288 WARNING ("%s plugin: config option `%s'"
289 " should have exactly one numerical value.",
290 plugin, gchild->key);
293 if (instance->cache_size)
295 WARNING ("%s plugin: ignoring extraneous"
296 " `CacheSize' config option.", plugin);
299 instance->cache_size = gchild->values[0].value.number;
303 WARNING ("%s plugin: Ignoring unknown config option"
304 " `%s'.", plugin, gchild->key);
308 if (gchild->children_num)
310 WARNING ("%s plugin: config option `%s' should not"
311 " have children.", plugin, gchild->key);
315 if (tail_file == NULL)
316 tail_file = default_file;
317 instance->tail = cu_tail_create (tail_file);
318 if (instance->tail == NULL)
320 ERROR ("%s plugin: `cu_tail_create' failed.", plugin);
321 DESTROY_INSTANCE (instance);
323 llentry_destroy (entry);
327 if (instance->cache_size == 0)
328 instance->cache_size = default_cache_size;
330 llist_append (*instances, entry);
334 } /* int logtail_config */
336 unsigned long *logtail_counters (logtail_instance_t *instance)
338 return instance->counters;
339 } /* unsigned log *logtail_counters */
341 int logtail_cache (logtail_instance_t *instance, char *plugin, char *key, void **data, int len)
343 llentry_t *entry = NULL;
345 if (c_avl_get (instance->tree, key, (void*)&entry) == 0)
347 *data = entry->value;
351 if ((key = strdup (key)) == NULL)
353 ERROR ("%s plugin: `strdup' failed.", plugin);
357 if (data != NULL && (*data = malloc (len)) == NULL)
359 ERROR ("%s plugin: `malloc' failed.", plugin);
365 memset (*data, '\0', len);
367 entry = llentry_create (key, data == NULL ? NULL : *data);
370 ERROR ("%s plugin: `llentry_create' failed.", plugin);
377 if (c_avl_insert (instance->tree, key, entry) != 0)
379 ERROR ("%s plugin: `c_avl_insert' failed.", plugin);
380 llentry_destroy (entry);
387 llist_prepend (instance->list, entry);
389 while (llist_size (instance->list) > instance->cache_size &&
390 (entry = llist_tail (instance->list)) != NULL )
392 c_avl_remove (instance->tree, entry->key, NULL, NULL);
393 llist_remove (instance->list, entry);
395 if (entry->value != NULL)
397 llentry_destroy (entry);
403 void logtail_decache (logtail_instance_t *instance, char *key)
405 llentry_t *entry = NULL;
406 if (c_avl_remove (instance->tree, key, NULL, (void*)&entry))
409 llist_remove (instance->list, entry);
411 if (entry->value != NULL)
414 llentry_destroy (entry);
417 /* vim: set sw=2 sts=2 ts=8 : */