collection.conf: Add some more graphs.
[collection4.git] / graph_def.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #include "graph_def.h"
6 #include "graph.h"
7 #include "graph_config.h"
8 #include "common.h"
9 #include "oconfig.h"
10
11 #include <fcgiapp.h>
12 #include <fcgi_stdio.h>
13
14 /*
15  * Data structures
16  */
17 struct graph_def_s
18 {
19   graph_ident_t *select;
20
21   char *ds_name;
22   char *legend;
23   uint32_t color;
24   _Bool stack;
25   _Bool area;
26
27   graph_def_t *next;
28 };
29
30 /*
31  * Private functions
32  */
33 #define DEF_CONFIG_FIELD(field) \
34 static int def_config_##field (const oconfig_item_t *ci, graph_ident_t *ident) \
35 {                                                                              \
36   char *tmp = NULL;                                                            \
37   int status = graph_config_get_string (ci, &tmp);                             \
38   if (status != 0)                                                             \
39     return (status);                                                           \
40   ident_set_##field (ident, tmp);                                              \
41   free (tmp);                                                                  \
42   return (0);                                                                  \
43 } /* }}} int def_config_field */
44
45 DEF_CONFIG_FIELD (host);
46 DEF_CONFIG_FIELD (plugin);
47 DEF_CONFIG_FIELD (plugin_instance);
48 DEF_CONFIG_FIELD (type);
49 DEF_CONFIG_FIELD (type_instance);
50
51 #undef DEF_CONFIG_FIELD
52
53 static int def_config_color (const oconfig_item_t *ci, uint32_t *ret_color) /* {{{ */
54 {
55   char *tmp;
56   char *endptr;
57   uint32_t color;
58
59   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
60     return (EINVAL);
61
62   tmp = ci->values[0].value.string;
63
64   endptr = NULL;
65   errno = 0;
66   color = (uint32_t) strtoul (tmp, &endptr, /* base = */ 16);
67   if ((errno != 0) || (endptr == tmp) || (color > 0x00ffffff))
68     return (EINVAL);
69
70   *ret_color = color;
71
72   return (0);
73 } /* }}} int def_config_color */
74
75 static graph_def_t *def_config_get_obj (graph_config_t *cfg, /* {{{ */
76     const oconfig_item_t *ci)
77 {
78   graph_ident_t *ident;
79   char *ds_name = NULL;
80   graph_def_t *def;
81   int i;
82
83   ident = graph_get_selector (cfg);
84   if (ident == NULL)
85   {
86     fprintf (stderr, "def_config_get_obj: graph_get_selector failed");
87     return (NULL);
88   }
89
90   for (i = 0; i < ci->children_num; i++)
91   {
92     oconfig_item_t *child;
93
94 #define HANDLE_FIELD(name,field) \
95     else if (strcasecmp (name, child->key) == 0) \
96       def_config_##field (child, ident)
97
98     child = ci->children + i;
99     if (strcasecmp ("DSName", child->key) == 0)
100       graph_config_get_string (child, &ds_name);
101
102     HANDLE_FIELD ("Host", host);
103     HANDLE_FIELD ("Plugin", plugin);
104     HANDLE_FIELD ("PluginInstance", plugin_instance);
105     HANDLE_FIELD ("Type", type);
106     HANDLE_FIELD ("TypeInstance", type_instance);
107
108 #undef HANDLE_FIELD
109   }
110
111   def = def_create (cfg, ident, ds_name);
112   if (def == NULL)
113   {
114     fprintf (stderr, "def_config_get_obj: def_create failed\n");
115     ident_destroy (ident);
116     free (ds_name);
117     return (NULL);
118   }
119
120   ident_destroy (ident);
121   free (ds_name);
122
123   return (def);
124 } /* }}} graph_def_t *def_config_get_obj */
125
126 /*
127  * Public functions
128  */
129 graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident, /* {{{ */
130     const char *ds_name)
131 {
132   graph_ident_t *selector;
133   graph_def_t *ret;
134
135   if ((cfg == NULL) || (ident == NULL) || (ds_name == NULL))
136     return (NULL);
137
138   selector = graph_get_selector (cfg);
139   if (selector == NULL)
140     return (NULL);
141
142   ret = malloc (sizeof (*ret));
143   if (ret == NULL)
144   {
145     ident_destroy (selector);
146     return (NULL);
147   }
148   memset (ret, 0, sizeof (*ret));
149   ret->legend = NULL;
150
151   ret->ds_name = strdup (ds_name);
152   if (ret->ds_name == NULL)
153   {
154     ident_destroy (selector);
155     free (ret);
156     return (NULL);
157   }
158
159   ret->color = get_random_color ();
160   ret->next = NULL;
161
162   ret->select = ident_copy_with_selector (selector, ident,
163       IDENT_FLAG_REPLACE_ALL);
164   if (ret->select == NULL)
165   {
166     ident_destroy (selector);
167     free (ret->ds_name);
168     free (ret);
169     return (NULL);
170   }
171
172   ident_destroy (selector);
173   return (ret);
174 } /* }}} graph_def_t *def_create */
175
176 void def_destroy (graph_def_t *def) /* {{{ */
177 {
178   graph_def_t *next;
179
180   if (def == NULL)
181     return;
182
183   next = def->next;
184
185   ident_destroy (def->select);
186
187   free (def->ds_name);
188
189   free (def);
190
191   def_destroy (next);
192 } /* }}} void def_destroy */
193
194 int def_config (graph_config_t *cfg, const oconfig_item_t *ci) /* {{{ */
195 {
196   graph_def_t *def;
197   int i;
198
199   def = def_config_get_obj (cfg, ci);
200   if (def == NULL)
201     return (EINVAL);
202
203   for (i = 0; i < ci->children_num; i++)
204   {
205     oconfig_item_t *child;
206
207     child = ci->children + i;
208     if (strcasecmp ("Legend", child->key) == 0)
209       graph_config_get_string (child, &def->legend);
210     else if (strcasecmp ("Color", child->key) == 0)
211       def_config_color (child, &def->color);
212     else if (strcasecmp ("Stack", child->key) == 0)
213       graph_config_get_bool (child, &def->stack);
214     else if (strcasecmp ("Area", child->key) == 0)
215       graph_config_get_bool (child, &def->area);
216     else
217       fprintf (stderr, "def_config: Ignoring unknown config option \"%s\"",
218           child->key);
219   }
220
221   return (graph_add_def (cfg, def));
222 } /* }}} int def_config */
223
224 int def_append (graph_def_t *head, graph_def_t *def) /* {{{ */
225 {
226   graph_def_t *ptr;
227
228   if ((head == NULL) || (def == NULL))
229     return (EINVAL);
230
231   ptr = head;
232   while (ptr->next != NULL)
233     ptr = ptr->next;
234
235   ptr->next = def;
236
237   return (0);
238 } /* }}} int def_append */
239
240 graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident, /* {{{ */
241     const char *ds_name)
242 {
243   graph_def_t *ptr;
244
245   if ((head == NULL) || (ident == NULL) || (ds_name == NULL))
246     return (NULL);
247
248   for (ptr = head; ptr != NULL; ptr = ptr->next)
249   {
250     if (!ident_matches (ptr->select, ident))
251       continue;
252
253     if (strcmp (ptr->ds_name, ds_name) == 0)
254       return (ptr);
255   }
256
257   return (NULL);
258 } /* }}} graph_def_t *def_search */
259
260 _Bool def_matches (graph_def_t *def, graph_ident_t *ident) /* {{{ */
261 {
262   return (ident_matches (def->select, ident));
263 } /* }}} _Bool def_matches */
264
265 int def_foreach (graph_def_t *def, def_callback_t callback, /* {{{ */
266     void *user_data)
267 {
268   graph_def_t *ptr;
269
270   if ((def == NULL) || (callback == NULL))
271     return (EINVAL);
272
273   for (ptr = def; ptr != NULL; ptr = ptr->next)
274   {
275     int status;
276
277     status = (*callback) (ptr, user_data);
278     if (status != 0)
279       return (status);
280   }
281
282   return (0);
283 } /* }}} int def_foreach */
284
285 int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident, /* {{{ */
286     str_array_t *args)
287 {
288   char *file;
289   int index;
290
291   if ((def == NULL) || (ident == NULL) || (args == NULL))
292     return (EINVAL);
293
294   file = ident_to_file (ident);
295   if (file == NULL)
296   {
297     DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
298     return (-1);
299   }
300
301   DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
302
303   index = array_argc (args);
304
305   /* CDEFs */
306   array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
307       index, file, def->ds_name);
308   array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
309       index, file, def->ds_name);
310   array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
311       index, file, def->ds_name);
312   /* VDEFs */
313   array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
314       index, index);
315   array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
316       index, index);
317   array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
318       index, index);
319   array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
320       index, index);
321
322   /* Graph part */
323   array_append_format (args, "%s:def_%04i_avg#%06"PRIx32":%s%s",
324       def->area ? "AREA" : "LINE1",
325       index, def->color,
326       (def->legend != NULL) ? def->legend : def->ds_name,
327       def->stack ? ":STACK" : "");
328   array_append_format (args, "GPRINT:vdef_%04i_min:%%lg min,", index);
329   array_append_format (args, "GPRINT:vdef_%04i_avg:%%lg avg,", index);
330   array_append_format (args, "GPRINT:vdef_%04i_max:%%lg max,", index);
331   array_append_format (args, "GPRINT:vdef_%04i_lst:%%lg last\\l", index);
332
333   free (file);
334
335   return (0);
336 } /* }}} int def_get_rrdargs */
337
338 /* vim: set sw=2 sts=2 et fdm=marker : */