Merge branch 'collectd-5.5' into collectd-5.6
[collectd.git] / src / daemon / utils_tail_match.c
1 /*
2  * collectd - src/utils_tail_match.c
3  * Copyright (C) 2007-2008  C-Ware, Inc.
4  * Copyright (C) 2008       Florian Forster
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Author:
25  *   Luke Heberling <lukeh at c-ware.com>
26  *   Florian Forster <octo at collectd.org>
27  *
28  * Description:
29  *   Encapsulates useful code to plugins which must parse a log file.
30  */
31
32 #include "collectd.h"
33
34 #include "common.h"
35 #include "plugin.h"
36 #include "utils_match.h"
37 #include "utils_tail.h"
38 #include "utils_tail_match.h"
39
40 struct cu_tail_match_simple_s {
41   char plugin[DATA_MAX_NAME_LEN];
42   char plugin_instance[DATA_MAX_NAME_LEN];
43   char type[DATA_MAX_NAME_LEN];
44   char type_instance[DATA_MAX_NAME_LEN];
45   cdtime_t interval;
46 };
47 typedef struct cu_tail_match_simple_s cu_tail_match_simple_t;
48
49 struct cu_tail_match_match_s {
50   cu_match_t *match;
51   void *user_data;
52   int (*submit)(cu_match_t *match, void *user_data);
53   void (*free)(void *user_data);
54 };
55 typedef struct cu_tail_match_match_s cu_tail_match_match_t;
56
57 struct cu_tail_match_s {
58   int flags;
59   cu_tail_t *tail;
60
61   cdtime_t interval;
62   cu_tail_match_match_t *matches;
63   size_t matches_num;
64 };
65
66 /*
67  * Private functions
68  */
69 static int simple_submit_match(cu_match_t *match, void *user_data) {
70   cu_tail_match_simple_t *data = (cu_tail_match_simple_t *)user_data;
71   cu_match_value_t *match_value;
72   value_list_t vl = VALUE_LIST_INIT;
73   value_t values[1];
74
75   match_value = (cu_match_value_t *)match_get_user_data(match);
76   if (match_value == NULL)
77     return (-1);
78
79   if ((match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
80       (match_value->values_num == 0))
81     values[0].gauge = NAN;
82   else
83     values[0] = match_value->value;
84
85   vl.values = values;
86   vl.values_len = 1;
87   sstrncpy(vl.host, hostname_g, sizeof(vl.host));
88   sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin));
89   sstrncpy(vl.plugin_instance, data->plugin_instance,
90            sizeof(vl.plugin_instance));
91   sstrncpy(vl.type, data->type, sizeof(vl.type));
92   sstrncpy(vl.type_instance, data->type_instance, sizeof(vl.type_instance));
93
94   vl.interval = data->interval;
95   plugin_dispatch_values(&vl);
96
97   if (match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) {
98     match_value->value.gauge = NAN;
99     match_value->values_num = 0;
100   }
101
102   return (0);
103 } /* int simple_submit_match */
104
105 static int tail_callback(void *data, char *buf,
106                          int __attribute__((unused)) buflen) {
107   cu_tail_match_t *obj = (cu_tail_match_t *)data;
108
109   for (size_t i = 0; i < obj->matches_num; i++)
110     match_apply(obj->matches[i].match, buf);
111
112   return (0);
113 } /* int tail_callback */
114
115 /*
116  * Public functions
117  */
118 cu_tail_match_t *tail_match_create(const char *filename) {
119   cu_tail_match_t *obj;
120
121   obj = calloc(1, sizeof(*obj));
122   if (obj == NULL)
123     return (NULL);
124
125   obj->tail = cu_tail_create(filename);
126   if (obj->tail == NULL) {
127     sfree(obj);
128     return (NULL);
129   }
130
131   return (obj);
132 } /* cu_tail_match_t *tail_match_create */
133
134 void tail_match_destroy(cu_tail_match_t *obj) {
135   if (obj == NULL)
136     return;
137
138   if (obj->tail != NULL) {
139     cu_tail_destroy(obj->tail);
140     obj->tail = NULL;
141   }
142
143   for (size_t i = 0; i < obj->matches_num; i++) {
144     cu_tail_match_match_t *match = obj->matches + i;
145     if (match->match != NULL) {
146       match_destroy(match->match);
147       match->match = NULL;
148     }
149
150     if ((match->user_data != NULL) && (match->free != NULL))
151       (*match->free)(match->user_data);
152     match->user_data = NULL;
153   }
154
155   sfree(obj->matches);
156   sfree(obj);
157 } /* void tail_match_destroy */
158
159 int tail_match_add_match(cu_tail_match_t *obj, cu_match_t *match,
160                          int (*submit_match)(cu_match_t *match,
161                                              void *user_data),
162                          void *user_data,
163                          void (*free_user_data)(void *user_data)) {
164   cu_tail_match_match_t *temp;
165
166   temp = realloc(obj->matches,
167                  sizeof(cu_tail_match_match_t) * (obj->matches_num + 1));
168   if (temp == NULL)
169     return (-1);
170
171   obj->matches = temp;
172   obj->matches_num++;
173
174   DEBUG("tail_match_add_match interval %lf",
175         CDTIME_T_TO_DOUBLE(((cu_tail_match_simple_t *)user_data)->interval));
176   temp = obj->matches + (obj->matches_num - 1);
177
178   temp->match = match;
179   temp->user_data = user_data;
180   temp->submit = submit_match;
181   temp->free = free_user_data;
182
183   return (0);
184 } /* int tail_match_add_match */
185
186 int tail_match_add_match_simple(cu_tail_match_t *obj, const char *regex,
187                                 const char *excluderegex, int ds_type,
188                                 const char *plugin, const char *plugin_instance,
189                                 const char *type, const char *type_instance,
190                                 const cdtime_t interval) {
191   cu_match_t *match;
192   cu_tail_match_simple_t *user_data;
193   int status;
194
195   match = match_create_simple(regex, excluderegex, ds_type);
196   if (match == NULL)
197     return (-1);
198
199   user_data = calloc(1, sizeof(*user_data));
200   if (user_data == NULL) {
201     match_destroy(match);
202     return (-1);
203   }
204
205   sstrncpy(user_data->plugin, plugin, sizeof(user_data->plugin));
206   if (plugin_instance != NULL)
207     sstrncpy(user_data->plugin_instance, plugin_instance,
208              sizeof(user_data->plugin_instance));
209
210   sstrncpy(user_data->type, type, sizeof(user_data->type));
211   if (type_instance != NULL)
212     sstrncpy(user_data->type_instance, type_instance,
213              sizeof(user_data->type_instance));
214
215   user_data->interval = interval;
216
217   status =
218       tail_match_add_match(obj, match, simple_submit_match, user_data, free);
219
220   if (status != 0) {
221     match_destroy(match);
222     sfree(user_data);
223   }
224
225   return (status);
226 } /* int tail_match_add_match_simple */
227
228 int tail_match_read(cu_tail_match_t *obj) {
229   char buffer[4096];
230   int status;
231
232   status = cu_tail_read(obj->tail, buffer, sizeof(buffer), tail_callback,
233                         (void *)obj);
234   if (status != 0) {
235     ERROR("tail_match: cu_tail_read failed.");
236     return (status);
237   }
238
239   for (size_t i = 0; i < obj->matches_num; i++) {
240     cu_tail_match_match_t *lt_match = obj->matches + i;
241
242     if (lt_match->submit == NULL)
243       continue;
244
245     (*lt_match->submit)(lt_match->match, lt_match->user_data);
246   }
247
248   return (0);
249 } /* int tail_match_read */
250
251 /* vim: set sw=2 sts=2 ts=8 : */