Fix make distcheck
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Tue, 29 Nov 2016 14:43:22 +0000 (15:43 +0100)
committerRuben Kerkhof <ruben@rubenkerkhof.com>
Tue, 29 Nov 2016 14:43:22 +0000 (15:43 +0100)
This was broken by 1d888f3

14 files changed:
src/Makefile.am
src/daemon/Makefile.am
src/daemon/utils_match.c [deleted file]
src/daemon/utils_match.h [deleted file]
src/daemon/utils_tail.c [deleted file]
src/daemon/utils_tail.h [deleted file]
src/daemon/utils_tail_match.c [deleted file]
src/daemon/utils_tail_match.h [deleted file]
src/utils_match.c [new file with mode: 0644]
src/utils_match.h [new file with mode: 0644]
src/utils_tail.c [new file with mode: 0644]
src/utils_tail.h [new file with mode: 0644]
src/utils_tail_match.c [new file with mode: 0644]
src/utils_tail_match.h [new file with mode: 0644]

index a01176d..3776389 100644 (file)
@@ -334,7 +334,8 @@ endif
 if BUILD_PLUGIN_CURL
 pkglib_LTLIBRARIES += curl.la
 curl_la_SOURCES = curl.c \
-                 utils_curl_stats.c utils_curl_stats.h
+                 utils_curl_stats.c utils_curl_stats.h \
+                 utils_match.c utils_match.h
 curl_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 curl_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
 curl_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
@@ -686,7 +687,7 @@ endif
 
 if BUILD_PLUGIN_MEMCACHEC
 pkglib_LTLIBRARIES += memcachec.la
-memcachec_la_SOURCES = memcachec.c
+memcachec_la_SOURCES = memcachec.c utils_match.c utils_match.h
 memcachec_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMEMCACHED_LDFLAGS)
 memcachec_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMEMCACHED_CPPFLAGS)
 memcachec_la_LIBADD = $(BUILD_WITH_LIBMEMCACHED_LIBS)
@@ -1114,14 +1115,14 @@ endif
 
 if BUILD_PLUGIN_TAIL
 pkglib_LTLIBRARIES += tail.la
-tail_la_SOURCES = tail.c
+tail_la_SOURCES = tail.c utils_tail_match.c utils_tail_match.h
 tail_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 tail_la_LIBADD = liblatency.la
 endif
 
 if BUILD_PLUGIN_TAIL_CSV
 pkglib_LTLIBRARIES += tail_csv.la
-tail_csv_la_SOURCES = tail_csv.c
+tail_csv_la_SOURCES = tail_csv.c utils_tail.c utils_tail.h
 tail_csv_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
index ac8c764..5207943 100644 (file)
@@ -61,15 +61,10 @@ collectd_SOURCES = collectd.c collectd.h \
                   utils_ignorelist.c utils_ignorelist.h \
                   utils_llist.c utils_llist.h \
                   utils_random.c utils_random.h \
-                  utils_tail_match.c utils_tail_match.h \
-                  utils_match.c utils_match.h \
                   utils_subst.c utils_subst.h \
-                  utils_tail.c utils_tail.h \
                   utils_time.c utils_time.h \
                   types_list.c types_list.h \
-                  utils_threshold.c utils_threshold.h \
-                  ../utils_latency_config.h ../utils_latency_config.c \
-                  ../utils_latency.h ../utils_latency.c
+                  utils_threshold.c utils_threshold.h
 
 
 collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
