Merge branch 'collectd-4.5'
[collectd.git] / src / match_value.c
1 /**
2  * collectd - src/match_value.c
3  * Copyright (C) 2008  Florian Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian Forster <octo at verplant.org>
20  **/
21
22 /*
23  * This module allows to filter and rewrite value lists based on
24  * Perl-compatible regular expressions.
25  */
26
27 #include "collectd.h"
28 #include "utils_cache.h"
29 #include "filter_chain.h"
30
31 /*
32  * private data types
33  */
34 struct mv_match_s;
35 typedef struct mv_match_s mv_match_t;
36 struct mv_match_s
37 {
38   gauge_t min;
39   gauge_t max;
40   int invert;
41 };
42
43 /*
44  * internal helper functions
45  */
46 static void mv_free_match (mv_match_t *m) /* {{{ */
47 {
48   if (m == NULL)
49     return;
50
51   free (m);
52 } /* }}} void mv_free_match */
53
54 static int mv_config_add_gauge (gauge_t *ret_value, /* {{{ */
55     oconfig_item_t *ci)
56 {
57
58   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
59   {
60     ERROR ("`value' match: `%s' needs exactly one numeric argument.",
61         ci->key);
62     return (-1);
63   }
64
65   *ret_value = ci->values[0].value.number;
66
67   return (0);
68 } /* }}} int mv_config_add_gauge */
69
70 static int mv_config_add_boolean (int *ret_value, /* {{{ */
71     oconfig_item_t *ci)
72 {
73
74   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
75   {
76     ERROR ("`value' match: `%s' needs exactly one boolean argument.",
77         ci->key);
78     return (-1);
79   }
80
81   if (ci->values[0].value.boolean)
82     *ret_value = 1;
83   else
84     *ret_value = 0;
85
86   return (0);
87 } /* }}} int mv_config_add_boolean */
88
89 static int mv_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
90 {
91   mv_match_t *m;
92   int status;
93   int i;
94
95   m = (mv_match_t *) malloc (sizeof (*m));
96   if (m == NULL)
97   {
98     ERROR ("mv_create: malloc failed.");
99     return (-ENOMEM);
100   }
101   memset (m, 0, sizeof (*m));
102
103   m->min = NAN;
104   m->max = NAN;
105   m->invert = 0;
106
107   status = 0;
108   for (i = 0; i < ci->children_num; i++)
109   {
110     oconfig_item_t *child = ci->children + i;
111
112     if (strcasecmp ("Min", child->key) == 0)
113       status = mv_config_add_gauge (&m->min, child);
114     else if (strcasecmp ("Max", child->key) == 0)
115       status = mv_config_add_gauge (&m->max, child);
116     else if (strcasecmp ("Invert", child->key) == 0)
117       status = mv_config_add_boolean (&m->invert, child);
118     else
119     {
120       ERROR ("`value' match: The `%s' configuration option is not "
121           "understood and will be ignored.", child->key);
122       status = 0;
123     }
124
125     if (status != 0)
126       break;
127   }
128
129   /* Additional sanity-checking */
130   while (status == 0)
131   {
132     if (isnan (m->min) && isnan (m->max))
133     {
134       ERROR ("`value' match: Neither minimum nor maximum are defined. "
135           "This match will be ignored.");
136       status = -1;
137     }
138
139     break;
140   }
141
142   if (status != 0)
143   {
144     mv_free_match (m);
145     return (status);
146   }
147
148   *user_data = m;
149   return (0);
150 } /* }}} int mv_create */
151
152 static int mv_destroy (void **user_data) /* {{{ */
153 {
154   if ((user_data != NULL) && (*user_data != NULL))
155     mv_free_match (*user_data);
156   return (0);
157 } /* }}} int mv_destroy */
158
159 static int mv_match (const data_set_t *ds, const value_list_t *vl, /* {{{ */
160     notification_meta_t **meta, void **user_data)
161 {
162   mv_match_t *m;
163   gauge_t *values;
164   int status;
165   int i;
166
167   if ((user_data == NULL) || (*user_data == NULL))
168     return (-1);
169
170   m = *user_data;
171
172   values = uc_get_rate (ds, vl);
173   if (values == NULL)
174   {
175     ERROR ("`value' match: Retrieving the current rate from the cache "
176         "failed.");
177     return (-1);
178   }
179
180   status = FC_MATCH_MATCHES;
181   for (i = 0; i < ds->ds_num; i++)
182   {
183     DEBUG ("`value' match: current = %g; min = %g; max = %g; invert = %s;",
184         values[i], m->min, m->max,
185         m->invert ? "true" : "false");
186
187     if ((!isnan (m->min) && (values[i] < m->min))
188         || (!isnan (m->max) && (values[i] > m->max)))
189     {
190       status = FC_MATCH_NO_MATCH;
191       break;
192     }
193   }
194
195   if (m->invert)
196   {
197     if (status == FC_MATCH_MATCHES)
198       status = FC_MATCH_NO_MATCH;
199     else
200       status = FC_MATCH_MATCHES;
201   }
202
203   free (values);
204   return (status);
205 } /* }}} int mv_match */
206
207 void module_register (void)
208 {
209   match_proc_t mproc;
210
211   memset (&mproc, 0, sizeof (mproc));
212   mproc.create  = mv_create;
213   mproc.destroy = mv_destroy;
214   mproc.match   = mv_match;
215   fc_register_match ("value", mproc);
216 } /* module_register */
217
218 /* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
219