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