Merge branch 'collectd-5.7' into collectd-5.8
[collectd.git] / src / target_v5upgrade.c
1 /**
2  * collectd - src/target_v5upgrade.c
3  * Copyright (C) 2008-2010  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  **/
26
27 #include "collectd.h"
28
29 #include "common.h"
30 #include "filter_chain.h"
31 #include "plugin.h"
32
33 static void v5_swap_instances(value_list_t *vl) /* {{{ */
34 {
35   char tmp[DATA_MAX_NAME_LEN];
36
37   assert(sizeof(tmp) == sizeof(vl->plugin_instance));
38   assert(sizeof(tmp) == sizeof(vl->type_instance));
39
40   memcpy(tmp, vl->plugin_instance, sizeof(tmp));
41   memcpy(vl->plugin_instance, vl->type_instance, sizeof(tmp));
42   memcpy(vl->type_instance, tmp, sizeof(tmp));
43 } /* }}} void v5_swap_instances */
44
45 /*
46  * Df type
47  *
48  * By default, the "df" plugin of version 4.* uses the "df" type and puts the
49  * mount point in the type instance. Detect this behavior and convert the type
50  * to "df_complex". This can be selected in versions 4.9 and 4.10 by setting
51  * the "ReportReserved" option of the "df" plugin.
52  */
53 static int v5_df(const data_set_t *ds, value_list_t *vl) /* {{{ */
54 {
55   value_list_t new_vl;
56
57   /* Can't upgrade if both instances have been set. */
58   if ((vl->plugin_instance[0] != 0) && (vl->type_instance[0] != 0))
59     return FC_TARGET_CONTINUE;
60
61   /* Copy everything: Time, interval, host, ... */
62   memcpy(&new_vl, vl, sizeof(new_vl));
63
64   /* Reset data we can't simply copy */
65   new_vl.values = &(value_t){.gauge = NAN};
66   new_vl.values_len = 1;
67   new_vl.meta = NULL;
68
69   /* Move the mount point name to the plugin instance */
70   if (new_vl.plugin_instance[0] == 0)
71     v5_swap_instances(&new_vl);
72
73   /* Change the type to "df_complex" */
74   sstrncpy(new_vl.type, "df_complex", sizeof(new_vl.type));
75
76   /* Dispatch two new value lists instead of this one */
77   new_vl.values[0].gauge = vl->values[0].gauge;
78   sstrncpy(new_vl.type_instance, "used", sizeof(new_vl.type_instance));
79   plugin_dispatch_values(&new_vl);
80
81   new_vl.values[0].gauge = vl->values[1].gauge;
82   sstrncpy(new_vl.type_instance, "free", sizeof(new_vl.type_instance));
83   plugin_dispatch_values(&new_vl);
84
85   /* Abort processing */
86   return FC_TARGET_STOP;
87 } /* }}} int v5_df */
88
89 /*
90  * Interface plugin
91  *
92  * 4.* stores the interface in the type instance and leaves the plugin
93  * instance empty. If this is the case, put the interface name into the plugin
94  * instance and clear the type instance.
95  */
96 static int v5_interface(const data_set_t *ds, value_list_t *vl) /* {{{ */
97 {
98   if ((vl->plugin_instance[0] != 0) || (vl->type_instance[0] == 0))
99     return FC_TARGET_CONTINUE;
100
101   v5_swap_instances(vl);
102   return FC_TARGET_CONTINUE;
103 } /* }}} int v5_interface */
104
105 /*
106  * MySQL query cache
107  *
108  * 4.* uses the "mysql_qcache" type which mixes different types of
109  * information. In 5.* this has been broken up.
110  */
111 static int v5_mysql_qcache(const data_set_t *ds, value_list_t *vl) /* {{{ */
112 {
113   value_list_t new_vl;
114
115   if (vl->values_len != 5)
116     return FC_TARGET_STOP;
117
118   /* Copy everything: Time, interval, host, ... */
119   memcpy(&new_vl, vl, sizeof(new_vl));
120
121   /* Reset data we can't simply copy */
122   new_vl.values = &(value_t){.gauge = NAN};
123   new_vl.values_len = 1;
124   new_vl.meta = NULL;
125
126   /* Change the type to "cache_result" */
127   sstrncpy(new_vl.type, "cache_result", sizeof(new_vl.type));
128
129   /* Dispatch new value lists instead of this one */
130   new_vl.values[0].derive = (derive_t)vl->values[0].counter;
131   sstrncpy(new_vl.type_instance, "qcache-hits", sizeof(new_vl.type_instance));
132   plugin_dispatch_values(&new_vl);
133
134   new_vl.values[0].derive = (derive_t)vl->values[1].counter;
135   sstrncpy(new_vl.type_instance, "qcache-inserts",
136            sizeof(new_vl.type_instance));
137   plugin_dispatch_values(&new_vl);
138
139   new_vl.values[0].derive = (derive_t)vl->values[2].counter;
140   sstrncpy(new_vl.type_instance, "qcache-not_cached",
141            sizeof(new_vl.type_instance));
142   plugin_dispatch_values(&new_vl);
143
144   new_vl.values[0].derive = (derive_t)vl->values[3].counter;
145   sstrncpy(new_vl.type_instance, "qcache-prunes", sizeof(new_vl.type_instance));
146   plugin_dispatch_values(&new_vl);
147
148   /* The last data source is a gauge value, so we have to use a different type
149    * here. */
150   new_vl.values[0].gauge = vl->values[4].gauge;
151   sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type));
152   sstrncpy(new_vl.type_instance, "qcache", sizeof(new_vl.type_instance));
153   plugin_dispatch_values(&new_vl);
154
155   /* Abort processing */
156   return FC_TARGET_STOP;
157 } /* }}} int v5_mysql_qcache */
158
159 /*
160  * MySQL thread count
161  *
162  * 4.* uses the "mysql_threads" type which mixes different types of
163  * information. In 5.* this has been broken up.
164  */
165 static int v5_mysql_threads(const data_set_t *ds, value_list_t *vl) /* {{{ */
166 {
167   value_list_t new_vl;
168
169   if (vl->values_len != 4)
170     return FC_TARGET_STOP;
171
172   /* Copy everything: Time, interval, host, ... */
173   memcpy(&new_vl, vl, sizeof(new_vl));
174
175   /* Reset data we can't simply copy */
176   new_vl.values = &(value_t){.gauge = NAN};
177   new_vl.values_len = 1;
178   new_vl.meta = NULL;
179
180   /* Change the type to "threads" */
181   sstrncpy(new_vl.type, "threads", sizeof(new_vl.type));
182
183   /* Dispatch new value lists instead of this one */
184   new_vl.values[0].gauge = vl->values[0].gauge;
185   sstrncpy(new_vl.type_instance, "running", sizeof(new_vl.type_instance));
186   plugin_dispatch_values(&new_vl);
187
188   new_vl.values[0].gauge = vl->values[1].gauge;
189   sstrncpy(new_vl.type_instance, "connected", sizeof(new_vl.type_instance));
190   plugin_dispatch_values(&new_vl);
191
192   new_vl.values[0].gauge = vl->values[2].gauge;
193   sstrncpy(new_vl.type_instance, "cached", sizeof(new_vl.type_instance));
194   plugin_dispatch_values(&new_vl);
195
196   /* The last data source is a counter value, so we have to use a different
197    * type here. */
198   new_vl.values[0].derive = (derive_t)vl->values[3].counter;
199   sstrncpy(new_vl.type, "total_threads", sizeof(new_vl.type));
200   sstrncpy(new_vl.type_instance, "created", sizeof(new_vl.type_instance));
201   plugin_dispatch_values(&new_vl);
202
203   /* Abort processing */
204   return FC_TARGET_STOP;
205 } /* }}} int v5_mysql_threads */
206
207 /*
208  * ZFS ARC hit and miss counters
209  *
210  * 4.* uses the flawed "arc_counts" type. In 5.* this has been replaced by the
211  * more generic "cache_result" type.
212  */
213 static int v5_zfs_arc_counts(const data_set_t *ds, value_list_t *vl) /* {{{ */
214 {
215   value_list_t new_vl;
216   _Bool is_hits;
217
218   if (vl->values_len != 4)
219     return FC_TARGET_STOP;
220
221   if (strcmp("hits", vl->type_instance) == 0)
222     is_hits = 1;
223   else if (strcmp("misses", vl->type_instance) == 0)
224     is_hits = 0;
225   else
226     return FC_TARGET_STOP;
227
228   /* Copy everything: Time, interval, host, ... */
229   memcpy(&new_vl, vl, sizeof(new_vl));
230
231   /* Reset data we can't simply copy */
232   new_vl.values = &(value_t){.gauge = NAN};
233   new_vl.values_len = 1;
234   new_vl.meta = NULL;
235
236   /* Change the type to "cache_result" */
237   sstrncpy(new_vl.type, "cache_result", sizeof(new_vl.type));
238
239   /* Dispatch new value lists instead of this one */
240   new_vl.values[0].derive = (derive_t)vl->values[0].counter;
241   snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "demand_data-%s",
242            is_hits ? "hit" : "miss");
243   plugin_dispatch_values(&new_vl);
244
245   new_vl.values[0].derive = (derive_t)vl->values[1].counter;
246   snprintf(new_vl.type_instance, sizeof(new_vl.type_instance),
247            "demand_metadata-%s", is_hits ? "hit" : "miss");
248   plugin_dispatch_values(&new_vl);
249
250   new_vl.values[0].derive = (derive_t)vl->values[2].counter;
251   snprintf(new_vl.type_instance, sizeof(new_vl.type_instance),
252            "prefetch_data-%s", is_hits ? "hit" : "miss");
253   plugin_dispatch_values(&new_vl);
254
255   new_vl.values[0].derive = (derive_t)vl->values[3].counter;
256   snprintf(new_vl.type_instance, sizeof(new_vl.type_instance),
257            "prefetch_metadata-%s", is_hits ? "hit" : "miss");
258   plugin_dispatch_values(&new_vl);
259
260   /* Abort processing */
261   return FC_TARGET_STOP;
262 } /* }}} int v5_zfs_arc_counts */
263
264 /*
265  * ZFS ARC L2 bytes
266  *
267  * "arc_l2_bytes" -> "io_octets-L2".
268  */
269 static int v5_zfs_arc_l2_bytes(const data_set_t *ds, value_list_t *vl) /* {{{ */
270 {
271   value_list_t new_vl;
272
273   if (vl->values_len != 2)
274     return FC_TARGET_STOP;
275
276   /* Copy everything: Time, interval, host, ... */
277   memcpy(&new_vl, vl, sizeof(new_vl));
278
279   /* Reset data we can't simply copy */
280   new_vl.meta = NULL;
281
282   /* Change the type/-instance to "io_octets-L2" */
283   sstrncpy(new_vl.type, "io_octets", sizeof(new_vl.type));
284   sstrncpy(new_vl.type_instance, "L2", sizeof(new_vl.type_instance));
285
286   /* Copy the actual values. */
287   value_t values[] = {
288       {.derive = (derive_t)vl->values[0].counter},
289       {.derive = (derive_t)vl->values[1].counter},
290   };
291   new_vl.values = values;
292   new_vl.values_len = STATIC_ARRAY_SIZE(values);
293
294   /* Dispatch new value lists instead of this one */
295   plugin_dispatch_values(&new_vl);
296
297   /* Abort processing */
298   return FC_TARGET_STOP;
299 } /* }}} int v5_zfs_arc_l2_bytes */
300
301 /*
302  * ZFS ARC L2 cache size
303  *
304  * 4.* uses a separate type for this. 5.* uses the generic "cache_size" type
305  * instead.
306  */
307 static int v5_zfs_arc_l2_size(const data_set_t *ds, value_list_t *vl) /* {{{ */
308 {
309   value_list_t new_vl;
310
311   if (vl->values_len != 1)
312     return FC_TARGET_STOP;
313
314   /* Copy everything: Time, interval, host, ... */
315   memcpy(&new_vl, vl, sizeof(new_vl));
316
317   /* Reset data we can't simply copy */
318   new_vl.values = &(value_t){.gauge = NAN};
319   new_vl.values_len = 1;
320   new_vl.meta = NULL;
321
322   new_vl.values[0].gauge = (gauge_t)vl->values[0].gauge;
323
324   /* Change the type to "cache_size" */
325   sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type));
326
327   /* Adapt the type instance */
328   sstrncpy(new_vl.type_instance, "L2", sizeof(new_vl.type_instance));
329
330   /* Dispatch new value lists instead of this one */
331   plugin_dispatch_values(&new_vl);
332
333   /* Abort processing */
334   return FC_TARGET_STOP;
335 } /* }}} int v5_zfs_arc_l2_size */
336
337 /*
338  * ZFS ARC ratio
339  *
340  * "arc_ratio-L1" -> "cache_ratio-arc"
341  * "arc_ratio-L2" -> "cache_ratio-L2"
342  */
343 static int v5_zfs_arc_ratio(const data_set_t *ds, value_list_t *vl) /* {{{ */
344 {
345   value_list_t new_vl;
346
347   if (vl->values_len != 1)
348     return FC_TARGET_STOP;
349
350   /* Copy everything: Time, interval, host, ... */
351   memcpy(&new_vl, vl, sizeof(new_vl));
352
353   /* Reset data we can't simply copy */
354   new_vl.values = &(value_t){.gauge = NAN};
355   new_vl.values_len = 1;
356   new_vl.meta = NULL;
357
358   new_vl.values[0].gauge = (gauge_t)vl->values[0].gauge;
359
360   /* Change the type to "cache_ratio" */
361   sstrncpy(new_vl.type, "cache_ratio", sizeof(new_vl.type));
362
363   /* Adapt the type instance */
364   if (strcmp("L1", vl->type_instance) == 0)
365     sstrncpy(new_vl.type_instance, "arc", sizeof(new_vl.type_instance));
366
367   /* Dispatch new value lists instead of this one */
368   plugin_dispatch_values(&new_vl);
369
370   /* Abort processing */
371   return FC_TARGET_STOP;
372 } /* }}} int v5_zfs_arc_ratio */
373
374 /*
375  * ZFS ARC size
376  *
377  * 4.* uses the "arc_size" type with four data sources. In 5.* this has been
378  * replaces with the "cache_size" type and static data has been removed.
379  */
380 static int v5_zfs_arc_size(const data_set_t *ds, value_list_t *vl) /* {{{ */
381 {
382   value_list_t new_vl;
383
384   if (vl->values_len != 4)
385     return FC_TARGET_STOP;
386
387   /* Copy everything: Time, interval, host, ... */
388   memcpy(&new_vl, vl, sizeof(new_vl));
389
390   /* Reset data we can't simply copy */
391   new_vl.values = &(value_t){.gauge = NAN};
392   new_vl.values_len = 1;
393   new_vl.meta = NULL;
394
395   /* Change the type to "cache_size" */
396   sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type));
397
398   /* Dispatch new value lists instead of this one */
399   new_vl.values[0].derive = (derive_t)vl->values[0].counter;
400   sstrncpy(new_vl.type_instance, "arc", sizeof(new_vl.type_instance));
401   plugin_dispatch_values(&new_vl);
402
403   /* Abort processing */
404   return FC_TARGET_STOP;
405 } /* }}} int v5_zfs_arc_size */
406
407 static int v5_destroy(void **user_data) /* {{{ */
408 {
409   return 0;
410 } /* }}} int v5_destroy */
411
412 static int v5_create(const oconfig_item_t *ci, void **user_data) /* {{{ */
413 {
414   *user_data = NULL;
415   return 0;
416 } /* }}} int v5_create */
417
418 static int v5_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */
419                      notification_meta_t __attribute__((unused)) * *meta,
420                      void __attribute__((unused)) * *user_data) {
421   if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
422     return -EINVAL;
423
424   if (strcmp("df", vl->type) == 0)
425     return v5_df(ds, vl);
426   else if (strcmp("interface", vl->plugin) == 0)
427     return v5_interface(ds, vl);
428   else if (strcmp("mysql_qcache", vl->type) == 0)
429     return v5_mysql_qcache(ds, vl);
430   else if (strcmp("mysql_threads", vl->type) == 0)
431     return v5_mysql_threads(ds, vl);
432   else if (strcmp("arc_counts", vl->type) == 0)
433     return v5_zfs_arc_counts(ds, vl);
434   else if (strcmp("arc_l2_bytes", vl->type) == 0)
435     return v5_zfs_arc_l2_bytes(ds, vl);
436   else if (strcmp("arc_l2_size", vl->type) == 0)
437     return v5_zfs_arc_l2_size(ds, vl);
438   else if (strcmp("arc_ratio", vl->type) == 0)
439     return v5_zfs_arc_ratio(ds, vl);
440   else if (strcmp("arc_size", vl->type) == 0)
441     return v5_zfs_arc_size(ds, vl);
442
443   return FC_TARGET_CONTINUE;
444 } /* }}} int v5_invoke */
445
446 void module_register(void) {
447   target_proc_t tproc = {0};
448
449   tproc.create = v5_create;
450   tproc.destroy = v5_destroy;
451   tproc.invoke = v5_invoke;
452   fc_register_target("v5upgrade", tproc);
453 } /* module_register */