diff --git a/src/daemon/utils_match.c b/src/daemon/utils_match.c
deleted file mode 100644 (file)
index 2e487b5..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-/**
- * collectd - src/utils_match.c
- * Copyright (C) 2008-2014  Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *   Florian octo Forster <octo at collectd.org>
- **/
-
-#include "collectd.h"
-
-#include "common.h"
-#include "plugin.h"
-
-#include "utils_match.h"
-
-#include <regex.h>
-
-#define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
-
-struct cu_match_s {
-  regex_t regex;
-  regex_t excluderegex;
-  int flags;
-
-  int (*callback)(const char *str, char *const *matches, size_t matches_num,
-                  void *user_data);
-  void *user_data;
-  void (*free)(void *user_data);
-};
-
-/*
- * Private functions
- */
-static char *match_substr(const char *str, int begin, int end) {
-  char *ret;
-  size_t ret_len;
-
-  if ((begin < 0) || (end < 0) || (begin >= end))
-    return (NULL);
-  if ((size_t)end > (strlen(str) + 1)) {
-    ERROR("utils_match: match_substr: `end' points after end of string.");
-    return (NULL);
-  }
-
-  ret_len = end - begin;
-  ret = malloc(ret_len + 1);
-  if (ret == NULL) {
-    ERROR("utils_match: match_substr: malloc failed.");
-    return (NULL);
-  }
-
-  sstrncpy(ret, str + begin, ret_len + 1);
-  return (ret);
-} /* char *match_substr */
-
-static int default_callback(const char __attribute__((unused)) * str,
-                            char *const *matches, size_t matches_num,
-                            void *user_data) {
-  cu_match_value_t *data = (cu_match_value_t *)user_data;
-
-  if (data->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) {
-    gauge_t value;
-    char *endptr = NULL;
-
-    if (data->ds_type & UTILS_MATCH_CF_GAUGE_INC) {
-      data->value.gauge = isnan(data->value.gauge) ? 1 : data->value.gauge + 1;
-      data->values_num++;
-      return (0);
-    }
-
-    if (matches_num < 2)
-      return (-1);
-
-    value = (gauge_t)strtod(matches[1], &endptr);
-    if (matches[1] == endptr)
-      return (-1);
-
-    if (data->ds_type & UTILS_MATCH_CF_GAUGE_DIST) {
-      latency_counter_add(data->latency, DOUBLE_TO_CDTIME_T(value));
-      data->values_num++;
-      return (0);
-    }
-
-    if ((data->values_num == 0) ||
-        (data->ds_type & UTILS_MATCH_CF_GAUGE_LAST) ||
-        (data->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) {
-      data->value.gauge = value;
-    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_AVERAGE) {
-      double f = ((double)data->values_num) / ((double)(data->values_num + 1));
-      data->value.gauge = (data->value.gauge * f) + (value * (1.0 - f));
-    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MIN) {
-      if (data->value.gauge > value)
-        data->value.gauge = value;
-    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MAX) {
-      if (data->value.gauge < value)
-        data->value.gauge = value;
-    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_ADD) {
-      data->value.gauge += value;
-    } else {
-      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
-      return (-1);
-    }
-
-    data->values_num++;
-  } else if (data->ds_type & UTILS_MATCH_DS_TYPE_COUNTER) {
-    counter_t value;
-    char *endptr = NULL;
-
-    if (data->ds_type & UTILS_MATCH_CF_COUNTER_INC) {
-      data->value.counter++;
-      data->values_num++;
-      return (0);
-    }
-
-    if (matches_num < 2)
-      return (-1);
-
-    value = (counter_t)strtoull(matches[1], &endptr, 0);
-    if (matches[1] == endptr)
-      return (-1);
-
-    if (data->ds_type & UTILS_MATCH_CF_COUNTER_SET)
-      data->value.counter = value;
-    else if (data->ds_type & UTILS_MATCH_CF_COUNTER_ADD)
-      data->value.counter += value;
-    else {
-      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
-      return (-1);
-    }
-
-    data->values_num++;
-  } else if (data->ds_type & UTILS_MATCH_DS_TYPE_DERIVE) {
-    derive_t value;
-    char *endptr = NULL;
-
-    if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC) {
-      data->value.derive++;
-      data->values_num++;
-      return (0);
-    }
-
-    if (matches_num < 2)
-      return (-1);
-
-    value = (derive_t)strtoll(matches[1], &endptr, 0);
-    if (matches[1] == endptr)
-      return (-1);
-
-    if (data->ds_type & UTILS_MATCH_CF_DERIVE_SET)
-      data->value.derive = value;
-    else if (data->ds_type & UTILS_MATCH_CF_DERIVE_ADD)
-      data->value.derive += value;
-    else {
-      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
-      return (-1);
-    }
-
-    data->values_num++;
-  } else if (data->ds_type & UTILS_MATCH_DS_TYPE_ABSOLUTE) {
-    absolute_t value;
-    char *endptr = NULL;
-
-    if (matches_num < 2)
-      return (-1);
-
-    value = (absolute_t)strtoull(matches[1], &endptr, 0);
-    if (matches[1] == endptr)
-      return (-1);
-
-    if (data->ds_type & UTILS_MATCH_CF_ABSOLUTE_SET)
-      data->value.absolute = value;
-    else {
-      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
-      return (-1);
-    }
-
-    data->values_num++;
-  } else {
-    ERROR("utils_match: default_callback: obj->ds_type is invalid!");
-    return (-1);
-  }
-
-  return (0);
-} /* int default_callback */
-
-static void match_simple_free(void *data) {
-  cu_match_value_t *user_data = (cu_match_value_t *)data;
-  if (user_data->latency)
-    latency_counter_destroy(user_data->latency);
-
-  free(data);
-} /* void match_simple_free */
-
-/*
- * Public functions
- */
-cu_match_t *
-match_create_callback(const char *regex, const char *excluderegex,
-                      int (*callback)(const char *str, char *const *matches,
-                                      size_t matches_num, void *user_data),
-                      void *user_data,
-                      void (*free_user_data)(void *user_data)) {
-  cu_match_t *obj;
-  int status;
-
-  DEBUG("utils_match: match_create_callback: regex = %s, excluderegex = %s",
-        regex, excluderegex);
-
-  obj = calloc(1, sizeof(*obj));
-  if (obj == NULL)
-    return (NULL);
-
-  status = regcomp(&obj->regex, regex, REG_EXTENDED | REG_NEWLINE);
-  if (status != 0) {
-    ERROR("Compiling the regular expression \"%s\" failed.", regex);
-    sfree(obj);
-    return (NULL);
-  }
-
-  if (excluderegex && strcmp(excluderegex, "") != 0) {
-    status = regcomp(&obj->excluderegex, excluderegex, REG_EXTENDED);
-    if (status != 0) {
-      ERROR("Compiling the excluding regular expression \"%s\" failed.",
-            excluderegex);
-      sfree(obj);
-      return (NULL);
-    }
-    obj->flags |= UTILS_MATCH_FLAGS_EXCLUDE_REGEX;
-  }
-
-  obj->callback = callback;
-  obj->user_data = user_data;
-  obj->free = free_user_data;
-
-  return (obj);
-} /* cu_match_t *match_create_callback */
-
-cu_match_t *match_create_simple(const char *regex, const char *excluderegex,
-                                int match_ds_type) {
-  cu_match_value_t *user_data;
-  cu_match_t *obj;
-
-  user_data = calloc(1, sizeof(*user_data));
-  if (user_data == NULL)
-    return (NULL);
-  user_data->ds_type = match_ds_type;
-
-  if ((match_ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
-      (match_ds_type & UTILS_MATCH_CF_GAUGE_DIST)) {
-    user_data->latency = latency_counter_create();
-    if (user_data->latency == NULL) {
-      ERROR("match_create_simple(): latency_counter_create() failed.");
-      free(user_data);
-      return (NULL);
-    }
-  }
-
-  obj = match_create_callback(regex, excluderegex, default_callback, user_data,
-                              match_simple_free);
-  if (obj == NULL) {
-    if (user_data->latency)
-      latency_counter_destroy(user_data->latency);
-
-    sfree(user_data);
-    return (NULL);
-  }
-  return (obj);
-} /* cu_match_t *match_create_simple */
-
-void match_value_reset(cu_match_value_t *mv) {
-  if (mv == NULL)
-    return;
-
-  /* Reset GAUGE metrics only and except GAUGE_PERSIST. */
-  if ((mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
-      !(mv->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) {
-    mv->value.gauge = NAN;
-    mv->values_num = 0;
-  }
-} /* }}} void match_value_reset */
-
-void match_destroy(cu_match_t *obj) {
-  if (obj == NULL)
-    return;
-
-  if ((obj->user_data != NULL) && (obj->free != NULL))
-    (*obj->free)(obj->user_data);
-
-  sfree(obj);
-} /* void match_destroy */
-
-int match_apply(cu_match_t *obj, const char *str) {
-  int status;
-  regmatch_t re_match[32];
-  char *matches[32] = {0};
-  size_t matches_num;
-
-  if ((obj == NULL) || (str == NULL))
-    return (-1);
-
-  if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) {
-    status =
-        regexec(&obj->excluderegex, str, STATIC_ARRAY_SIZE(re_match), re_match,
-                /* eflags = */ 0);
-    /* Regex did match, so exclude this line */
-    if (status == 0) {
-      DEBUG("ExludeRegex matched, don't count that line\n");
-      return (0);
-    }
-  }
-
-  status = regexec(&obj->regex, str, STATIC_ARRAY_SIZE(re_match), re_match,
-                   /* eflags = */ 0);
-
-  /* Regex did not match */
-  if (status != 0)
-    return (0);
-
-  for (matches_num = 0; matches_num < STATIC_ARRAY_SIZE(matches);
-       matches_num++) {
-    if ((re_match[matches_num].rm_so < 0) || (re_match[matches_num].rm_eo < 0))
-      break;
-
-    matches[matches_num] = match_substr(str, re_match[matches_num].rm_so,
-                                        re_match[matches_num].rm_eo);
-    if (matches[matches_num] == NULL) {
-      status = -1;
-      break;
-    }
-  }
-
-  if (status != 0) {
-    ERROR("utils_match: match_apply: match_substr failed.");
-  } else {
-    status = obj->callback(str, matches, matches_num, obj->user_data);
-    if (status != 0) {
-      ERROR("utils_match: match_apply: callback failed.");
-    }
-  }
-
-  for (size_t i = 0; i < matches_num; i++) {
-    sfree(matches[i]);
-  }
-
-  return (status);
-} /* int match_apply */
-
-void *match_get_user_data(cu_match_t *obj) {
-  if (obj == NULL)
-    return (NULL);
-  return (obj->user_data);
-} /* void *match_get_user_data */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_match.h b/src/daemon/utils_match.h
deleted file mode 100644 (file)
index 1383530..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/**
- * collectd - src/utils_match.h
- * Copyright (C) 2008-2014  Florian octo Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *   Florian octo Forster <octo at collectd.org>
- **/
-
-#ifndef UTILS_MATCH_H
-#define UTILS_MATCH_H 1
-
-#include "plugin.h"
-#include "utils_latency.h"
-
-/*
- * Each type may have 12 sub-types
- * 0x1000 = 1000000000000
- *          ^             <- Type bit
- *           ^^^^^^^^^^^^ <- Subtype bits
- */
-#define UTILS_MATCH_DS_TYPE_GAUGE 0x1000
-#define UTILS_MATCH_DS_TYPE_COUNTER 0x2000
-#define UTILS_MATCH_DS_TYPE_DERIVE 0x4000
-#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x8000
-
-#define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
-#define UTILS_MATCH_CF_GAUGE_MIN 0x02
-#define UTILS_MATCH_CF_GAUGE_MAX 0x04
-#define UTILS_MATCH_CF_GAUGE_LAST 0x08
-#define UTILS_MATCH_CF_GAUGE_INC 0x10
-#define UTILS_MATCH_CF_GAUGE_ADD 0x20
-#define UTILS_MATCH_CF_GAUGE_PERSIST 0x40
-#define UTILS_MATCH_CF_GAUGE_DIST 0x80
-
-#define UTILS_MATCH_CF_COUNTER_SET 0x01
-#define UTILS_MATCH_CF_COUNTER_ADD 0x02
-#define UTILS_MATCH_CF_COUNTER_INC 0x04
-
-#define UTILS_MATCH_CF_DERIVE_SET 0x01
-#define UTILS_MATCH_CF_DERIVE_ADD 0x02
-#define UTILS_MATCH_CF_DERIVE_INC 0x04
-
-#define UTILS_MATCH_CF_ABSOLUTE_SET 0x01
-#define UTILS_MATCH_CF_ABSOLUTE_ADD 0x02
-#define UTILS_MATCH_CF_ABSOLUTE_INC 0x04
-
-/*
- * Data types
- */
-struct cu_match_s;
-typedef struct cu_match_s cu_match_t;
-
-struct cu_match_value_s {
-  int ds_type;
-  value_t value;
-  unsigned int values_num;
-  latency_counter_t *latency;
-};
-typedef struct cu_match_value_s cu_match_value_t;
-
-/*
- * Prototypes
- */
-/*
- * NAME
- *  match_create_callback
- *
- * DESCRIPTION
- *  Creates a new `cu_match_t' object which will use the regular expression
- *  `regex' to match lines, see the `match_apply' method below. If the line
- *  matches, the callback passed in `callback' will be called along with the
- *  pointer `user_pointer'.
- *  The string that's passed to the callback depends on the regular expression:
- *  If the regular expression includes a sub-match, i. e. something like
- *    "value=([0-9][0-9]*)"
- *  then only the submatch (the part in the parenthesis) will be passed to the
- *  callback. If there is no submatch, then the entire string is passed to the
- *  callback.
- *  The optional `excluderegex' allows to exclude the line from the match, if
- *  the excluderegex matches.
- *  When `match_destroy' is called the `user_data' pointer is freed using
- *  the `free_user_data' callback - if it is not NULL.
- */
-cu_match_t *
-match_create_callback(const char *regex, const char *excluderegex,
-                      int (*callback)(const char *str, char *const *matches,
-                                      size_t matches_num, void *user_data),
-                      void *user_data, void (*free_user_data)(void *user_data));
-
-/*
- * NAME
- *  match_create_simple
- *
- * DESCRIPTION
- *  Creates a new `cu_match_t' with a default callback. The user data for that
- *  default callback will be a `cu_match_value_t' structure, with
- *  `ds_type' copied to the structure. The default callback will handle the
- *  string as containing a number (see strtoll(3) and strtod(3)) and store that
- *  number in the `value' member. How that is done depends on `ds_type':
- *
- *  UTILS_MATCH_DS_TYPE_GAUGE
- *    The function will search for a floating point number in the string and
- *    store it in value.gauge.
- *  UTILS_MATCH_DS_TYPE_COUNTER_SET
- *    The function will search for an integer in the string and store it in
- *    value.counter.
- *  UTILS_MATCH_DS_TYPE_COUNTER_ADD
- *    The function will search for an integer in the string and add it to the
- *    value in value.counter.
- *  UTILS_MATCH_DS_TYPE_COUNTER_INC
- *    The function will not search for anything in the string and increase
- *    value.counter by one.
- */
-cu_match_t *match_create_simple(const char *regex, const char *excluderegex,
-                                int ds_type);
-
-/*
- * NAME
- *  match_value_reset
- *
- * DESCRIPTION
- *   Resets the internal state, if applicable. This function must be called
- *   after each iteration for "simple" matches, usually after dispatching the
- *   metrics.
- */
-void match_value_reset(cu_match_value_t *mv);
-
-/*
- * NAME
- *  match_destroy
- *
- * DESCRIPTION
- *  Destroys the object and frees all internal resources.
- */
-void match_destroy(cu_match_t *obj);
-
-/*
- * NAME
- *  match_apply
- *
- * DESCRIPTION
- *  Tries to match the string `str' with the regular expression of `obj'. If
- *  the string matches, calls the callback in `obj' with the (sub-)match.
- *
- *  The user_data pointer passed to `match_create_callback' is NOT freed
- *  automatically. The `cu_match_value_t' structure allocated by
- *  `match_create_callback' is freed automatically.
- */
-int match_apply(cu_match_t *obj, const char *str);
-
-/*
- * NAME
- *  match_get_user_data
- *
- * DESCRIPTION
- *  Returns the pointer passed to `match_create_callback' or a pointer to the
- *  `cu_match_value_t' structure allocated by `match_create_simple'.
- */
-void *match_get_user_data(cu_match_t *obj);
-
-#endif /* UTILS_MATCH_H */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_tail.c b/src/daemon/utils_tail.c
deleted file mode 100644 (file)
index 565a224..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/**
- * collectd - src/utils_tail.c
- * Copyright (C) 2007-2008  C-Ware, Inc.
- * Copyright (C) 2008       Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author:
- *   Luke Heberling <lukeh at c-ware.com>
- *   Florian Forster <octo at collectd.org>
- *
- * Description:
- *   Encapsulates useful code for plugins which must watch for appends to
- *   the end of a file.
- **/
-
-#include "collectd.h"
-
-#include "common.h"
-#include "utils_tail.h"
-
-struct cu_tail_s {
-  char *file;
-  FILE *fh;
-  struct stat stat;
-};
-
-static int cu_tail_reopen(cu_tail_t *obj) {
-  int seek_end = 0;
-  FILE *fh;
-  struct stat stat_buf = {0};
-  int status;
-
-  status = stat(obj->file, &stat_buf);
-  if (status != 0) {
-    char errbuf[1024];
-    ERROR("utils_tail: stat (%s) failed: %s", obj->file,
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return (-1);
-  }
-
-  /* The file is already open.. */
-  if ((obj->fh != NULL) && (stat_buf.st_ino == obj->stat.st_ino)) {
-    /* Seek to the beginning if file was truncated */
-    if (stat_buf.st_size < obj->stat.st_size) {
-      INFO("utils_tail: File `%s' was truncated.", obj->file);
-      status = fseek(obj->fh, 0, SEEK_SET);
-      if (status != 0) {
-        char errbuf[1024];
-        ERROR("utils_tail: fseek (%s) failed: %s", obj->file,
-              sstrerror(errno, errbuf, sizeof(errbuf)));
-        fclose(obj->fh);
-        obj->fh = NULL;
-        return (-1);
-      }
-    }
-    memcpy(&obj->stat, &stat_buf, sizeof(struct stat));
-    return (1);
-  }
-
-  /* Seek to the end if we re-open the same file again or the file opened
-   * is the first at all or the first after an error */
-  if ((obj->stat.st_ino == 0) || (obj->stat.st_ino == stat_buf.st_ino))
-    seek_end = 1;
-
-  fh = fopen(obj->file, "r");
-  if (fh == NULL) {
-    char errbuf[1024];
-    ERROR("utils_tail: fopen (%s) failed: %s", obj->file,
-          sstrerror(errno, errbuf, sizeof(errbuf)));
-    return (-1);
-  }
-
-  if (seek_end != 0) {
-    status = fseek(fh, 0, SEEK_END);
-    if (status != 0) {
-      char errbuf[1024];
-      ERROR("utils_tail: fseek (%s) failed: %s", obj->file,
-            sstrerror(errno, errbuf, sizeof(errbuf)));
-      fclose(fh);
-      return (-1);
-    }
-  }
-
-  if (obj->fh != NULL)
-    fclose(obj->fh);
-  obj->fh = fh;
-  memcpy(&obj->stat, &stat_buf, sizeof(struct stat));
-
-  return (0);
-} /* int cu_tail_reopen */
-
-cu_tail_t *cu_tail_create(const char *file) {
-  cu_tail_t *obj;
-
-  obj = calloc(1, sizeof(*obj));
-  if (obj == NULL)
-    return (NULL);
-
-  obj->file = strdup(file);
-  if (obj->file == NULL) {
-    free(obj);
-    return (NULL);
-  }
-
-  obj->fh = NULL;
-
-  return (obj);
-} /* cu_tail_t *cu_tail_create */
-
-int cu_tail_destroy(cu_tail_t *obj) {
-  if (obj->fh != NULL)
-    fclose(obj->fh);
-  free(obj->file);
-  free(obj);
-
-  return (0);
-} /* int cu_tail_destroy */
-
-int cu_tail_readline(cu_tail_t *obj, char *buf, int buflen) {
-  int status;
-
-  if (buflen < 1) {
-    ERROR("utils_tail: cu_tail_readline: buflen too small: %i bytes.", buflen);
-    return (-1);
-  }
-
-  if (obj->fh == NULL) {
-    status = cu_tail_reopen(obj);
-    if (status < 0)
-      return (status);
-  }
-  assert(obj->fh != NULL);
-
-  /* Try to read from the filehandle. If that succeeds, everything appears to
-   * be fine and we can return. */
-  clearerr(obj->fh);
-  if (fgets(buf, buflen, obj->fh) != NULL) {
-    buf[buflen - 1] = 0;
-    return (0);
-  }
-
-  /* Check if we encountered an error */
-  if (ferror(obj->fh) != 0) {
-    /* Jupp, error. Force `cu_tail_reopen' to reopen the file.. */
-    fclose(obj->fh);
-    obj->fh = NULL;
-  }
-  /* else: eof -> check if the file was moved away and reopen the new file if
-   * so.. */
-
-  status = cu_tail_reopen(obj);
-  /* error -> return with error */
-  if (status < 0)
-    return (status);
-  /* file end reached and file not reopened -> nothing more to read */
-  else if (status > 0) {
-    buf[0] = 0;
-    return (0);
-  }
-
-  /* If we get here: file was re-opened and there may be more to read.. Let's
-   * try again. */
-  if (fgets(buf, buflen, obj->fh) != NULL) {
-    buf[buflen - 1] = 0;
-    return (0);
-  }
-
-  if (ferror(obj->fh) != 0) {
-    char errbuf[1024];
-    WARNING("utils_tail: fgets (%s) returned an error: %s", obj->file,
-            sstrerror(errno, errbuf, sizeof(errbuf)));
-    fclose(obj->fh);
-    obj->fh = NULL;
-    return (-1);
-  }
-
-  /* EOf, well, apparently the new file is empty.. */
-  buf[0] = 0;
-  return (0);
-} /* int cu_tail_readline */
-
-int cu_tail_read(cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
-                 void *data) {
-  int status;
-
-  while (42) {
-    size_t len;
-
-    status = cu_tail_readline(obj, buf, buflen);
-    if (status != 0) {
-      ERROR("utils_tail: cu_tail_read: cu_tail_readline "
-            "failed.");
-      break;
-    }
-
-    /* check for EOF */
-    if (buf[0] == 0)
-      break;
-
-    len = strlen(buf);
-    while (len > 0) {
-      if (buf[len - 1] != '\n')
-        break;
-      buf[len - 1] = '\0';
-      len--;
-    }
-
-    status = callback(data, buf, buflen);
-    if (status != 0) {
-      ERROR("utils_tail: cu_tail_read: callback returned "
-            "status %i.",
-            status);
-      break;
-    }
-  }
-
-  return status;
-} /* int cu_tail_read */
diff --git a/src/daemon/utils_tail.h b/src/daemon/utils_tail.h
deleted file mode 100644 (file)
index 73a6de2..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * collectd - src/utils_tail.h
- * Copyright (C) 2007-2008  C-Ware, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author:
- *   Luke Heberling <lukeh at c-ware.com>
- *
- * DESCRIPTION
- *   Facilitates reading information that is appended to a file, taking into
- *   account that the file may be rotated and a new file created under the
- *   same name.
- **/
-
-#ifndef UTILS_TAIL_H
-#define UTILS_TAIL_H 1
-
-struct cu_tail_s;
-typedef struct cu_tail_s cu_tail_t;
-
-typedef int tailfunc_t(void *data, char *buf, int buflen);
-
-/*
- * NAME
- *   cu_tail_create
- *
- * DESCRIPTION
- *   Allocates a new tail object..
- *
- * PARAMETERS
- *   `file'       The name of the file to be tailed.
- */
-cu_tail_t *cu_tail_create(const char *file);
-
-/*
- * cu_tail_destroy
- *
- * Takes a tail object returned by `cu_tail_create' and destroys it, freeing
- * all internal memory.
- *
- * Returns 0 when successful and non-zero otherwise.
- */
-int cu_tail_destroy(cu_tail_t *obj);
-
-/*
- * cu_tail_readline
- *
- * Reads from the file until `buflen' characters are read, a newline
- * character is read, or an eof condition is encountered. `buf' is
- * always null-terminated on successful return and isn't touched when non-zero
- * is returned.
- *
- * You can check if the EOF condition is reached by looking at the buffer: If
- * the length of the string stored in the buffer is zero, EOF occurred.
- * Otherwise at least the newline character will be in the buffer.
- *
- * Returns 0 when successful and non-zero otherwise.
- */
-int cu_tail_readline(cu_tail_t *obj, char *buf, int buflen);
-
-/*
- * cu_tail_readline
- *
- * Reads from the file until eof condition or an error is encountered.
- *
- * Returns 0 when successful and non-zero otherwise.
- */
-int cu_tail_read(cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
-                 void *data);
-
-#endif /* UTILS_TAIL_H */
diff --git a/src/daemon/utils_tail_match.c b/src/daemon/utils_tail_match.c
deleted file mode 100644 (file)
index 505c693..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * collectd - src/utils_tail_match.c
- * Copyright (C) 2007-2008  C-Ware, Inc.
- * Copyright (C) 2008       Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author:
- *   Luke Heberling <lukeh at c-ware.com>
- *   Florian Forster <octo at collectd.org>
- *
- * Description:
- *   Encapsulates useful code to plugins which must parse a log file.
- */
-
-#include "collectd.h"
-
-#include "common.h"
-#include "plugin.h"
-#include "utils_latency_config.h"
-#include "utils_match.h"
-#include "utils_tail.h"
-#include "utils_tail_match.h"
-
-struct cu_tail_match_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];
-  cdtime_t interval;
-  latency_config_t latency_config;
-};
-typedef struct cu_tail_match_simple_s cu_tail_match_simple_t;
-
-struct cu_tail_match_match_s {
-  cu_match_t *match;
-  void *user_data;
-  int (*submit)(cu_match_t *match, void *user_data);
-  void (*free)(void *user_data);
-};
-typedef struct cu_tail_match_match_s cu_tail_match_match_t;
-
-struct cu_tail_match_s {
-  int flags;
-  cu_tail_t *tail;
-
-  cdtime_t interval;
-  cu_tail_match_match_t *matches;
-  size_t matches_num;
-};
-
-/*
- * Private functions
- */
-static int simple_submit_match(cu_match_t *match, void *user_data) {
-  cu_tail_match_simple_t *data = (cu_tail_match_simple_t *)user_data;
-  cu_match_value_t *match_value;
-  value_list_t vl = VALUE_LIST_INIT;
-  value_t values[1];
-
-  match_value = (cu_match_value_t *)match_get_user_data(match);
-  if (match_value == NULL)
-    return (-1);
-
-  if ((match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
-      (match_value->values_num == 0))
-    values[0].gauge = NAN;
-  else
-    values[0] = match_value->value;
-
-  vl.values = values;
-  vl.values_len = 1;
-  sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin));
-  sstrncpy(vl.plugin_instance, data->plugin_instance,
-           sizeof(vl.plugin_instance));
-  sstrncpy(vl.type, data->type, sizeof(vl.type));
-  sstrncpy(vl.type_instance, data->type_instance, sizeof(vl.type_instance));
-
-  vl.interval = data->interval;
-  plugin_dispatch_values(&vl);
-
-  match_value_reset(match_value);
-  return (0);
-} /* int simple_submit_match */
-
-static int latency_submit_match(cu_match_t *match, void *user_data) {
-  cu_tail_match_simple_t *data = (cu_tail_match_simple_t *)user_data;
-  cu_match_value_t *match_value;
-  value_list_t vl = VALUE_LIST_INIT;
-
-  match_value = (cu_match_value_t *)match_get_user_data(match);
-  if (match_value == NULL)
-    return (-1);
-
-  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
-  sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin));
-  sstrncpy(vl.plugin_instance, data->plugin_instance,
-           sizeof(vl.plugin_instance));
-  vl.interval = data->interval;
-  vl.time = cdtime();
-
-  /* Submit percentiles */
-  sstrncpy(vl.type, data->type, sizeof(vl.type));
-  for (size_t i = 0; i < data->latency_config.percentile_num; i++) {
-    if (strlen(data->type_instance) != 0)
-      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%.0f",
-                data->type_instance, data->latency_config.percentile[i]);
-    else
-      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%.0f",
-                data->latency_config.percentile[i]);
-
-    vl.values = &(value_t){
-        .gauge =
-            (match_value->values_num != 0)
-                ? CDTIME_T_TO_DOUBLE(latency_counter_get_percentile(
-                      match_value->latency, data->latency_config.percentile[i]))
-                : NAN,
-    };
-    vl.values_len = 1;
-
-    plugin_dispatch_values(&vl);
-  }
-
-  /* Submit buckets */
-  sstrncpy(vl.type, "bucket", sizeof(vl.type));
-  for (size_t i = 0; i < data->latency_config.buckets_num; i++) {
-    latency_bucket_t bucket = data->latency_config.buckets[i];
-
-    double lower_bound = CDTIME_T_TO_DOUBLE(bucket.lower_bound);
-    double upper_bound =
-        bucket.upper_bound ? CDTIME_T_TO_DOUBLE(bucket.upper_bound) : INFINITY;
-
-    if (strlen(data->type_instance) != 0)
-      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s-%g_%g",
-                data->type, data->type_instance, lower_bound, upper_bound);
-    else
-      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%g_%g",
-                data->type, lower_bound, upper_bound);
-
-    vl.values = &(value_t){
-        .gauge =
-            latency_counter_get_rate(match_value->latency, bucket.lower_bound,
-                                     bucket.upper_bound, vl.time),
-    };
-    vl.values_len = 1;
-
-    plugin_dispatch_values(&vl);
-  }
-
-  match_value->value.gauge = NAN;
-  match_value->values_num = 0;
-  latency_counter_reset(match_value->latency);
-
-  return (0);
-} /* int latency_submit_match */
-
-static int tail_callback(void *data, char *buf,
-                         int __attribute__((unused)) buflen) {
-  cu_tail_match_t *obj = (cu_tail_match_t *)data;
-
-  for (size_t i = 0; i < obj->matches_num; i++)
-    match_apply(obj->matches[i].match, buf);
-
-  return (0);
-} /* int tail_callback */
-
-static void tail_match_simple_free(void *data) {
-  cu_tail_match_simple_t *user_data = (cu_tail_match_simple_t *)data;
-  latency_config_free(user_data->latency_config);
-  sfree(user_data);
-} /* void tail_match_simple_free */
-
-/*
- * Public functions
- */
-cu_tail_match_t *tail_match_create(const char *filename) {
-  cu_tail_match_t *obj;
-
-  obj = calloc(1, sizeof(*obj));
-  if (obj == NULL)
-    return (NULL);
-
-  obj->tail = cu_tail_create(filename);
-  if (obj->tail == NULL) {
-    sfree(obj);
-    return (NULL);
-  }
-
-  return (obj);
-} /* cu_tail_match_t *tail_match_create */
-
-void tail_match_destroy(cu_tail_match_t *obj) {
-  if (obj == NULL)
-    return;
-
-  if (obj->tail != NULL) {
-    cu_tail_destroy(obj->tail);
-    obj->tail = NULL;
-  }
-
-  for (size_t i = 0; i < obj->matches_num; i++) {
-    cu_tail_match_match_t *match = obj->matches + i;
-    if (match->match != NULL) {
-      match_destroy(match->match);
-      match->match = NULL;
-    }
-
-    if ((match->user_data != NULL) && (match->free != NULL))
-      (*match->free)(match->user_data);
-    match->user_data = NULL;
-  }
-
-  sfree(obj->matches);
-  sfree(obj);
-} /* void tail_match_destroy */
-
-int tail_match_add_match(cu_tail_match_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_tail_match_match_t *temp;
-
-  temp = realloc(obj->matches,
-                 sizeof(cu_tail_match_match_t) * (obj->matches_num + 1));
-  if (temp == NULL)
-    return (-1);
-
-  obj->matches = temp;
-  obj->matches_num++;
-
-  DEBUG("tail_match_add_match interval %lf",
-        CDTIME_T_TO_DOUBLE(((cu_tail_match_simple_t *)user_data)->interval));
-  temp = obj->matches + (obj->matches_num - 1);
-
-  temp->match = match;
-  temp->user_data = user_data;
-  temp->submit = submit_match;
-  temp->free = free_user_data;
-
-  return (0);
-} /* int tail_match_add_match */
-
-int tail_match_add_match_simple(cu_tail_match_t *obj, const char *regex,
-                                const char *excluderegex, int ds_type,
-                                const char *plugin, const char *plugin_instance,
-                                const char *type, const char *type_instance,
-                                const latency_config_t latency_cfg,
-                                const cdtime_t interval) {
-  cu_match_t *match;
-  cu_tail_match_simple_t *user_data;
-  int status;
-
-  match = match_create_simple(regex, excluderegex, ds_type);
-  if (match == NULL)
-    return (-1);
-
-  user_data = calloc(1, sizeof(*user_data));
-  if (user_data == NULL) {
-    match_destroy(match);
-    return (-1);
-  }
-
-  sstrncpy(user_data->plugin, plugin, sizeof(user_data->plugin));
-  if (plugin_instance != NULL)
-    sstrncpy(user_data->plugin_instance, plugin_instance,
-             sizeof(user_data->plugin_instance));
-
-  sstrncpy(user_data->type, type, sizeof(user_data->type));
-  if (type_instance != NULL)
-    sstrncpy(user_data->type_instance, type_instance,
-             sizeof(user_data->type_instance));
-
-  user_data->interval = interval;
-
-  if ((ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
-      (ds_type & UTILS_MATCH_CF_GAUGE_DIST)) {
-    status = latency_config_copy(&user_data->latency_config, latency_cfg);
-    if (status != 0) {
-      ERROR("tail_match_add_match_simple: latency_config_copy() failed.");
-      status = -1;
-      goto out;
-    }
-
-    status = tail_match_add_match(obj, match, latency_submit_match, user_data,
-                                  tail_match_simple_free);
-  } else {
-    status =
-        tail_match_add_match(obj, match, simple_submit_match, user_data, free);
-  }
-
-out:
-  if (status != 0) {
-    tail_match_simple_free(user_data);
-    match_destroy(match);
-  }
-
-  return (status);
-} /* int tail_match_add_match_simple */
-
-int tail_match_read(cu_tail_match_t *obj) {
-  char buffer[4096];
-  int status;
-
-  status = cu_tail_read(obj->tail, buffer, sizeof(buffer), tail_callback,
-                        (void *)obj);
-  if (status != 0) {
-    ERROR("tail_match: cu_tail_read failed.");
-    return (status);
-  }
-
-  for (size_t i = 0; i < obj->matches_num; i++) {
-    cu_tail_match_match_t *lt_match = obj->matches + i;
-
-    if (lt_match->submit == NULL)
-      continue;
-
-    (*lt_match->submit)(lt_match->match, lt_match->user_data);
-  }
-
-  return (0);
-} /* int tail_match_read */
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/daemon/utils_tail_match.h b/src/daemon/utils_tail_match.h
deleted file mode 100644 (file)
index 09e3d40..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * collectd - src/utils_tail_match.h
- * Copyright (C) 2007-2008  C-Ware, Inc.
- * Copyright (C) 2008       Florian Forster
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *   Luke Heberling <lukeh at c-ware.com>
- *   Florian Forster <octo at collectd.org>
- *
- * Description:
- *   `tail_match' uses `utils_tail' and `utils_match' to tail a file and try to
- *   match it using several regular expressions. Matches are then passed to
- *   user-provided callback functions or default handlers. This should keep all
- *   of the parsing logic out of the actual plugin, which only operate with
- *   regular expressions.
- */
-
-#include "utils_latency_config.h"
-#include "utils_match.h"
-
-struct cu_tail_match_s;
-typedef struct cu_tail_match_s cu_tail_match_t;
-
-/*
- * NAME
- *   tail_match_create
- *
- * DESCRIPTION
- *   Allocates, initializes and returns a new `cu_tail_match_t' object.
- *
- * PARAMETERS
- *   `filename'  The name to read data from.
- *
- * RETURN VALUE
- *   Returns NULL upon failure, non-NULL otherwise.
- */
-cu_tail_match_t *tail_match_create(const char *filename);
-
-/*
- * NAME
- *   tail_match_destroy
- *
- * DESCRIPTION
- *   Releases resources used by the `cu_tail_match_t' object.
- *
- * PARAMETERS
- *   The object to destroy.
- */
-void tail_match_destroy(cu_tail_match_t *obj);
-
-/*
- * NAME
- *   tail_match_add_match
- *
- * DESCRIPTION
- *   Adds a match, in form of a `cu_match_t' object, to the object.
- *   After data has been read from the logfile (using utils_tail) the callback
- *   function `submit_match' is called with the match object and the user
- *   supplied data.
- *   Please note that his function is called regardless whether this match
- *   matched any lines recently or not.
- *   When `tail_match_destroy' is called the `user_data' pointer is freed using
- *   the `free_user_data' callback - if it is not NULL.
- *   When using this interface the `tail_match' module doesn't dispatch any
- * values
- *   itself - all that has to happen in either the match-callbacks or the
- *   submit_match callback.
- *
- * RETURN VALUE
- *   Zero upon success, non-zero otherwise.
- */
-int tail_match_add_match(cu_tail_match_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));
-
-/*
- * NAME
- *  tail_match_add_match_simple
- *
- * DESCRIPTION
- *  A simplified version of `tail_match_add_match'. The regular expressen
- * `regex'
- *  must match a number, which is then dispatched according to `ds_type'. See
- *  the `match_create_simple' function in utils_match.h for a description how
- *  this flag effects calculation of a new value.
- *  The values gathered are dispatched by the tail_match module in this case.
- * The
- *  passed `plugin', `plugin_instance', `type', and `type_instance' are
- *  directly used when submitting these values.
- *  With excluderegex it is possible to exlude lines from the match.
- *  The `latency_cfg' specifies configuration for submitting latency.
- *
- * RETURN VALUE
- *   Zero upon success, non-zero otherwise.
- */
-int tail_match_add_match_simple(cu_tail_match_t *obj, const char *regex,
-                                const char *excluderegex, int ds_type,
-                                const char *plugin, const char *plugin_instance,
-                                const char *type, const char *type_instance,
-                                const latency_config_t latency_cfg,
-                                const cdtime_t interval);
-
-/*
- * NAME
- *   tail_match_read
- *
- * DESCRIPTION
- *   This function should be called periodically by plugins. It reads new lines
- *   from the logfile using `utils_tail' and tries to match them using all
- *   added `utils_match' objects.
- *   After all lines have been read and processed, the submit_match callback is
- *   called or, in case of tail_match_add_match_simple, the data is dispatched
- * to
- *   the daemon directly.
- *
- * RETURN VALUE
- *   Zero on success, nonzero on failure.
-*/
-int tail_match_read(cu_tail_match_t *obj);
-
-/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_match.c b/src/utils_match.c
new file mode 100644 (file)
index 0000000..2e487b5
--- /dev/null
@@ -0,0 +1,372 @@
+/**
+ * collectd - src/utils_match.c
+ * Copyright (C) 2008-2014  Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+
+#include "common.h"
+#include "plugin.h"
+
+#include "utils_match.h"
+
+#include <regex.h>
+
+#define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
+
+struct cu_match_s {
+  regex_t regex;
+  regex_t excluderegex;
+  int flags;
+
+  int (*callback)(const char *str, char *const *matches, size_t matches_num,
+                  void *user_data);
+  void *user_data;
+  void (*free)(void *user_data);
+};
+
+/*
+ * Private functions
+ */
+static char *match_substr(const char *str, int begin, int end) {
+  char *ret;
+  size_t ret_len;
+
+  if ((begin < 0) || (end < 0) || (begin >= end))
+    return (NULL);
+  if ((size_t)end > (strlen(str) + 1)) {
+    ERROR("utils_match: match_substr: `end' points after end of string.");
+    return (NULL);
+  }
+
+  ret_len = end - begin;
+  ret = malloc(ret_len + 1);
+  if (ret == NULL) {
+    ERROR("utils_match: match_substr: malloc failed.");
+    return (NULL);
+  }
+
+  sstrncpy(ret, str + begin, ret_len + 1);
+  return (ret);
+} /* char *match_substr */
+
+static int default_callback(const char __attribute__((unused)) * str,
+                            char *const *matches, size_t matches_num,
+                            void *user_data) {
+  cu_match_value_t *data = (cu_match_value_t *)user_data;
+
+  if (data->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) {
+    gauge_t value;
+    char *endptr = NULL;
+
+    if (data->ds_type & UTILS_MATCH_CF_GAUGE_INC) {
+      data->value.gauge = isnan(data->value.gauge) ? 1 : data->value.gauge + 1;
+      data->values_num++;
+      return (0);
+    }
+
+    if (matches_num < 2)
+      return (-1);
+
+    value = (gauge_t)strtod(matches[1], &endptr);
+    if (matches[1] == endptr)
+      return (-1);
+
+    if (data->ds_type & UTILS_MATCH_CF_GAUGE_DIST) {
+      latency_counter_add(data->latency, DOUBLE_TO_CDTIME_T(value));
+      data->values_num++;
+      return (0);
+    }
+
+    if ((data->values_num == 0) ||
+        (data->ds_type & UTILS_MATCH_CF_GAUGE_LAST) ||
+        (data->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) {
+      data->value.gauge = value;
+    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_AVERAGE) {
+      double f = ((double)data->values_num) / ((double)(data->values_num + 1));
+      data->value.gauge = (data->value.gauge * f) + (value * (1.0 - f));
+    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MIN) {
+      if (data->value.gauge > value)
+        data->value.gauge = value;
+    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MAX) {
+      if (data->value.gauge < value)
+        data->value.gauge = value;
+    } else if (data->ds_type & UTILS_MATCH_CF_GAUGE_ADD) {
+      data->value.gauge += value;
+    } else {
+      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
+      return (-1);
+    }
+
+    data->values_num++;
+  } else if (data->ds_type & UTILS_MATCH_DS_TYPE_COUNTER) {
+    counter_t value;
+    char *endptr = NULL;
+
+    if (data->ds_type & UTILS_MATCH_CF_COUNTER_INC) {
+      data->value.counter++;
+      data->values_num++;
+      return (0);
+    }
+
+    if (matches_num < 2)
+      return (-1);
+
+    value = (counter_t)strtoull(matches[1], &endptr, 0);
+    if (matches[1] == endptr)
+      return (-1);
+
+    if (data->ds_type & UTILS_MATCH_CF_COUNTER_SET)
+      data->value.counter = value;
+    else if (data->ds_type & UTILS_MATCH_CF_COUNTER_ADD)
+      data->value.counter += value;
+    else {
+      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
+      return (-1);
+    }
+
+    data->values_num++;
+  } else if (data->ds_type & UTILS_MATCH_DS_TYPE_DERIVE) {
+    derive_t value;
+    char *endptr = NULL;
+
+    if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC) {
+      data->value.derive++;
+      data->values_num++;
+      return (0);
+    }
+
+    if (matches_num < 2)
+      return (-1);
+
+    value = (derive_t)strtoll(matches[1], &endptr, 0);
+    if (matches[1] == endptr)
+      return (-1);
+
+    if (data->ds_type & UTILS_MATCH_CF_DERIVE_SET)
+      data->value.derive = value;
+    else if (data->ds_type & UTILS_MATCH_CF_DERIVE_ADD)
+      data->value.derive += value;
+    else {
+      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
+      return (-1);
+    }
+
+    data->values_num++;
+  } else if (data->ds_type & UTILS_MATCH_DS_TYPE_ABSOLUTE) {
+    absolute_t value;
+    char *endptr = NULL;
+
+    if (matches_num < 2)
+      return (-1);
+
+    value = (absolute_t)strtoull(matches[1], &endptr, 0);
+    if (matches[1] == endptr)
+      return (-1);
+
+    if (data->ds_type & UTILS_MATCH_CF_ABSOLUTE_SET)
+      data->value.absolute = value;
+    else {
+      ERROR("utils_match: default_callback: obj->ds_type is invalid!");
+      return (-1);
+    }
+
+    data->values_num++;
+  } else {
+    ERROR("utils_match: default_callback: obj->ds_type is invalid!");
+    return (-1);
+  }
+
+  return (0);
+} /* int default_callback */
+
+static void match_simple_free(void *data) {
+  cu_match_value_t *user_data = (cu_match_value_t *)data;
+  if (user_data->latency)
+    latency_counter_destroy(user_data->latency);
+
+  free(data);
+} /* void match_simple_free */
+
+/*
+ * Public functions
+ */
+cu_match_t *
+match_create_callback(const char *regex, const char *excluderegex,
+                      int (*callback)(const char *str, char *const *matches,
+                                      size_t matches_num, void *user_data),
+                      void *user_data,
+                      void (*free_user_data)(void *user_data)) {
+  cu_match_t *obj;
+  int status;
+
+  DEBUG("utils_match: match_create_callback: regex = %s, excluderegex = %s",
+        regex, excluderegex);
+
+  obj = calloc(1, sizeof(*obj));
+  if (obj == NULL)
+    return (NULL);
+
+  status = regcomp(&obj->regex, regex, REG_EXTENDED | REG_NEWLINE);
+  if (status != 0) {
+    ERROR("Compiling the regular expression \"%s\" failed.", regex);
+    sfree(obj);
+    return (NULL);
+  }
+
+  if (excluderegex && strcmp(excluderegex, "") != 0) {
+    status = regcomp(&obj->excluderegex, excluderegex, REG_EXTENDED);
+    if (status != 0) {
+      ERROR("Compiling the excluding regular expression \"%s\" failed.",
+            excluderegex);
+      sfree(obj);
+      return (NULL);
+    }
+    obj->flags |= UTILS_MATCH_FLAGS_EXCLUDE_REGEX;
+  }
+
+  obj->callback = callback;
+  obj->user_data = user_data;
+  obj->free = free_user_data;
+
+  return (obj);
+} /* cu_match_t *match_create_callback */
+
+cu_match_t *match_create_simple(const char *regex, const char *excluderegex,
+                                int match_ds_type) {
+  cu_match_value_t *user_data;
+  cu_match_t *obj;
+
+  user_data = calloc(1, sizeof(*user_data));
+  if (user_data == NULL)
+    return (NULL);
+  user_data->ds_type = match_ds_type;
+
+  if ((match_ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
+      (match_ds_type & UTILS_MATCH_CF_GAUGE_DIST)) {
+    user_data->latency = latency_counter_create();
+    if (user_data->latency == NULL) {
+      ERROR("match_create_simple(): latency_counter_create() failed.");
+      free(user_data);
+      return (NULL);
+    }
+  }
+
+  obj = match_create_callback(regex, excluderegex, default_callback, user_data,
+                              match_simple_free);
+  if (obj == NULL) {
+    if (user_data->latency)
+      latency_counter_destroy(user_data->latency);
+
+    sfree(user_data);
+    return (NULL);
+  }
+  return (obj);
+} /* cu_match_t *match_create_simple */
+
+void match_value_reset(cu_match_value_t *mv) {
+  if (mv == NULL)
+    return;
+
+  /* Reset GAUGE metrics only and except GAUGE_PERSIST. */
+  if ((mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
+      !(mv->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) {
+    mv->value.gauge = NAN;
+    mv->values_num = 0;
+  }
+} /* }}} void match_value_reset */
+
+void match_destroy(cu_match_t *obj) {
+  if (obj == NULL)
+    return;
+
+  if ((obj->user_data != NULL) && (obj->free != NULL))
+    (*obj->free)(obj->user_data);
+
+  sfree(obj);
+} /* void match_destroy */
+
+int match_apply(cu_match_t *obj, const char *str) {
+  int status;
+  regmatch_t re_match[32];
+  char *matches[32] = {0};
+  size_t matches_num;
+
+  if ((obj == NULL) || (str == NULL))
+    return (-1);
+
+  if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) {
+    status =
+        regexec(&obj->excluderegex, str, STATIC_ARRAY_SIZE(re_match), re_match,
+                /* eflags = */ 0);
+    /* Regex did match, so exclude this line */
+    if (status == 0) {
+      DEBUG("ExludeRegex matched, don't count that line\n");
+      return (0);
+    }
+  }
+
+  status = regexec(&obj->regex, str, STATIC_ARRAY_SIZE(re_match), re_match,
+                   /* eflags = */ 0);
+
+  /* Regex did not match */
+  if (status != 0)
+    return (0);
+
+  for (matches_num = 0; matches_num < STATIC_ARRAY_SIZE(matches);
+       matches_num++) {
+    if ((re_match[matches_num].rm_so < 0) || (re_match[matches_num].rm_eo < 0))
+      break;
+
+    matches[matches_num] = match_substr(str, re_match[matches_num].rm_so,
+                                        re_match[matches_num].rm_eo);
+    if (matches[matches_num] == NULL) {
+      status = -1;
+      break;
+    }
+  }
+
+  if (status != 0) {
+    ERROR("utils_match: match_apply: match_substr failed.");
+  } else {
+    status = obj->callback(str, matches, matches_num, obj->user_data);
+    if (status != 0) {
+      ERROR("utils_match: match_apply: callback failed.");
+    }
+  }
+
+  for (size_t i = 0; i < matches_num; i++) {
+    sfree(matches[i]);
+  }
+
+  return (status);
+} /* int match_apply */
+
+void *match_get_user_data(cu_match_t *obj) {
+  if (obj == NULL)
+    return (NULL);
+  return (obj->user_data);
+} /* void *match_get_user_data */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_match.h b/src/utils_match.h
new file mode 100644 (file)
index 0000000..1383530
--- /dev/null
@@ -0,0 +1,181 @@
+/**
+ * collectd - src/utils_match.h
+ * Copyright (C) 2008-2014  Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_MATCH_H
+#define UTILS_MATCH_H 1
+
+#include "plugin.h"
+#include "utils_latency.h"
+
+/*
+ * Each type may have 12 sub-types
+ * 0x1000 = 1000000000000
+ *          ^             <- Type bit
+ *           ^^^^^^^^^^^^ <- Subtype bits
+ */
+#define UTILS_MATCH_DS_TYPE_GAUGE 0x1000
+#define UTILS_MATCH_DS_TYPE_COUNTER 0x2000
+#define UTILS_MATCH_DS_TYPE_DERIVE 0x4000
+#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x8000
+
+#define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
+#define UTILS_MATCH_CF_GAUGE_MIN 0x02
+#define UTILS_MATCH_CF_GAUGE_MAX 0x04
+#define UTILS_MATCH_CF_GAUGE_LAST 0x08
+#define UTILS_MATCH_CF_GAUGE_INC 0x10
+#define UTILS_MATCH_CF_GAUGE_ADD 0x20
+#define UTILS_MATCH_CF_GAUGE_PERSIST 0x40
+#define UTILS_MATCH_CF_GAUGE_DIST 0x80
+
+#define UTILS_MATCH_CF_COUNTER_SET 0x01
+#define UTILS_MATCH_CF_COUNTER_ADD 0x02
+#define UTILS_MATCH_CF_COUNTER_INC 0x04
+
+#define UTILS_MATCH_CF_DERIVE_SET 0x01
+#define UTILS_MATCH_CF_DERIVE_ADD 0x02
+#define UTILS_MATCH_CF_DERIVE_INC 0x04
+
+#define UTILS_MATCH_CF_ABSOLUTE_SET 0x01
+#define UTILS_MATCH_CF_ABSOLUTE_ADD 0x02
+#define UTILS_MATCH_CF_ABSOLUTE_INC 0x04
+
+/*
+ * Data types
+ */
+struct cu_match_s;
+typedef struct cu_match_s cu_match_t;
+
+struct cu_match_value_s {
+  int ds_type;
+  value_t value;
+  unsigned int values_num;
+  latency_counter_t *latency;
+};
+typedef struct cu_match_value_s cu_match_value_t;
+
+/*
+ * Prototypes
+ */
+/*
+ * NAME
+ *  match_create_callback
+ *
+ * DESCRIPTION
+ *  Creates a new `cu_match_t' object which will use the regular expression
+ *  `regex' to match lines, see the `match_apply' method below. If the line
+ *  matches, the callback passed in `callback' will be called along with the
+ *  pointer `user_pointer'.
+ *  The string that's passed to the callback depends on the regular expression:
+ *  If the regular expression includes a sub-match, i. e. something like
+ *    "value=([0-9][0-9]*)"
+ *  then only the submatch (the part in the parenthesis) will be passed to the
+ *  callback. If there is no submatch, then the entire string is passed to the
+ *  callback.
+ *  The optional `excluderegex' allows to exclude the line from the match, if
+ *  the excluderegex matches.
+ *  When `match_destroy' is called the `user_data' pointer is freed using
+ *  the `free_user_data' callback - if it is not NULL.
+ */
+cu_match_t *
+match_create_callback(const char *regex, const char *excluderegex,
+                      int (*callback)(const char *str, char *const *matches,
+                                      size_t matches_num, void *user_data),
+                      void *user_data, void (*free_user_data)(void *user_data));
+
+/*
+ * NAME
+ *  match_create_simple
+ *
+ * DESCRIPTION
+ *  Creates a new `cu_match_t' with a default callback. The user data for that
+ *  default callback will be a `cu_match_value_t' structure, with
+ *  `ds_type' copied to the structure. The default callback will handle the
+ *  string as containing a number (see strtoll(3) and strtod(3)) and store that
+ *  number in the `value' member. How that is done depends on `ds_type':
+ *
+ *  UTILS_MATCH_DS_TYPE_GAUGE
+ *    The function will search for a floating point number in the string and
+ *    store it in value.gauge.
+ *  UTILS_MATCH_DS_TYPE_COUNTER_SET
+ *    The function will search for an integer in the string and store it in
+ *    value.counter.
+ *  UTILS_MATCH_DS_TYPE_COUNTER_ADD
+ *    The function will search for an integer in the string and add it to the
+ *    value in value.counter.
+ *  UTILS_MATCH_DS_TYPE_COUNTER_INC
+ *    The function will not search for anything in the string and increase
+ *    value.counter by one.
+ */
+cu_match_t *match_create_simple(const char *regex, const char *excluderegex,
+                                int ds_type);
+
+/*
+ * NAME
+ *  match_value_reset
+ *
+ * DESCRIPTION
+ *   Resets the internal state, if applicable. This function must be called
+ *   after each iteration for "simple" matches, usually after dispatching the
+ *   metrics.
+ */
+void match_value_reset(cu_match_value_t *mv);
+
+/*
+ * NAME
+ *  match_destroy
+ *
+ * DESCRIPTION
+ *  Destroys the object and frees all internal resources.
+ */
+void match_destroy(cu_match_t *obj);
+
+/*
+ * NAME
+ *  match_apply
+ *
+ * DESCRIPTION
+ *  Tries to match the string `str' with the regular expression of `obj'. If
+ *  the string matches, calls the callback in `obj' with the (sub-)match.
+ *
+ *  The user_data pointer passed to `match_create_callback' is NOT freed
+ *  automatically. The `cu_match_value_t' structure allocated by
+ *  `match_create_callback' is freed automatically.
+ */
+int match_apply(cu_match_t *obj, const char *str);
+
+/*
+ * NAME
+ *  match_get_user_data
+ *
+ * DESCRIPTION
+ *  Returns the pointer passed to `match_create_callback' or a pointer to the
+ *  `cu_match_value_t' structure allocated by `match_create_simple'.
+ */
+void *match_get_user_data(cu_match_t *obj);
+
+#endif /* UTILS_MATCH_H */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_tail.c b/src/utils_tail.c
new file mode 100644 (file)
index 0000000..565a224
--- /dev/null
@@ -0,0 +1,235 @@
+/**
+ * collectd - src/utils_tail.c
+ * Copyright (C) 2007-2008  C-Ware, Inc.
+ * Copyright (C) 2008       Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ *   Luke Heberling <lukeh at c-ware.com>
+ *   Florian Forster <octo at collectd.org>
+ *
+ * Description:
+ *   Encapsulates useful code for plugins which must watch for appends to
+ *   the end of a file.
+ **/
+
+#include "collectd.h"
+
+#include "common.h"
+#include "utils_tail.h"
+
+struct cu_tail_s {
+  char *file;
+  FILE *fh;
+  struct stat stat;
+};
+
+static int cu_tail_reopen(cu_tail_t *obj) {
+  int seek_end = 0;
+  FILE *fh;
+  struct stat stat_buf = {0};
+  int status;
+
+  status = stat(obj->file, &stat_buf);
+  if (status != 0) {
+    char errbuf[1024];
+    ERROR("utils_tail: stat (%s) failed: %s", obj->file,
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    return (-1);
+  }
+
+  /* The file is already open.. */
+  if ((obj->fh != NULL) && (stat_buf.st_ino == obj->stat.st_ino)) {
+    /* Seek to the beginning if file was truncated */
+    if (stat_buf.st_size < obj->stat.st_size) {
+      INFO("utils_tail: File `%s' was truncated.", obj->file);
+      status = fseek(obj->fh, 0, SEEK_SET);
+      if (status != 0) {
+        char errbuf[1024];
+        ERROR("utils_tail: fseek (%s) failed: %s", obj->file,
+              sstrerror(errno, errbuf, sizeof(errbuf)));
+        fclose(obj->fh);
+        obj->fh = NULL;
+        return (-1);
+      }
+    }
+    memcpy(&obj->stat, &stat_buf, sizeof(struct stat));
+    return (1);
+  }
+
+  /* Seek to the end if we re-open the same file again or the file opened
+   * is the first at all or the first after an error */
+  if ((obj->stat.st_ino == 0) || (obj->stat.st_ino == stat_buf.st_ino))
+    seek_end = 1;
+
+  fh = fopen(obj->file, "r");
+  if (fh == NULL) {
+    char errbuf[1024];
+    ERROR("utils_tail: fopen (%s) failed: %s", obj->file,
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    return (-1);
+  }
+
+  if (seek_end != 0) {
+    status = fseek(fh, 0, SEEK_END);
+    if (status != 0) {
+      char errbuf[1024];
+      ERROR("utils_tail: fseek (%s) failed: %s", obj->file,
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+      fclose(fh);
+      return (-1);
+    }
+  }
+
+  if (obj->fh != NULL)
+    fclose(obj->fh);
+  obj->fh = fh;
+  memcpy(&obj->stat, &stat_buf, sizeof(struct stat));
+
+  return (0);
+} /* int cu_tail_reopen */
+
+cu_tail_t *cu_tail_create(const char *file) {
+  cu_tail_t *obj;
+
+  obj = calloc(1, sizeof(*obj));
+  if (obj == NULL)
+    return (NULL);
+
+  obj->file = strdup(file);
+  if (obj->file == NULL) {
+    free(obj);
+    return (NULL);
+  }
+
+  obj->fh = NULL;
+
+  return (obj);
+} /* cu_tail_t *cu_tail_create */
+
+int cu_tail_destroy(cu_tail_t *obj) {
+  if (obj->fh != NULL)
+    fclose(obj->fh);
+  free(obj->file);
+  free(obj);
+
+  return (0);
+} /* int cu_tail_destroy */
+
+int cu_tail_readline(cu_tail_t *obj, char *buf, int buflen) {
+  int status;
+
+  if (buflen < 1) {
+    ERROR("utils_tail: cu_tail_readline: buflen too small: %i bytes.", buflen);
+    return (-1);
+  }
+
+  if (obj->fh == NULL) {
+    status = cu_tail_reopen(obj);
+    if (status < 0)
+      return (status);
+  }
+  assert(obj->fh != NULL);
+
+  /* Try to read from the filehandle. If that succeeds, everything appears to
+   * be fine and we can return. */
+  clearerr(obj->fh);
+  if (fgets(buf, buflen, obj->fh) != NULL) {
+    buf[buflen - 1] = 0;
+    return (0);
+  }
+
+  /* Check if we encountered an error */
+  if (ferror(obj->fh) != 0) {
+    /* Jupp, error. Force `cu_tail_reopen' to reopen the file.. */
+    fclose(obj->fh);
+    obj->fh = NULL;
+  }
+  /* else: eof -> check if the file was moved away and reopen the new file if
+   * so.. */
+
+  status = cu_tail_reopen(obj);
+  /* error -> return with error */
+  if (status < 0)
+    return (status);
+  /* file end reached and file not reopened -> nothing more to read */
+  else if (status > 0) {
+    buf[0] = 0;
+    return (0);
+  }
+
+  /* If we get here: file was re-opened and there may be more to read.. Let's
+   * try again. */
+  if (fgets(buf, buflen, obj->fh) != NULL) {
+    buf[buflen - 1] = 0;
+    return (0);
+  }
+
+  if (ferror(obj->fh) != 0) {
+    char errbuf[1024];
+    WARNING("utils_tail: fgets (%s) returned an error: %s", obj->file,
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+    fclose(obj->fh);
+    obj->fh = NULL;
+    return (-1);
+  }
+
+  /* EOf, well, apparently the new file is empty.. */
+  buf[0] = 0;
+  return (0);
+} /* int cu_tail_readline */
+
+int cu_tail_read(cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
+                 void *data) {
+  int status;
+
+  while (42) {
+    size_t len;
+
+    status = cu_tail_readline(obj, buf, buflen);
+    if (status != 0) {
+      ERROR("utils_tail: cu_tail_read: cu_tail_readline "
+            "failed.");
+      break;
+    }
+
+    /* check for EOF */
+    if (buf[0] == 0)
+      break;
+
+    len = strlen(buf);
+    while (len > 0) {
+      if (buf[len - 1] != '\n')
+        break;
+      buf[len - 1] = '\0';
+      len--;
+    }
+
+    status = callback(data, buf, buflen);
+    if (status != 0) {
+      ERROR("utils_tail: cu_tail_read: callback returned "
+            "status %i.",
+            status);
+      break;
+    }
+  }
+
+  return status;
+} /* int cu_tail_read */
diff --git a/src/utils_tail.h b/src/utils_tail.h
new file mode 100644 (file)
index 0000000..73a6de2
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * collectd - src/utils_tail.h
+ * Copyright (C) 2007-2008  C-Ware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ *   Luke Heberling <lukeh at c-ware.com>
+ *
+ * DESCRIPTION
+ *   Facilitates reading information that is appended to a file, taking into
+ *   account that the file may be rotated and a new file created under the
+ *   same name.
+ **/
+
+#ifndef UTILS_TAIL_H
+#define UTILS_TAIL_H 1
+
+struct cu_tail_s;
+typedef struct cu_tail_s cu_tail_t;
+
+typedef int tailfunc_t(void *data, char *buf, int buflen);
+
+/*
+ * NAME
+ *   cu_tail_create
+ *
+ * DESCRIPTION
+ *   Allocates a new tail object..
+ *
+ * PARAMETERS
+ *   `file'       The name of the file to be tailed.
+ */
+cu_tail_t *cu_tail_create(const char *file);
+
+/*
+ * cu_tail_destroy
+ *
+ * Takes a tail object returned by `cu_tail_create' and destroys it, freeing
+ * all internal memory.
+ *
+ * Returns 0 when successful and non-zero otherwise.
+ */
+int cu_tail_destroy(cu_tail_t *obj);
+
+/*
+ * cu_tail_readline
+ *
+ * Reads from the file until `buflen' characters are read, a newline
+ * character is read, or an eof condition is encountered. `buf' is
+ * always null-terminated on successful return and isn't touched when non-zero
+ * is returned.
+ *
+ * You can check if the EOF condition is reached by looking at the buffer: If
+ * the length of the string stored in the buffer is zero, EOF occurred.
+ * Otherwise at least the newline character will be in the buffer.
+ *
+ * Returns 0 when successful and non-zero otherwise.
+ */
+int cu_tail_readline(cu_tail_t *obj, char *buf, int buflen);
+
+/*
+ * cu_tail_readline
+ *
+ * Reads from the file until eof condition or an error is encountered.
+ *
+ * Returns 0 when successful and non-zero otherwise.
+ */
+int cu_tail_read(cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
+                 void *data);
+
+#endif /* UTILS_TAIL_H */
diff --git a/src/utils_tail_match.c b/src/utils_tail_match.c
new file mode 100644 (file)
index 0000000..505c693
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * collectd - src/utils_tail_match.c
+ * Copyright (C) 2007-2008  C-Ware, Inc.
+ * Copyright (C) 2008       Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ *   Luke Heberling <lukeh at c-ware.com>
+ *   Florian Forster <octo at collectd.org>
+ *
+ * Description:
+ *   Encapsulates useful code to plugins which must parse a log file.
+ */
+
+#include "collectd.h"
+
+#include "common.h"
+#include "plugin.h"
+#include "utils_latency_config.h"
+#include "utils_match.h"
+#include "utils_tail.h"
+#include "utils_tail_match.h"
+
+struct cu_tail_match_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];
+  cdtime_t interval;
+  latency_config_t latency_config;
+};
+typedef struct cu_tail_match_simple_s cu_tail_match_simple_t;
+
+struct cu_tail_match_match_s {
+  cu_match_t *match;
+  void *user_data;
+  int (*submit)(cu_match_t *match, void *user_data);
+  void (*free)(void *user_data);
+};
+typedef struct cu_tail_match_match_s cu_tail_match_match_t;
+
+struct cu_tail_match_s {
+  int flags;
+  cu_tail_t *tail;
+
+  cdtime_t interval;
+  cu_tail_match_match_t *matches;
+  size_t matches_num;
+};
+
+/*
+ * Private functions
+ */
+static int simple_submit_match(cu_match_t *match, void *user_data) {
+  cu_tail_match_simple_t *data = (cu_tail_match_simple_t *)user_data;
+  cu_match_value_t *match_value;
+  value_list_t vl = VALUE_LIST_INIT;
+  value_t values[1];
+
+  match_value = (cu_match_value_t *)match_get_user_data(match);
+  if (match_value == NULL)
+    return (-1);
+
+  if ((match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
+      (match_value->values_num == 0))
+    values[0].gauge = NAN;
+  else
+    values[0] = match_value->value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin));
+  sstrncpy(vl.plugin_instance, data->plugin_instance,
+           sizeof(vl.plugin_instance));
+  sstrncpy(vl.type, data->type, sizeof(vl.type));
+  sstrncpy(vl.type_instance, data->type_instance, sizeof(vl.type_instance));
+
+  vl.interval = data->interval;
+  plugin_dispatch_values(&vl);
+
+  match_value_reset(match_value);
+  return (0);
+} /* int simple_submit_match */
+
+static int latency_submit_match(cu_match_t *match, void *user_data) {
+  cu_tail_match_simple_t *data = (cu_tail_match_simple_t *)user_data;
+  cu_match_value_t *match_value;
+  value_list_t vl = VALUE_LIST_INIT;
+
+  match_value = (cu_match_value_t *)match_get_user_data(match);
+  if (match_value == NULL)
+    return (-1);
+
+  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
+  sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin));
+  sstrncpy(vl.plugin_instance, data->plugin_instance,
+           sizeof(vl.plugin_instance));
+  vl.interval = data->interval;
+  vl.time = cdtime();
+
+  /* Submit percentiles */
+  sstrncpy(vl.type, data->type, sizeof(vl.type));
+  for (size_t i = 0; i < data->latency_config.percentile_num; i++) {
+    if (strlen(data->type_instance) != 0)
+      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%.0f",
+                data->type_instance, data->latency_config.percentile[i]);
+    else
+      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%.0f",
+                data->latency_config.percentile[i]);
+
+    vl.values = &(value_t){
+        .gauge =
+            (match_value->values_num != 0)
+                ? CDTIME_T_TO_DOUBLE(latency_counter_get_percentile(
+                      match_value->latency, data->latency_config.percentile[i]))
+                : NAN,
+    };
+    vl.values_len = 1;
+
+    plugin_dispatch_values(&vl);
+  }
+
+  /* Submit buckets */
+  sstrncpy(vl.type, "bucket", sizeof(vl.type));
+  for (size_t i = 0; i < data->latency_config.buckets_num; i++) {
+    latency_bucket_t bucket = data->latency_config.buckets[i];
+
+    double lower_bound = CDTIME_T_TO_DOUBLE(bucket.lower_bound);
+    double upper_bound =
+        bucket.upper_bound ? CDTIME_T_TO_DOUBLE(bucket.upper_bound) : INFINITY;
+
+    if (strlen(data->type_instance) != 0)
+      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s-%g_%g",
+                data->type, data->type_instance, lower_bound, upper_bound);
+    else
+      ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%g_%g",
+                data->type, lower_bound, upper_bound);
+
+    vl.values = &(value_t){
+        .gauge =
+            latency_counter_get_rate(match_value->latency, bucket.lower_bound,
+                                     bucket.upper_bound, vl.time),
+    };
+    vl.values_len = 1;
+
+    plugin_dispatch_values(&vl);
+  }
+
+  match_value->value.gauge = NAN;
+  match_value->values_num = 0;
+  latency_counter_reset(match_value->latency);
+
+  return (0);
+} /* int latency_submit_match */
+
+static int tail_callback(void *data, char *buf,
+                         int __attribute__((unused)) buflen) {
+  cu_tail_match_t *obj = (cu_tail_match_t *)data;
+
+  for (size_t i = 0; i < obj->matches_num; i++)
+    match_apply(obj->matches[i].match, buf);
+
+  return (0);
+} /* int tail_callback */
+
+static void tail_match_simple_free(void *data) {
+  cu_tail_match_simple_t *user_data = (cu_tail_match_simple_t *)data;
+  latency_config_free(user_data->latency_config);
+  sfree(user_data);
+} /* void tail_match_simple_free */
+
+/*
+ * Public functions
+ */
+cu_tail_match_t *tail_match_create(const char *filename) {
+  cu_tail_match_t *obj;
+
+  obj = calloc(1, sizeof(*obj));
+  if (obj == NULL)
+    return (NULL);
+
+  obj->tail = cu_tail_create(filename);
+  if (obj->tail == NULL) {
+    sfree(obj);
+    return (NULL);
+  }
+
+  return (obj);
+} /* cu_tail_match_t *tail_match_create */
+
+void tail_match_destroy(cu_tail_match_t *obj) {
+  if (obj == NULL)
+    return;
+
+  if (obj->tail != NULL) {
+    cu_tail_destroy(obj->tail);
+    obj->tail = NULL;
+  }
+
+  for (size_t i = 0; i < obj->matches_num; i++) {
+    cu_tail_match_match_t *match = obj->matches + i;
+    if (match->match != NULL) {
+      match_destroy(match->match);
+      match->match = NULL;
+    }
+
+    if ((match->user_data != NULL) && (match->free != NULL))
+      (*match->free)(match->user_data);
+    match->user_data = NULL;
+  }
+
+  sfree(obj->matches);
+  sfree(obj);
+} /* void tail_match_destroy */
+
+int tail_match_add_match(cu_tail_match_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_tail_match_match_t *temp;
+
+  temp = realloc(obj->matches,
+                 sizeof(cu_tail_match_match_t) * (obj->matches_num + 1));
+  if (temp == NULL)
+    return (-1);
+
+  obj->matches = temp;
+  obj->matches_num++;
+
+  DEBUG("tail_match_add_match interval %lf",
+        CDTIME_T_TO_DOUBLE(((cu_tail_match_simple_t *)user_data)->interval));
+  temp = obj->matches + (obj->matches_num - 1);
+
+  temp->match = match;
+  temp->user_data = user_data;
+  temp->submit = submit_match;
+  temp->free = free_user_data;
+
+  return (0);
+} /* int tail_match_add_match */
+
+int tail_match_add_match_simple(cu_tail_match_t *obj, const char *regex,
+                                const char *excluderegex, int ds_type,
+                                const char *plugin, const char *plugin_instance,
+                                const char *type, const char *type_instance,
+                                const latency_config_t latency_cfg,
+                                const cdtime_t interval) {
+  cu_match_t *match;
+  cu_tail_match_simple_t *user_data;
+  int status;
+
+  match = match_create_simple(regex, excluderegex, ds_type);
+  if (match == NULL)
+    return (-1);
+
+  user_data = calloc(1, sizeof(*user_data));
+  if (user_data == NULL) {
+    match_destroy(match);
+    return (-1);
+  }
+
+  sstrncpy(user_data->plugin, plugin, sizeof(user_data->plugin));
+  if (plugin_instance != NULL)
+    sstrncpy(user_data->plugin_instance, plugin_instance,
+             sizeof(user_data->plugin_instance));
+
+  sstrncpy(user_data->type, type, sizeof(user_data->type));
+  if (type_instance != NULL)
+    sstrncpy(user_data->type_instance, type_instance,
+             sizeof(user_data->type_instance));
+
+  user_data->interval = interval;
+
+  if ((ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
+      (ds_type & UTILS_MATCH_CF_GAUGE_DIST)) {
+    status = latency_config_copy(&user_data->latency_config, latency_cfg);
+    if (status != 0) {
+      ERROR("tail_match_add_match_simple: latency_config_copy() failed.");
+      status = -1;
+      goto out;
+    }
+
+    status = tail_match_add_match(obj, match, latency_submit_match, user_data,
+                                  tail_match_simple_free);
+  } else {
+    status =
+        tail_match_add_match(obj, match, simple_submit_match, user_data, free);
+  }
+
+out:
+  if (status != 0) {
+    tail_match_simple_free(user_data);
+    match_destroy(match);
+  }
+
+  return (status);
+} /* int tail_match_add_match_simple */
+
+int tail_match_read(cu_tail_match_t *obj) {
+  char buffer[4096];
+  int status;
+
+  status = cu_tail_read(obj->tail, buffer, sizeof(buffer), tail_callback,
+                        (void *)obj);
+  if (status != 0) {
+    ERROR("tail_match: cu_tail_read failed.");
+    return (status);
+  }
+
+  for (size_t i = 0; i < obj->matches_num; i++) {
+    cu_tail_match_match_t *lt_match = obj->matches + i;
+
+    if (lt_match->submit == NULL)
+      continue;
+
+    (*lt_match->submit)(lt_match->match, lt_match->user_data);
+  }
+
+  return (0);
+} /* int tail_match_read */
+
+/* vim: set sw=2 sts=2 ts=8 : */
diff --git a/src/utils_tail_match.h b/src/utils_tail_match.h
new file mode 100644 (file)
index 0000000..09e3d40
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * collectd - src/utils_tail_match.h
+ * Copyright (C) 2007-2008  C-Ware, Inc.
+ * Copyright (C) 2008       Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Luke Heberling <lukeh at c-ware.com>
+ *   Florian Forster <octo at collectd.org>
+ *
+ * Description:
+ *   `tail_match' uses `utils_tail' and `utils_match' to tail a file and try to
+ *   match it using several regular expressions. Matches are then passed to
+ *   user-provided callback functions or default handlers. This should keep all
+ *   of the parsing logic out of the actual plugin, which only operate with
+ *   regular expressions.
+ */
+
+#include "utils_latency_config.h"
+#include "utils_match.h"
+
+struct cu_tail_match_s;
+typedef struct cu_tail_match_s cu_tail_match_t;
+
+/*
+ * NAME
+ *   tail_match_create
+ *
+ * DESCRIPTION
+ *   Allocates, initializes and returns a new `cu_tail_match_t' object.
+ *
+ * PARAMETERS
+ *   `filename'  The name to read data from.
+ *
+ * RETURN VALUE
+ *   Returns NULL upon failure, non-NULL otherwise.
+ */
+cu_tail_match_t *tail_match_create(const char *filename);
+
+/*
+ * NAME
+ *   tail_match_destroy
+ *
+ * DESCRIPTION
+ *   Releases resources used by the `cu_tail_match_t' object.
+ *
+ * PARAMETERS
+ *   The object to destroy.
+ */
+void tail_match_destroy(cu_tail_match_t *obj);
+
+/*
+ * NAME
+ *   tail_match_add_match
+ *
+ * DESCRIPTION
+ *   Adds a match, in form of a `cu_match_t' object, to the object.
+ *   After data has been read from the logfile (using utils_tail) the callback
+ *   function `submit_match' is called with the match object and the user
+ *   supplied data.
+ *   Please note that his function is called regardless whether this match
+ *   matched any lines recently or not.
+ *   When `tail_match_destroy' is called the `user_data' pointer is freed using
+ *   the `free_user_data' callback - if it is not NULL.
+ *   When using this interface the `tail_match' module doesn't dispatch any
+ * values
+ *   itself - all that has to happen in either the match-callbacks or the
+ *   submit_match callback.
+ *
+ * RETURN VALUE
+ *   Zero upon success, non-zero otherwise.
+ */
+int tail_match_add_match(cu_tail_match_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));
+
+/*
+ * NAME
+ *  tail_match_add_match_simple
+ *
+ * DESCRIPTION
+ *  A simplified version of `tail_match_add_match'. The regular expressen
+ * `regex'
+ *  must match a number, which is then dispatched according to `ds_type'. See
+ *  the `match_create_simple' function in utils_match.h for a description how
+ *  this flag effects calculation of a new value.
+ *  The values gathered are dispatched by the tail_match module in this case.
+ * The
+ *  passed `plugin', `plugin_instance', `type', and `type_instance' are
+ *  directly used when submitting these values.
+ *  With excluderegex it is possible to exlude lines from the match.
+ *  The `latency_cfg' specifies configuration for submitting latency.
+ *
+ * RETURN VALUE
+ *   Zero upon success, non-zero otherwise.
+ */
+int tail_match_add_match_simple(cu_tail_match_t *obj, const char *regex,
+                                const char *excluderegex, int ds_type,
+                                const char *plugin, const char *plugin_instance,
+                                const char *type, const char *type_instance,
+                                const latency_config_t latency_cfg,
+                                const cdtime_t interval);
+
+/*
+ * NAME
+ *   tail_match_read
+ *
+ * DESCRIPTION
+ *   This function should be called periodically by plugins. It reads new lines
+ *   from the logfile using `utils_tail' and tries to match them using all
+ *   added `utils_match' objects.
+ *   After all lines have been read and processed, the submit_match callback is
+ *   called or, in case of tail_match_add_match_simple, the data is dispatched
+ * to
+ *   the daemon directly.
+ *
+ * RETURN VALUE
+ *   Zero on success, nonzero on failure.
+*/
+int tail_match_read(cu_tail_match_t *obj);
+
+/* vim: set sw=2 sts=2 ts=8 : */