87754e185b73ee35a01ff9a46cce262d19cde4e4
[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 #include "utils_latency_config.h"
40
41 struct cu_tail_match_simple_s
42 {
43   char plugin[DATA_MAX_NAME_LEN];
44   char plugin_instance[DATA_MAX_NAME_LEN];
45   char type[DATA_MAX_NAME_LEN];
46   char type_instance[DATA_MAX_NAME_LEN];
47   cdtime_t interval;
48   latency_config_t latency_config;
49 };
50 typedef struct cu_tail_match_simple_s cu_tail_match_simple_t;
51
52 struct cu_tail_match_match_s
53 {
54   cu_match_t *match;
55   void *user_data;
56   int (*submit) (cu_match_t *match, void *user_data);
57   void (*free) (void *user_data);
58 };
59 typedef struct cu_tail_match_match_s cu_tail_match_match_t;
60
61 struct cu_tail_match_s
62 {
63   int flags;
64   cu_tail_t *tail;
65
66   cdtime_t interval;
67   cu_tail_match_match_t *matches;
68   size_t matches_num;
69 };
70
71 /*
72  * Private functions
73  */
74 static int simple_submit_match (cu_match_t *match, void *user_data)
75 {
76   cu_tail_match_simple_t *data = (cu_tail_match_simple_t *) user_data;
77   cu_match_value_t *match_value;
78   value_list_t vl = VALUE_LIST_INIT;
79   value_t values[1];
80
81   match_value = (cu_match_value_t *) match_get_user_data (match);
82   if (match_value == NULL)
83     return (-1);
84
85   if ((match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
86       && (match_value->values_num == 0))
87     values[0].gauge = NAN;
88   else
89     values[0] = match_value->value;
90
91   vl.values = values;
92   vl.values_len = 1;
93   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
94   sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
95   sstrncpy (vl.plugin_instance, data->plugin_instance,
96       sizeof (vl.plugin_instance));
97   sstrncpy (vl.type, data->type, sizeof (vl.type));
98   sstrncpy (vl.type_instance, data->type_instance,
99       sizeof (vl.type_instance));
100
101   vl.interval = data->interval;
102   plugin_dispatch_values (&vl);
103
104   if (match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
105   {
106     match_value->value.gauge = NAN;
107     match_value->values_num = 0;
108   }
109
110   return (0);
111 } /* int simple_submit_match */
112
113 static int simple_submit_latency (cu_match_t *match, void *user_data)
114 {
115   cu_tail_match_simple_t *data = (cu_tail_match_simple_t *) user_data;
116   cu_match_value_t *match_value;
117   value_list_t vl = VALUE_LIST_INIT;
118   value_t values[1];
119
120   match_value = (cu_match_value_t *) match_get_user_data (match);
121   if (match_value == NULL)
122     return (-1);
123
124   vl.values = values;
125   vl.values_len = 1;
126   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
127   sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
128   sstrncpy (vl.plugin_instance, data->plugin_instance,
129       sizeof (vl.plugin_instance));
130   sstrncpy (vl.type, data->type, sizeof (vl.type));
131   vl.interval = data->interval;
132   vl.time = cdtime ();
133
134   if (data->latency_config.lower) {
135     ssnprintf (vl.type_instance, sizeof (vl.type_instance),
136         "lower");
137     values[0].gauge = (match_value->values_num != 0)
138       ? CDTIME_T_TO_DOUBLE (latency_counter_get_min (match_value->latency))
139       : NAN;
140     plugin_dispatch_values (&vl);
141   }
142
143   if (data->latency_config.avg) {
144     ssnprintf (vl.type_instance, sizeof (vl.type_instance),
145         "average");
146     values[0].gauge = (match_value->values_num != 0)
147       ? CDTIME_T_TO_DOUBLE (latency_counter_get_average (match_value->latency))
148       : NAN;
149     plugin_dispatch_values (&vl);
150   }
151
152   if (data->latency_config.upper) {
153     ssnprintf (vl.type_instance, sizeof (vl.type_instance),
154         "upper");
155     values[0].gauge = (match_value->values_num != 0)
156       ? CDTIME_T_TO_DOUBLE (latency_counter_get_max (match_value->latency))
157       : NAN;
158     plugin_dispatch_values (&vl);
159   }
160
161   size_t i;
162   /* Submit percentiles */
163   if (data->latency_config.percentile_type != NULL)
164     sstrncpy (vl.type, data->latency_config.percentile_type, sizeof (vl.type));
165   for (i = 0; i < data->latency_config.percentile_num; i++)
166   {
167     ssnprintf (vl.type_instance, sizeof (vl.type_instance),
168         "percentile-%.0f",  data->latency_config.percentile[i]);
169     values[0].gauge = (match_value->values_num != 0)
170       ? CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (match_value->latency,
171                                             data->latency_config.percentile[i]))
172       : NAN;
173     plugin_dispatch_values (&vl);
174   }
175
176   /* Submit rates */
177   sstrncpy (vl.type, data->type, sizeof (vl.type));
178   if (data->latency_config.rates_type != NULL)
179     sstrncpy (vl.type, data->latency_config.rates_type, sizeof (vl.type));
180   for (i = 0; i < data->latency_config.rates_num; i++)
181   {
182     ssnprintf (vl.type_instance, sizeof (vl.type_instance),
183         "rate-%.3f-%.3f",
184         CDTIME_T_TO_DOUBLE(data->latency_config.rates[i * 2]),
185         CDTIME_T_TO_DOUBLE(data->latency_config.rates[i * 2 + 1]));
186     values[0].gauge = (match_value->values_num != 0) 
187       ? latency_counter_get_rate (match_value->latency,
188                                   data->latency_config.rates[i * 2],
189                                   data->latency_config.rates[i * 2 + 1],
190                                   vl.time)
191       : NAN;
192     plugin_dispatch_values (&vl);
193   }
194   latency_counter_reset (match_value->latency);
195
196   match_value->value.gauge = NAN;
197   match_value->values_num = 0;
198
199   return (0);
200 } /* int simple_submit_latency */
201
202 static int tail_callback (void *data, char *buf,
203     int __attribute__((unused)) buflen)
204 {
205   cu_tail_match_t *obj = (cu_tail_match_t *) data;
206
207   for (size_t i = 0; i < obj->matches_num; i++)
208     match_apply (obj->matches[i].match, buf);
209
210   return (0);
211 } /* int tail_callback */
212
213 static void tail_match_simple_free (void *data)
214 {
215   cu_tail_match_simple_t *user_data = (cu_tail_match_simple_t *) data;
216   latency_config_free(user_data->latency_config);
217   sfree (user_data);
218 } /* void tail_match_simple_free */
219
220 /*
221  * Public functions
222  */
223 cu_tail_match_t *tail_match_create (const char *filename)
224 {
225   cu_tail_match_t *obj;
226
227   obj = calloc (1, sizeof (*obj));
228   if (obj == NULL)
229     return (NULL);
230
231   obj->tail = cu_tail_create (filename);
232   if (obj->tail == NULL)
233   {
234     sfree (obj);
235     return (NULL);
236   }
237
238   return (obj);
239 } /* cu_tail_match_t *tail_match_create */
240
241 void tail_match_destroy (cu_tail_match_t *obj)
242 {
243   if (obj == NULL)
244     return;
245
246   if (obj->tail != NULL)
247   {
248     cu_tail_destroy (obj->tail);
249     obj->tail = NULL;
250   }
251
252   for (size_t i = 0; i < obj->matches_num; i++)
253   {
254     cu_tail_match_match_t *match = obj->matches + i;
255     if (match->match != NULL)
256     {
257       match_destroy (match->match);
258       match->match = NULL;
259     }
260
261     if ((match->user_data != NULL)
262         && (match->free != NULL))
263       (*match->free) (match->user_data);
264     match->user_data = NULL;
265   }
266
267   sfree (obj->matches);
268   sfree (obj);
269 } /* void tail_match_destroy */
270
271 int tail_match_add_match (cu_tail_match_t *obj, cu_match_t *match,
272     int (*submit_match) (cu_match_t *match, void *user_data),
273     void *user_data,
274     void (*free_user_data) (void *user_data))
275 {
276   cu_tail_match_match_t *temp;
277
278   temp = realloc (obj->matches,
279       sizeof (cu_tail_match_match_t) * (obj->matches_num + 1));
280   if (temp == NULL)
281     return (-1);
282
283   obj->matches = temp;
284   obj->matches_num++;
285
286   DEBUG ("tail_match_add_match interval %lf", CDTIME_T_TO_DOUBLE(((cu_tail_match_simple_t *)user_data)->interval));
287   temp = obj->matches + (obj->matches_num - 1);
288
289   temp->match = match;
290   temp->user_data = user_data;
291   temp->submit = submit_match;
292   temp->free = free_user_data;
293
294   return (0);
295 } /* int tail_match_add_match */
296
297 int tail_match_add_match_simple (cu_tail_match_t *obj,
298     const char *regex, const char *excluderegex, int ds_type,
299     const char *plugin, const char *plugin_instance,
300     const char *type, const char *type_instance,
301     const latency_config_t latency_cfg,
302     const cdtime_t interval)
303 {
304   cu_match_t *match;
305   cu_tail_match_simple_t *user_data;
306   int status;
307
308   match = match_create_simple (regex, excluderegex, ds_type);
309   if (match == NULL)
310     return (-1);
311
312   user_data = calloc (1, sizeof (*user_data));
313   if (user_data == NULL)
314   {
315     match_destroy (match);
316     return (-1);
317   }
318
319   sstrncpy (user_data->plugin, plugin, sizeof (user_data->plugin));
320   if (plugin_instance != NULL)
321     sstrncpy (user_data->plugin_instance, plugin_instance,
322         sizeof (user_data->plugin_instance));
323
324   sstrncpy (user_data->type, type, sizeof (user_data->type));
325   if (type_instance != NULL)
326     sstrncpy (user_data->type_instance, type_instance,
327         sizeof (user_data->type_instance));
328
329   user_data->interval = interval;
330
331   if ((ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
332       && (ds_type & UTILS_MATCH_CF_GAUGE_LATENCY))
333   {
334     status = latency_config_copy(&user_data->latency_config, latency_cfg);
335     if (status != 0)
336     {
337       ERROR ("tail_match_add_match_simple: latency_config_copy() failed.");
338       status = -1;
339       goto out;
340     }
341
342     status = tail_match_add_match (obj, match, simple_submit_latency,
343       user_data, tail_match_simple_free);
344   } else {
345     status = tail_match_add_match (obj, match, simple_submit_match,
346       user_data, free);
347   }
348
349 out:
350   if (status != 0)
351   {
352     tail_match_simple_free(user_data);
353     match_destroy (match);
354   }
355
356   return (status);
357 } /* int tail_match_add_match_simple */
358
359 int tail_match_read (cu_tail_match_t *obj)
360 {
361   char buffer[4096];
362   int status;
363
364   status = cu_tail_read (obj->tail, buffer, sizeof (buffer), tail_callback,
365       (void *) obj);
366   if (status != 0)
367   {
368     ERROR ("tail_match: cu_tail_read failed.");
369     return (status);
370   }
371
372   for (size_t i = 0; i < obj->matches_num; i++)
373   {
374     cu_tail_match_match_t *lt_match = obj->matches + i;
375
376     if (lt_match->submit == NULL)
377       continue;
378
379     (*lt_match->submit) (lt_match->match, lt_match->user_data);
380   }
381
382   return (0);
383 } /* int tail_match_read */
384
385 /* vim: set sw=2 sts=2 ts=8 : */