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