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