Code

utils_ignorelist.c: remove useless assignment
[collectd.git] / src / target_scale.c
1 /**
2  * collectd - src/target_scale.c
3  * Copyright (C) 2008-2009  Florian Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian Forster <octo at collectd.org>
25  **/
27 #include "collectd.h"
28 #include "common.h"
29 #include "filter_chain.h"
31 #include "utils_cache.h"
33 struct ts_data_s
34 {
35         double factor;
36         double offset;
38         char **data_sources;
39         size_t data_sources_num;
40 };
41 typedef struct ts_data_s ts_data_t;
43 static int ts_invoke_counter (const data_set_t *ds, value_list_t *vl, /* {{{ */
44                 ts_data_t *data, int dsrc_index)
45 {
46         uint64_t curr_counter;
47         int status;
48         int failure;
50         /* Required meta data */
51         uint64_t prev_counter;
52         char key_prev_counter[128];
53         uint64_t int_counter;
54         char key_int_counter[128];
55         double int_fraction;
56         char key_int_fraction[128];
58         curr_counter = (uint64_t) vl->values[dsrc_index].counter;
60         ssnprintf (key_prev_counter, sizeof (key_prev_counter),
61                         "target_scale[%p,%i]:prev_counter",
62                         (void *) data, dsrc_index);
63         ssnprintf (key_int_counter, sizeof (key_int_counter),
64                         "target_scale[%p,%i]:int_counter",
65                         (void *) data, dsrc_index);
66         ssnprintf (key_int_fraction, sizeof (key_int_fraction),
67                         "target_scale[%p,%i]:int_fraction",
68                         (void *) data, dsrc_index);
70         prev_counter = curr_counter;
71         int_counter = 0;
72         int_fraction = 0.0;
74         /* Query the meta data */
75         failure = 0;
77         status = uc_meta_data_get_unsigned_int (vl, key_prev_counter,
78                         &prev_counter);
79         if (status != 0)
80                 failure++;
82         status = uc_meta_data_get_unsigned_int (vl, key_int_counter, &int_counter);
83         if (status != 0)
84                 failure++;
86         status = uc_meta_data_get_double (vl, key_int_fraction, &int_fraction);
87         if (status != 0)
88                 failure++;
90         if (failure == 0)
91         {
92                 uint64_t diff;
93                 double rate;
95                 diff = (uint64_t) counter_diff (prev_counter, curr_counter);
96                 rate = ((double) diff) / CDTIME_T_TO_DOUBLE (vl->interval);
98                 /* Modify the rate. */
99                 if (!isnan (data->factor))
100                         rate *= data->factor;
101                 if (!isnan (data->offset))
102                         rate += data->offset;
104                 /* Calculate the internal counter. */
105                 int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
106                 diff = (uint64_t) int_fraction;
107                 int_fraction -= ((double) diff);
108                 int_counter  += diff;
110                 assert (int_fraction >= 0.0);
111                 assert (int_fraction <  1.0);
113                 DEBUG ("Target `scale': ts_invoke_counter: %"PRIu64" -> %g -> %"PRIu64
114                                 "(+%g)",
115                                 curr_counter, rate, int_counter, int_fraction);
116         }
117         else /* (failure != 0) */
118         {
119                 int_counter = 0;
120                 int_fraction = 0.0;
121         }
123         vl->values[dsrc_index].counter = (counter_t) int_counter;
125         /* Update to the new counter value */
126         uc_meta_data_add_unsigned_int (vl, key_prev_counter, curr_counter);
127         uc_meta_data_add_unsigned_int (vl, key_int_counter, int_counter);
128         uc_meta_data_add_double (vl, key_int_fraction, int_fraction);
131         return (0);
132 } /* }}} int ts_invoke_counter */
134 static int ts_invoke_gauge (const data_set_t *ds, value_list_t *vl, /* {{{ */
135                 ts_data_t *data, int dsrc_index)
137         if (!isnan (data->factor))
138                 vl->values[dsrc_index].gauge *= data->factor;
139         if (!isnan (data->offset))
140                 vl->values[dsrc_index].gauge += data->offset;
142         return (0);
143 } /* }}} int ts_invoke_gauge */
145 static int ts_invoke_derive (const data_set_t *ds, value_list_t *vl, /* {{{ */
146                 ts_data_t *data, int dsrc_index)
148         int64_t curr_derive;
149         int status;
150         int failure;
152         /* Required meta data */
153         int64_t prev_derive;
154         char key_prev_derive[128];
155         int64_t int_derive;
156         char key_int_derive[128];
157         double int_fraction;
158         char key_int_fraction[128];
160         curr_derive = (int64_t) vl->values[dsrc_index].derive;
162         ssnprintf (key_prev_derive, sizeof (key_prev_derive),
163                         "target_scale[%p,%i]:prev_derive",
164                         (void *) data, dsrc_index);
165         ssnprintf (key_int_derive, sizeof (key_int_derive),
166                         "target_scale[%p,%i]:int_derive",
167                         (void *) data, dsrc_index);
168         ssnprintf (key_int_fraction, sizeof (key_int_fraction),
169                         "target_scale[%p,%i]:int_fraction",
170                         (void *) data, dsrc_index);
172         prev_derive = curr_derive;
173         int_derive = 0;
174         int_fraction = 0.0;
176         /* Query the meta data */
177         failure = 0;
179         status = uc_meta_data_get_signed_int (vl, key_prev_derive,
180                         &prev_derive);
181         if (status != 0)
182                 failure++;
184         status = uc_meta_data_get_signed_int (vl, key_int_derive, &int_derive);
185         if (status != 0)
186                 failure++;
188         status = uc_meta_data_get_double (vl, key_int_fraction, &int_fraction);
189         if (status != 0)
190                 failure++;
192         if (failure == 0)
193         {
194                 int64_t difference;
195                 double rate;
197                 /* Calcualte the rate */
198                 difference = curr_derive - prev_derive;
199                 rate = ((double) difference) / CDTIME_T_TO_DOUBLE (vl->interval);
201                 /* Modify the rate. */
202                 if (!isnan (data->factor))
203                         rate *= data->factor;
204                 if (!isnan (data->offset))
205                         rate += data->offset;
207                 /* Calculate the internal derive. */
208                 int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
209                 if (int_fraction < 0.0) /* handle negative integer rounding correctly */
210                         difference = ((int64_t) int_fraction) - 1;
211                 else
212                         difference = (int64_t) int_fraction;
213                 int_fraction -= ((double) difference);
214                 int_derive  += difference;
216                 assert (int_fraction >= 0.0);
217                 assert (int_fraction <  1.0);
219                 DEBUG ("Target `scale': ts_invoke_derive: %"PRIu64" -> %g -> %"PRIu64
220                                 "(+%g)",
221                                 curr_derive, rate, int_derive, int_fraction);
222         }
223         else /* (failure != 0) */
224         {
225                 int_derive = 0;
226                 int_fraction = 0.0;
227         }
229         vl->values[dsrc_index].derive = (derive_t) int_derive;
231         /* Update to the new derive value */
232         uc_meta_data_add_signed_int (vl, key_prev_derive, curr_derive);
233         uc_meta_data_add_signed_int (vl, key_int_derive, int_derive);
234         uc_meta_data_add_double (vl, key_int_fraction, int_fraction);
236         return (0);
237 } /* }}} int ts_invoke_derive */
239 static int ts_invoke_absolute (const data_set_t *ds, value_list_t *vl, /* {{{ */
240                 ts_data_t *data, int dsrc_index)
242         uint64_t curr_absolute;
243         double rate;
244         int status;
246         /* Required meta data */
247         double int_fraction;
248         char key_int_fraction[128];
250         curr_absolute = (uint64_t) vl->values[dsrc_index].absolute;
252         ssnprintf (key_int_fraction, sizeof (key_int_fraction),
253                         "target_scale[%p,%i]:int_fraction",
254                         (void *) data, dsrc_index);
256         int_fraction = 0.0;
258         /* Query the meta data */
259         status = uc_meta_data_get_double (vl, key_int_fraction, &int_fraction);
260         if (status != 0)
261                 int_fraction = 0.0;
263         rate = ((double) curr_absolute) / CDTIME_T_TO_DOUBLE (vl->interval);
265         /* Modify the rate. */
266         if (!isnan (data->factor))
267                 rate *= data->factor;
268         if (!isnan (data->offset))
269                 rate += data->offset;
271         /* Calculate the new absolute. */
272         int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
273         curr_absolute = (uint64_t) int_fraction;
274         int_fraction -= ((double) curr_absolute);
276         vl->values[dsrc_index].absolute = (absolute_t) curr_absolute;
278         /* Update to the new absolute value */
279         uc_meta_data_add_double (vl, key_int_fraction, int_fraction);
281         return (0);
282 } /* }}} int ts_invoke_absolute */
284 static int ts_config_set_double (double *ret, oconfig_item_t *ci) /* {{{ */
286         if ((ci->values_num != 1)
287                         || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
288         {
289                 WARNING ("scale target: The `%s' config option needs "
290                                 "exactly one numeric argument.", ci->key);
291                 return (-1);
292         }
294         *ret = ci->values[0].value.number;
295         DEBUG ("ts_config_set_double: *ret = %g", *ret);
297         return (0);
298 } /* }}} int ts_config_set_double */
300 static int ts_config_add_data_source(ts_data_t *data, /* {{{ */
301                 oconfig_item_t *ci)
303         size_t new_data_sources_num;
304         char **temp;
305         int i;
307         /* Check number of arbuments. */
308         if (ci->values_num < 1)
309         {
310                 ERROR ("`value' match: `%s' needs at least one argument.",
311                                 ci->key);
312                 return (-1);
313         }
315         /* Check type of arguments */
316         for (i = 0; i < ci->values_num; i++)
317         {
318                 if (ci->values[i].type == OCONFIG_TYPE_STRING)
319                         continue;
321                 ERROR ("`value' match: `%s' accepts only string arguments "
322                                 "(argument %i is a %s).",
323                                 ci->key, i + 1,
324                                 (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
325                                 ? "truth value" : "number");
326                 return (-1);
327         }
329         /* Allocate space for the char pointers */
330         new_data_sources_num = data->data_sources_num + ((size_t) ci->values_num);
331         temp = (char **) realloc (data->data_sources,
332                         new_data_sources_num * sizeof (char *));
333         if (temp == NULL)
334         {
335                 ERROR ("`value' match: realloc failed.");
336                 return (-1);
337         }
338         data->data_sources = temp;
340         /* Copy the strings, allocating memory as needed.  */
341         for (i = 0; i < ci->values_num; i++)
342         {
343                 size_t j;
345                 /* If we get here, there better be memory for us to write to.  */
346                 assert (data->data_sources_num < new_data_sources_num);
348                 j = data->data_sources_num;
349                 data->data_sources[j] = sstrdup (ci->values[i].value.string);
350                 if (data->data_sources[j] == NULL)
351                 {
352                         ERROR ("`value' match: sstrdup failed.");
353                         continue;
354                 }
355                 data->data_sources_num++;
356         }
358         return (0);
359 } /* }}} int ts_config_add_data_source */
361 static int ts_destroy (void **user_data) /* {{{ */
363         ts_data_t *data;
365         if (user_data == NULL)
366                 return (-EINVAL);
368         data = (ts_data_t *) *user_data;
370         if ((data != NULL) && (data->data_sources != NULL))
371         {
372                 size_t i;
373                 for (i = 0; i < data->data_sources_num; i++)
374                         sfree (data->data_sources[i]);
375                 sfree (data->data_sources);
376         }
378         sfree (data);
379         *user_data = NULL;
381         return (0);
382 } /* }}} int ts_destroy */
384 static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
386         ts_data_t *data;
387         int status;
388         int i;
390         data = calloc (1, sizeof (*data));
391         if (data == NULL)
392         {
393                 ERROR ("ts_create: calloc failed.");
394                 return (-ENOMEM);
395         }
397         data->factor = NAN;
398         data->offset = NAN;
400         status = 0;
401         for (i = 0; i < ci->children_num; i++)
402         {
403                 oconfig_item_t *child = ci->children + i;
405                 if (strcasecmp ("Factor", child->key) == 0)
406                                 status = ts_config_set_double (&data->factor, child);
407                 else if (strcasecmp ("Offset", child->key) == 0)
408                                 status = ts_config_set_double (&data->offset, child);
409                 else if (strcasecmp ("DataSource", child->key) == 0)
410                                 status = ts_config_add_data_source(data, child);
411                 else
412                 {
413                         ERROR ("Target `scale': The `%s' configuration option is not understood "
414                                         "and will be ignored.", child->key);
415                         status = 0;
416                 }
418                 if (status != 0)
419                         break;
420         }
422         /* Additional sanity-checking */
423         while (status == 0)
424         {
425                 if (isnan (data->factor) && isnan (data->offset))
426                 {
427                         ERROR ("Target `scale': You need to at least set either the `Factor' "
428                                         "or `Offset' option!");
429                         status = -1;
430                 }
432                 break;
433         }
435         if (status != 0)
436         {
437                 ts_destroy ((void *) &data);
438                 return (status);
439         }
441         *user_data = data;
442         return (0);
443 } /* }}} int ts_create */
445 static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
446                 notification_meta_t __attribute__((unused)) **meta, void **user_data)
448         ts_data_t *data;
449         size_t i;
451         if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
452                 return (-EINVAL);
454         data = *user_data;
455         if (data == NULL)
456         {
457                 ERROR ("Target `scale': Invoke: `data' is NULL.");
458                 return (-EINVAL);
459         }
461         for (i = 0; i < ds->ds_num; i++)
462         {
463                 /* If we've got a list of data sources, is it in the list? */
464                 if (data->data_sources) {
465                         size_t j;
466                         for (j = 0; j < data->data_sources_num; j++)
467                                 if (strcasecmp(ds->ds[i].name, data->data_sources[j]) == 0)
468                                         break;
470                         /* No match, ignore */
471                         if (j >= data->data_sources_num)
472                                 continue;
473                 }
475                 if (ds->ds[i].type == DS_TYPE_COUNTER)
476                         ts_invoke_counter (ds, vl, data, i);
477                 else if (ds->ds[i].type == DS_TYPE_GAUGE)
478                         ts_invoke_gauge (ds, vl, data, i);
479                 else if (ds->ds[i].type == DS_TYPE_DERIVE)
480                         ts_invoke_derive (ds, vl, data, i);
481                 else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
482                         ts_invoke_absolute (ds, vl, data, i);
483                 else
484                         ERROR ("Target `scale': Ignoring unknown data source type %i",
485                                         ds->ds[i].type);
486         }
488         return (FC_TARGET_CONTINUE);
489 } /* }}} int ts_invoke */
491 void module_register (void)
493         target_proc_t tproc;
495         memset (&tproc, 0, sizeof (tproc));
496         tproc.create  = ts_create;
497         tproc.destroy = ts_destroy;
498         tproc.invoke  = ts_invoke;
499         fc_register_target ("scale", tproc);
500 } /* module_register */
502 /* vim: set sw=2 ts=2 tw=78 fdm=marker : */