/** * collectd - src/target_v5upgrade.c * Copyright (C) 2008-2010 Florian Forster * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Authors: * Florian Forster **/ #include "collectd.h" #include "filter_chain.h" #include "plugin.h" #include "utils/common/common.h" static void v5_swap_instances(value_list_t *vl) /* {{{ */ { char tmp[DATA_MAX_NAME_LEN]; assert(sizeof(tmp) == sizeof(vl->plugin_instance)); assert(sizeof(tmp) == sizeof(vl->type_instance)); memcpy(tmp, vl->plugin_instance, sizeof(tmp)); memcpy(vl->plugin_instance, vl->type_instance, sizeof(tmp)); memcpy(vl->type_instance, tmp, sizeof(tmp)); } /* }}} void v5_swap_instances */ /* * Df type * * By default, the "df" plugin of version 4.* uses the "df" type and puts the * mount point in the type instance. Detect this behavior and convert the type * to "df_complex". This can be selected in versions 4.9 and 4.10 by setting * the "ReportReserved" option of the "df" plugin. */ static int v5_df(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; /* Can't upgrade if both instances have been set. */ if ((vl->plugin_instance[0] != 0) && (vl->type_instance[0] != 0)) return FC_TARGET_CONTINUE; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; /* Move the mount point name to the plugin instance */ if (new_vl.plugin_instance[0] == 0) v5_swap_instances(&new_vl); /* Change the type to "df_complex" */ sstrncpy(new_vl.type, "df_complex", sizeof(new_vl.type)); /* Dispatch two new value lists instead of this one */ new_vl.values[0].gauge = vl->values[0].gauge; sstrncpy(new_vl.type_instance, "used", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); new_vl.values[0].gauge = vl->values[1].gauge; sstrncpy(new_vl.type_instance, "free", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_df */ /* * Interface plugin * * 4.* stores the interface in the type instance and leaves the plugin * instance empty. If this is the case, put the interface name into the plugin * instance and clear the type instance. */ static int v5_interface(const data_set_t *ds, value_list_t *vl) /* {{{ */ { if ((vl->plugin_instance[0] != 0) || (vl->type_instance[0] == 0)) return FC_TARGET_CONTINUE; v5_swap_instances(vl); return FC_TARGET_CONTINUE; } /* }}} int v5_interface */ /* * MySQL query cache * * 4.* uses the "mysql_qcache" type which mixes different types of * information. In 5.* this has been broken up. */ static int v5_mysql_qcache(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; if (vl->values_len != 5) return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; /* Change the type to "cache_result" */ sstrncpy(new_vl.type, "cache_result", sizeof(new_vl.type)); /* Dispatch new value lists instead of this one */ new_vl.values[0].derive = (derive_t)vl->values[0].counter; sstrncpy(new_vl.type_instance, "qcache-hits", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[1].counter; sstrncpy(new_vl.type_instance, "qcache-inserts", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[2].counter; sstrncpy(new_vl.type_instance, "qcache-not_cached", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[3].counter; sstrncpy(new_vl.type_instance, "qcache-prunes", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); /* The last data source is a gauge value, so we have to use a different type * here. */ new_vl.values[0].gauge = vl->values[4].gauge; sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type)); sstrncpy(new_vl.type_instance, "qcache", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_mysql_qcache */ /* * MySQL thread count * * 4.* uses the "mysql_threads" type which mixes different types of * information. In 5.* this has been broken up. */ static int v5_mysql_threads(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; if (vl->values_len != 4) return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; /* Change the type to "threads" */ sstrncpy(new_vl.type, "threads", sizeof(new_vl.type)); /* Dispatch new value lists instead of this one */ new_vl.values[0].gauge = vl->values[0].gauge; sstrncpy(new_vl.type_instance, "running", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); new_vl.values[0].gauge = vl->values[1].gauge; sstrncpy(new_vl.type_instance, "connected", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); new_vl.values[0].gauge = vl->values[2].gauge; sstrncpy(new_vl.type_instance, "cached", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); /* The last data source is a counter value, so we have to use a different * type here. */ new_vl.values[0].derive = (derive_t)vl->values[3].counter; sstrncpy(new_vl.type, "total_threads", sizeof(new_vl.type)); sstrncpy(new_vl.type_instance, "created", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_mysql_threads */ /* * ZFS ARC hit and miss counters * * 4.* uses the flawed "arc_counts" type. In 5.* this has been replaced by the * more generic "cache_result" type. */ static int v5_zfs_arc_counts(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; bool is_hits; if (vl->values_len != 4) return FC_TARGET_STOP; if (strcmp("hits", vl->type_instance) == 0) is_hits = true; else if (strcmp("misses", vl->type_instance) == 0) is_hits = false; else return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; /* Change the type to "cache_result" */ sstrncpy(new_vl.type, "cache_result", sizeof(new_vl.type)); /* Dispatch new value lists instead of this one */ new_vl.values[0].derive = (derive_t)vl->values[0].counter; snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "demand_data-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[1].counter; snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "demand_metadata-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[2].counter; snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "prefetch_data-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[3].counter; snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "prefetch_metadata-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_zfs_arc_counts */ /* * ZFS ARC L2 bytes * * "arc_l2_bytes" -> "io_octets-L2". */ static int v5_zfs_arc_l2_bytes(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; if (vl->values_len != 2) return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.meta = NULL; /* Change the type/-instance to "io_octets-L2" */ sstrncpy(new_vl.type, "io_octets", sizeof(new_vl.type)); sstrncpy(new_vl.type_instance, "L2", sizeof(new_vl.type_instance)); /* Copy the actual values. */ value_t values[] = { {.derive = (derive_t)vl->values[0].counter}, {.derive = (derive_t)vl->values[1].counter}, }; new_vl.values = values; new_vl.values_len = STATIC_ARRAY_SIZE(values); /* Dispatch new value lists instead of this one */ plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_zfs_arc_l2_bytes */ /* * ZFS ARC L2 cache size * * 4.* uses a separate type for this. 5.* uses the generic "cache_size" type * instead. */ static int v5_zfs_arc_l2_size(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; if (vl->values_len != 1) return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; new_vl.values[0].gauge = (gauge_t)vl->values[0].gauge; /* Change the type to "cache_size" */ sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type)); /* Adapt the type instance */ sstrncpy(new_vl.type_instance, "L2", sizeof(new_vl.type_instance)); /* Dispatch new value lists instead of this one */ plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_zfs_arc_l2_size */ /* * ZFS ARC ratio * * "arc_ratio-L1" -> "cache_ratio-arc" * "arc_ratio-L2" -> "cache_ratio-L2" */ static int v5_zfs_arc_ratio(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; if (vl->values_len != 1) return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; new_vl.values[0].gauge = (gauge_t)vl->values[0].gauge; /* Change the type to "cache_ratio" */ sstrncpy(new_vl.type, "cache_ratio", sizeof(new_vl.type)); /* Adapt the type instance */ if (strcmp("L1", vl->type_instance) == 0) sstrncpy(new_vl.type_instance, "arc", sizeof(new_vl.type_instance)); /* Dispatch new value lists instead of this one */ plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_zfs_arc_ratio */ /* * ZFS ARC size * * 4.* uses the "arc_size" type with four data sources. In 5.* this has been * replaces with the "cache_size" type and static data has been removed. */ static int v5_zfs_arc_size(const data_set_t *ds, value_list_t *vl) /* {{{ */ { value_list_t new_vl; if (vl->values_len != 4) return FC_TARGET_STOP; /* Copy everything: Time, interval, host, ... */ memcpy(&new_vl, vl, sizeof(new_vl)); /* Reset data we can't simply copy */ new_vl.values = &(value_t){.gauge = NAN}; new_vl.values_len = 1; new_vl.meta = NULL; /* Change the type to "cache_size" */ sstrncpy(new_vl.type, "cache_size", sizeof(new_vl.type)); /* Dispatch new value lists instead of this one */ new_vl.values[0].derive = (derive_t)vl->values[0].counter; sstrncpy(new_vl.type_instance, "arc", sizeof(new_vl.type_instance)); plugin_dispatch_values(&new_vl); /* Abort processing */ return FC_TARGET_STOP; } /* }}} int v5_zfs_arc_size */ static int v5_destroy(void **user_data) /* {{{ */ { return 0; } /* }}} int v5_destroy */ static int v5_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ { *user_data = NULL; return 0; } /* }}} int v5_create */ static int v5_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ notification_meta_t __attribute__((unused)) * *meta, void __attribute__((unused)) * *user_data) { if ((ds == NULL) || (vl == NULL) || (user_data == NULL)) return -EINVAL; if (strcmp("df", vl->type) == 0) return v5_df(ds, vl); else if (strcmp("interface", vl->plugin) == 0) return v5_interface(ds, vl); else if (strcmp("mysql_qcache", vl->type) == 0) return v5_mysql_qcache(ds, vl); else if (strcmp("mysql_threads", vl->type) == 0) return v5_mysql_threads(ds, vl); else if (strcmp("arc_counts", vl->type) == 0) return v5_zfs_arc_counts(ds, vl); else if (strcmp("arc_l2_bytes", vl->type) == 0) return v5_zfs_arc_l2_bytes(ds, vl); else if (strcmp("arc_l2_size", vl->type) == 0) return v5_zfs_arc_l2_size(ds, vl); else if (strcmp("arc_ratio", vl->type) == 0) return v5_zfs_arc_ratio(ds, vl); else if (strcmp("arc_size", vl->type) == 0) return v5_zfs_arc_size(ds, vl); return FC_TARGET_CONTINUE; } /* }}} int v5_invoke */ void module_register(void) { target_proc_t tproc = {0}; tproc.create = v5_create; tproc.destroy = v5_destroy; tproc.invoke = v5_invoke; fc_register_target("v5upgrade", tproc); } /* module_register */