From: Florian Forster Date: Tue, 16 May 2017 17:34:25 +0000 (+0200) Subject: Merge branch 'collectd-5.6' into collectd-5.7 X-Git-Tag: collectd-5.7.2~6 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=fbaf81a04c23d51947d94a5c7d9142290dff07bc;hp=-c Merge branch 'collectd-5.6' into collectd-5.7 --- fbaf81a04c23d51947d94a5c7d9142290dff07bc diff --combined src/collectd.conf.pod index 764ab644,f88430a0..881ae201 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@@ -555,7 -555,6 +555,7 @@@ B # Receive values from an AMQP broker @@@ -730,12 -729,6 +730,12 @@@ If set to B, append the name of t identifier. If set to B (the default), this is only done when there is more than one DS. +=item B B|B + +If set to B (the default) the C<.> (dot) character is replaced with +I. Otherwise, if set to B, the C<.> (dot) character +is preserved, i.e. passed through. + =back =head2 Plugin C @@@ -1121,13 -1114,6 +1121,13 @@@ When set to B, the battery plugi and "remaining capacity") and B (difference between "design capacity" and "last full capacity"). +=item B B|B + +When set to B, the battery plugin will only read statistics +related to battery performance as exposed by StateFS at +/run/state. StateFS is used in Mer-based Sailfish OS, for +example. + =back =head2 Plugin C @@@ -2393,67 -2379,6 +2393,67 @@@ Enabled by default, collects unknown (a =back +=head2 Plugin C + +The I collects information about DPDK interfaces using the +extended NIC stats API in DPDK. + +B + + + Coremask "0x4" + MemoryChannels "4" + ProcessType "secondary" + FilePrefix "rte" + EnabledPortMask 0xffff + PortName "interface1" + PortName "interface2" + + +B + +=over 4 + +=item B I + +A string containing an hexadecimal bit mask of the cores to run on. Note that +core numbering can change between platforms and should be determined beforehand. + +=item B I + +A string containing a number of memory channels per processor socket. + +=item B I + +A string containing the type of DPDK process instance. + +=item B I + +The prefix text used for hugepage filenames. The filename will be set to +/var/run/._config where prefix is what is passed in by the user. + +=item B I + +A string containing amount of Memory to allocate from hugepages on specific +sockets in MB + +=item B I + +A hexidecimal bit mask of the DPDK ports which should be enabled. A mask +of 0x0 means that all ports will be disabled. A bitmask of all Fs means +that all ports will be enabled. This is an optional argument - default +is all ports enabled. + +=item B I + +A string containing an optional name for the enabled DPDK ports. Each PortName +option should contain only one port name; specify as many PortName options as +desired. Default naming convention will be used if PortName is blank. If there +are less PortName options than there are enabled ports, the default naming +convention will be used for the additional ports. + +=back + =head2 Plugin C =over 4 @@@ -2904,101 -2829,6 +2904,101 @@@ TCP-Port to connect to. Defaults to B<7 =back +=head2 Plugin C + +To collect B information, collectd reads directories +"/sys/devices/system/node/*/hugepages" and +"/sys/kernel/mm/hugepages". +Reading of these directories can be disabled by the following +options (default is enabled). + +=over 4 + +=item B B|B + +If enabled, information will be collected from the hugepage +counters in "/sys/devices/system/node/*/hugepages". +This is used to check the per-node hugepage statistics on +a NUMA system. + +=item B B|B + +If enabled, information will be collected from the hugepage +counters in "/sys/kernel/mm/hugepages". +This can be used on both NUMA and non-NUMA systems to check +the overall hugepage statistics. + +=item B B|B + +Whether to report hugepages metrics in number of pages. +Defaults to B. + +=item B B|B + +Whether to report hugepages metrics in bytes. +Defaults to B. + +=item B B|B + +Whether to report hugepages metrics as percentage. +Defaults to B. + +=back + +=head2 Plugin C + +The I plugin collects information provided by monitoring features of +Intel Resource Director Technology (Intel(R) RDT) like Cache Monitoring +Technology (CMT), Memory Bandwidth Monitoring (MBM). These features provide +information about utilization of shared resources. CMT monitors last level cache +occupancy (LLC). MBM supports two types of events reporting local and remote +memory bandwidth. Local memory bandwidth (MBL) reports the bandwidth of +accessing memory associated with the local socket. Remote memory bandwidth (MBR) +reports the bandwidth of accessing the remote socket. Also this technology +allows to monitor instructions per clock (IPC). +Monitor events are hardware dependant. Monitoring capabilities are detected on +plugin initialization and only supported events are monitored. + +B + + + Cores "0-2" "3,4,6" "8-10,15" + + +B + +=over 4 + +=item B I + +The interval within which to retrieve statistics on monitored events in seconds. +For milliseconds divide the time by 1000 for example if the desired interval +is 50ms, set interval to 0.05. Due to limited capacity of counters it is not +recommended to set interval higher than 1 sec. + +=item B I + +All events are reported on a per core basis. Monitoring of the events can be +configured for group of cores (aggregated statistics). This field defines groups +of cores on which to monitor supported events. The field is represented as list +of strings with core group values. Each string represents a list of cores in a +group. Allowed formats are: + 0,1,2,3 + 0-10,20-18 + 1,3,5-8,10,0x10-12 + +If an empty string is provided as value for this field default cores +configuration is applied - a separate group is created for each core. + +=back + +B By default global interval is used to retrieve statistics on monitored +events. To configure a plugin specific interval use B option of the +intel_rdt block. For milliseconds divide the time by 1000 for +example if the desired interval is 50ms, set interval to 0.05. +Due to limited capacity of counters it is not recommended to set interval higher +than 1 sec. + =head2 Plugin C =over 4 @@@ -3420,12 -3250,11 +3420,12 @@@ interpreted. For a description of matc The B connects to a memcached server and queries statistics about cache utilization, memory and bandwidth used. -L +L - Host "memcache.example.com" + #Host "memcache.example.com" + Address "127.0.0.1" Port 11211 @@@ -3438,25 -3267,16 +3438,25 @@@ following options are allowed =item B I -Hostname to connect to. Defaults to B<127.0.0.1>. +Sets the B field of dispatched values. Defaults to the global hostname +setting. +For backwards compatibility, values are also dispatched with the global +hostname when B is set to B<127.0.0.1> or B and B
is +not set. + +=item B
I
+ +Hostname or IP to connect to. For backwards compatibility, defaults to the +value of B or B<127.0.0.1> if B is unset. =item B I -TCP-Port to connect to. Defaults to B<11211>. +TCP port to connect to. Defaults to B<11211>. =item B I Connect to I using the UNIX domain socket at I. If this -setting is given, the B and B settings are ignored. +setting is given, the B
and B settings are ignored. =back @@@ -5556,10 -5376,10 +5556,10 @@@ multiple hosts =item B I Sets the interval in which to send ICMP echo packets to the configured hosts. - This is B the interval in which statistics are queries from the plugin but - the interval in which the hosts are "pinged". Therefore, the setting here - should be smaller than or equal to the global B setting. Fractional - times, such as "1.24" are allowed. + This is B the interval in which metrics are read from the plugin but the + interval in which the hosts are "pinged". Therefore, the setting here should be + smaller than or equal to the global B setting. Fractional times, such + as "1.24" are allowed. Default: B<1.0> @@@ -5903,7 -5723,7 +5903,7 @@@ values are made available through thos =item B<$1> -The timestamp of the queried value as a floating point number. +The timestamp of the queried value as an RFC 3339-formatted local time. =item B<$2> @@@ -7119,15 -6939,6 +7119,15 @@@ user using (extended) regular expressio Type "counter" Instance "local_user" + + Regex "l=([0-9]*\\.[0-9]*)" + + Percentile 99 + Bucket 0 100 + + Type "latency" + Instance "foo" + @@@ -7190,13 -7001,6 +7190,13 @@@ Use the greatest number only Use the last number found. +=item B + +Use the last number found. The number is not reset at the end of an interval. +It is continously reported until another number is matched. This is intended +for cases in which only state changes are reported, for example a thermometer +that only reports the temperature when it changes. + =item B =item B @@@ -7226,74 -7030,14 +7226,74 @@@ Increase the internal counter by one. T not use the matched subexpression, but simply count the number of matched lines. Thus, you may use a regular expression without submatch in this case. +=item B + +Type to do calculations based on the distribution of values, primarily +calculating percentiles. This is primarily geared towards latency, but can be +used for other metrics as well. The range of values tracked with this setting +must be in the range (0–2^34) and can be fractional. Please note that neither +zero nor 2^34 are inclusive bounds, i.e. zero I be handled by a +distribution. + +This option must be used together with the B and/or B +options. + +B + + + Percentile 99 + Bucket 0 100 + + +=over 4 + +=item B I + +Calculate and dispatch the configured percentile, i.e. compute the value, so +that I of all matched values are smaller than or equal to the computed +latency. + +Metrics are reported with the I B (the value of the above option) +and the I C<[EInstanceE-]EPercentE>. + +This option may be repeated to calculate more than one percentile. + +=item B I I + +Export the number of values (a C) falling within the given range. Both, +I and I may be a fractional number, such as B<0.5>. +Each B option specifies an interval C<(I, +I]>, i.e. the range I the lower bound and I +the upper bound. I and I may be zero, meaning no +lower/upper bound. + +To export the entire (0–inf) range without overlap, use the upper bound of the +previous range as the lower bound of the following range. In other words, use +the following schema: + + Bucket 0 1 + Bucket 1 2 + Bucket 2 5 + Bucket 5 10 + Bucket 10 20 + Bucket 20 50 + Bucket 50 0 + +Metrics are reported with the I C and the I +CTypeE[-EInstanceE]-Elower_boundE_Eupper_boundE>. + +This option may be repeated to calculate more than one rate. + =back -As you'd expect the B types interpret the submatch as a floating point -number, using L. The B and B types interpret -the submatch as an unsigned integer using L. The B types -interpret the submatch as a signed integer using L. B -and B do not use the submatch at all and it may be omitted in this -case. +=back + +The B and B types interpret the submatch as a floating +point number, using L. The B and B types +interpret the submatch as an unsigned integer using L. The +B types interpret the submatch as a signed integer using +L. B and B do not use the submatch at all +and it may be omitted in this case. =item B I @@@ -7550,7 -7294,7 +7550,7 @@@ couple metrics: number of records, and =item B I -The hostname or ip which identifies the server. +The hostname or IP which identifies the server. Default: B<127.0.0.1> =item B I @@@ -7564,60 -7308,61 +7564,60 @@@ Default: B<1978 =head2 Plugin C The I reads CPU frequency and C-state residency on modern -Intel processors by using the new Model Specific Registers. +Intel processors by using I. =over 4 =item B I -Bitmask of the list of core C states supported by the processor. +Bit mask of the list of core C-states supported by the processor. This option should only be used if the automated detection fails. -Default value extracted from the cpu model and family. +Default value extracted from the CPU model and family. Currently supported C-states (by this plugin): 3, 6, 7 -Example: (1<<3)+(1<<6)+(1<<7) = 392 for all states +B + + All states (3, 6 and 7): + (1<<3) + (1<<6) + (1<<7) = 392 =item B I -Bitmask of the list of pacages C states supported by the processor. -This option should only be used if the automated detection fails. -Default value extracted from the cpu model and family. +Bit mask of the list of packages C-states supported by the processor. This +option should only be used if the automated detection fails. Default value +extracted from the CPU model and family. Currently supported C-states (by this plugin): 2, 3, 6, 7, 8, 9, 10 -Example: (1<<2)+(1<<3)+(1<<6)+(1<<7) = 396 for states 2, 3, 6 and 7 - -=item B I|I +B -Boolean enabling the collection of the I/O System-Management Interrupt -counter'. This option should only be used if the automated detection -fails or if you want to disable this feature. + States 2, 3, 6 and 7: + (1<<2) + (1<<3) + (1<<6) + (1<<7) = 396 -=item B I|I +=item B I|I -Boolean enabling the collection of the temperature of each core. -This option should only be used if the automated detectionfails or -if you want to disable this feature. +Boolean enabling the collection of the I/O System-Management Interrupt counter. +This option should only be used if the automated detection fails or if you want +to disable this feature. =item B I|I -Boolean enabling the collection of the temperature of each package. -This option should only be used if the automated detectionfails or -if you want to disable this feature. +Boolean enabling the collection of the temperature of each core. This option +should only be used if the automated detection fails or if you want to disable +this feature. =item B I -Thermal Control Circuit Activation Temperature of the installed -CPU. This temperature is used when collecting the temperature of -cores or packages. This option should only be used if the automated -detection fails. Default value extracted from B +I of the installed CPU. This +temperature is used when collecting the temperature of cores or packages. This +option should only be used if the automated detection fails. Default value +extracted from B. =item B I -Bitmask of the list of elements to be thermally monitored. This option -should only be used if the automated detection fails or if you want to -disable some collections. The different bits of this bitmask accepted -by this plugin are: +Bit mask of the list of elements to be thermally monitored. This option should +only be used if the automated detection fails or if you want to disable some +collections. The different bits of this bit mask accepted by this plugin are: =over 4 @@@ -7631,14 -7376,6 +7631,14 @@@ =back +=item B I|I + +Boolean enabling the use of logical core numbering for per core statistics. +When enabled, CnE> is used as plugin instance, where I is a +sequential number assigned by the kernel. Otherwise, CnE> is used +where I is the n-th core of the socket, causing name conflicts when there is +more than one socket. + =back =head2 Plugin C @@@ -7920,49 -7657,6 +7920,49 @@@ Example Ignore all I devices on any domain, but other block devices (eg. I) will be collected. +=item B B|B + +If I is set to B, the default, then the device name +seen by the guest will be used for reporting metrics. +This corresponds to the CtargetE> node in the XML definition of the +domain. + +If I is set to B, then metrics will be reported +using the path of the source, e.g. an image file. +This corresponds to the CsourceE> node in the XML definition of the +domain. + +B + +If the domain XML have the following device defined: + + + + + + +
+ + +Setting C will cause the I to be set +to C. +Setting C will cause the I to be set +to C. + +=item B B|B + +The B controls whether the full path or the +L of the source is being used as the I when +B is set to B. Defaults to B. + +B + +Assume the device path (source tag) is C. +Setting C will cause the I to +be set to C. +Setting C will cause the I to be +set to C. + =item B B When the virt plugin logs data, it sets the hostname of the collected data @@@ -8129,38 -7823,6 +8129,38 @@@ If set to B, append the name of t identifier. If set to B (the default), this is only done when there is more than one DS. +=item B B|B + +If set to B (the default) the C<.> (dot) character is replaced with +I. Otherwise, if set to B, the C<.> (dot) character +is preserved, i.e. passed through. + +=item B B|B + +If set to B, detect and remove duplicate components in Graphite metric +names. For example, the metric name C will +be shortened to C. + +=back + +=head2 Plugin C + +The C plugin writes metrics as INFO log messages. + +This plugin supports two output formats: I and I. + +Synopsis: + + + Format Graphite + + +=over 4 + +=item B I + +The output format to use. Can be one of C or C. + =back =head2 Plugin C @@@ -8269,41 -7931,6 +8269,41 @@@ want to use authentication all three fi =back +=head2 Plugin C + +The I implements a tiny webserver that can be scraped +using I. + +B + +=over 4 + +=item B I + +Port the embedded webserver should listen on. Defaults to B<9103>. + +=item B I + +Time in seconds after which I considers a metric "stale" if it +hasn't seen any update for it. This value must match the setting in Prometheus. +It defaults to B<300> seconds (5 minutes), same as Prometheus. + +B + +I has a global setting, C, which controls after +which time a metric without updates is considered "stale". This setting +effectively puts an upper limit on the interval in which metrics are reported. + +When the I encounters a metric with an interval +exceeding this limit, it will inform you, the user, and provide the metric to +I B a timestamp. That causes I to consider the +metric "fresh" each time it is scraped, with the time of the scrape being +considered the time of the update. The result is that there appear more +datapoints in I than were actually created, but at least the metric +doesn't disappear periodically. + +=back + =head2 Plugin C This output plugin submits values to an HTTP server using POST requests and @@@ -8537,18 -8164,6 +8537,18 @@@ path component, for example C. +=item B B|B + +If set to B, append the name of the I (DS) to the "metric" +identifier. If set to B (the default), this is only done when there is +more than one DS. + +=item B B|B + +If set to B (the default) the C<.> (dot) character is replaced with +I. Otherwise, if set to B, the C<.> (dot) character +is preserved, i.e. passed through. + =item B B|B If set to B (the default), convert counter values to rates. If set to @@@ -9483,8 -9098,6 +9483,8 @@@ Available options =item B I +=item B I I + Match values where the given regular expressions match the various fields of the identifier of a value. If multiple regular expressions are given, B regexen must match for a value to match. @@@ -9773,10 -9386,6 +9773,10 @@@ Available options =item B I I +=item B I I I + +=item B I I + Match the appropriate field with the given regular expression I. If the regular expression matches, that part that matches is replaced with I. If multiple places of the input buffer match a given regular @@@ -9815,37 -9424,9 +9815,37 @@@ Available options =item B I I -Set the appropriate field to the given string. The strings for plugin instance -and type instance may be empty, the strings for host and plugin may not be -empty. It's currently not possible to set the type of a value this way. +Set the appropriate field to the given string. The strings for plugin instance, +type instance, and meta data may be empty, the strings for host and plugin may +not be empty. It's currently not possible to set the type of a value this way. + +The following placeholders will be replaced by an appropriate value: + +=over 4 + +=item B<%{host}> + +=item B<%{plugin}> + +=item B<%{plugin_instance}> + +=item B<%{type}> + +=item B<%{type_instance}> + +These placeholders are replaced by the identifier field of the same name. + +=item B<%{meta:>IB<}> + +These placeholders are replaced by the meta data value with the given name. + +=back + +Please note that these placeholders are B! + +=item B I + +Delete the named meta data field. =back diff --combined src/curl_json.c index e6c0b513,9cdd4fe8..6f31145c --- a/src/curl_json.c +++ b/src/curl_json.c @@@ -171,23 -171,53 +171,53 @@@ static int cj_get_type(cj_key_t *key) return ds->ds[0].type; } - static int cj_cb_map_key(void *ctx, const unsigned char *val, yajl_len_t len); + /* cj_load_key loads the configuration for "key" from the parent context and + * sets either .key or .tree in the current context. */ + static int cj_load_key(cj_t *db, char const *key) { + if (db == NULL || key == NULL || db->depth <= 0) + return EINVAL; - static void cj_cb_inc_array_index(void *ctx, _Bool update_key) { - cj_t *db = (cj_t *)ctx; + sstrncpy(db->state[db->depth].name, key, sizeof(db->state[db->depth].name)); + + c_avl_tree_t *tree = db->state[db->depth - 1].tree; + if (tree == NULL) { + return 0; + } + + /* the parent has a key, so the tree pointer is invalid. */ + if (CJ_IS_KEY(db->state[db->depth - 1].key)) { + return 0; + } + + void *value = NULL; + if (c_avl_get(tree, key, (void *)&value) == 0) { + if (CJ_IS_KEY((cj_key_t *)value)) { + db->state[db->depth].key = value; + } else { + db->state[db->depth].tree = value; + } + } else if (c_avl_get(tree, CJ_ANY, (void *)&value) == 0) { + if (CJ_IS_KEY((cj_key_t *)value)) { + db->state[db->depth].key = value; + } else { + db->state[db->depth].tree = value; + } + } else { + db->state[db->depth].key = NULL; + } + + return 0; + } + static void cj_advance_array(cj_t *db) { if (!db->state[db->depth].in_array) return; db->state[db->depth].index++; - if (update_key) { - char name[DATA_MAX_NAME_LEN]; - - ssnprintf(name, sizeof(name), "%d", db->state[db->depth].index - 1); - - cj_cb_map_key(ctx, (unsigned char *)name, (yajl_len_t)strlen(name)); - } + char name[DATA_MAX_NAME_LEN]; + ssnprintf(name, sizeof(name), "%d", db->state[db->depth].index); + cj_load_key(db, name); } /* yajl callbacks */ @@@ -195,12 -225,12 +225,12 @@@ #define CJ_CB_CONTINUE 1 static int cj_cb_boolean(void *ctx, int boolVal) { - cj_cb_inc_array_index(ctx, /* update_key = */ 0); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } static int cj_cb_null(void *ctx) { - cj_cb_inc_array_index(ctx, /* update_key = */ 0); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } @@@ -209,40 -239,37 +239,37 @@@ static int cj_cb_number(void *ctx, cons cj_t *db = (cj_t *)ctx; cj_key_t *key = db->state[db->depth].key; - value_t vt; - int type; - int status; /* Create a null-terminated version of the string. */ memcpy(buffer, number, number_len); buffer[sizeof(buffer) - 1] = 0; - if ((key == NULL) || !CJ_IS_KEY(key)) { - if (key != NULL && - !db->state[db->depth].in_array /*can be inhomogeneous*/) { - NOTICE("curl_json plugin: Found \"%s\", but the configuration expects" - " a map.", - buffer); - return (CJ_CB_CONTINUE); - } - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - key = db->state[db->depth].key; - if ((key == NULL) || !CJ_IS_KEY(key)) { - return (CJ_CB_CONTINUE); - } - } else { - cj_cb_inc_array_index(ctx, /* update_key = */ 1); + + if (key == NULL) { + /* no config for this element. */ + cj_advance_array(ctx); + return CJ_CB_CONTINUE; + } else if (!CJ_IS_KEY(key)) { + /* the config expects a map or an array. */ + NOTICE( + "curl_json plugin: Found \"%s\", but the configuration expects a map.", + buffer); + cj_advance_array(ctx); + return CJ_CB_CONTINUE; } - type = cj_get_type(key); - status = parse_value(buffer, &vt, type); + int type = cj_get_type(key); + value_t vt; + int status = parse_value(buffer, &vt, type); if (status != 0) { NOTICE("curl_json plugin: Unable to parse number: \"%s\"", buffer); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } cj_submit(db, key, &vt); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } /* int cj_cb_number */ @@@ -251,40 -278,15 +278,15 @@@ * NULL. */ static int cj_cb_map_key(void *ctx, unsigned char const *in_name, yajl_len_t in_name_len) { - cj_t *db = (cj_t *)ctx; - c_avl_tree_t *tree; + char name[in_name_len + 1]; - tree = db->state[db->depth - 1].tree; - - if (tree != NULL) { - cj_key_t *value = NULL; - char *name; - size_t name_len; - - /* Create a null-terminated version of the name. */ - name = db->state[db->depth].name; - name_len = - COUCH_MIN((size_t)in_name_len, sizeof(db->state[db->depth].name) - 1); - memcpy(name, in_name, name_len); - name[name_len] = 0; - - if (c_avl_get(tree, name, (void *)&value) == 0) { - if (CJ_IS_KEY((cj_key_t *)value)) { - db->state[db->depth].key = value; - } else { - db->state[db->depth].tree = (c_avl_tree_t *)value; - } - } else if (c_avl_get(tree, CJ_ANY, (void *)&value) == 0) - if (CJ_IS_KEY((cj_key_t *)value)) { - db->state[db->depth].key = value; - } else { - db->state[db->depth].tree = (c_avl_tree_t *)value; - } - else - db->state[db->depth].key = NULL; - } + memmove(name, in_name, in_name_len); + name[sizeof(name) - 1] = 0; - return (CJ_CB_CONTINUE); + if (cj_load_key(ctx, name) != 0) + return CJ_CB_ABORT; + + return CJ_CB_CONTINUE; } static int cj_cb_string(void *ctx, const unsigned char *val, yajl_len_t len) { @@@ -292,38 -294,43 +294,43 @@@ return (cj_cb_number(ctx, (const char *)val, len)); } /* int cj_cb_string */ - static int cj_cb_start(void *ctx) { - cj_t *db = (cj_t *)ctx; - if (++db->depth >= YAJL_MAX_DEPTH) { - ERROR("curl_json plugin: %s depth exceeds max, aborting.", - db->url ? db->url : db->sock); - return (CJ_CB_ABORT); - } - return (CJ_CB_CONTINUE); - } - static int cj_cb_end(void *ctx) { cj_t *db = (cj_t *)ctx; db->state[db->depth].tree = NULL; - --db->depth; + db->depth--; + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } static int cj_cb_start_map(void *ctx) { - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - return cj_cb_start(ctx); + cj_t *db = (cj_t *)ctx; + + if ((db->depth + 1) >= YAJL_MAX_DEPTH) { + ERROR("curl_json plugin: %s depth exceeds max, aborting.", + db->url ? db->url : db->sock); + return (CJ_CB_ABORT); + } + db->depth++; + return (CJ_CB_CONTINUE); } static int cj_cb_end_map(void *ctx) { return cj_cb_end(ctx); } static int cj_cb_start_array(void *ctx) { cj_t *db = (cj_t *)ctx; - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - if (db->depth + 1 < YAJL_MAX_DEPTH) { - db->state[db->depth + 1].in_array = 1; - db->state[db->depth + 1].index = 0; + + if ((db->depth + 1) >= YAJL_MAX_DEPTH) { + ERROR("curl_json plugin: %s depth exceeds max, aborting.", + db->url ? db->url : db->sock); + return CJ_CB_ABORT; } - return cj_cb_start(ctx); + db->depth++; + db->state[db->depth].in_array = 1; + db->state[db->depth].index = 0; + + cj_load_key(db, "0"); + + return CJ_CB_CONTINUE; } static int cj_cb_end_array(void *ctx) { @@@ -709,11 -716,10 +716,11 @@@ static int cj_config_add_url(oconfig_it cb_name = ssnprintf_alloc("curl_json-%s-%s", db->instance, db->url ? db->url : db->sock); - user_data_t ud = {.data = db, .free_func = cj_free}; - plugin_register_complex_read(/* group = */ NULL, cb_name, cj_read, - /* interval = */ db->interval, &ud); + /* interval = */ db->interval, + &(user_data_t){ + .data = db, .free_func = cj_free, + }); sfree(cb_name); } else { cj_free(db); diff --combined src/perl.c index 59109133,d01f5c7c..ea53fbf3 --- a/src/perl.c +++ b/src/perl.c @@@ -22,7 -22,6 +22,7 @@@ * * Authors: * Sebastian Harl + * Pavel Rochnyak **/ /* @@@ -78,9 -77,8 +78,9 @@@ #define PLUGIN_LOG 4 #define PLUGIN_NOTIF 5 #define PLUGIN_FLUSH 6 +#define PLUGIN_FLUSH_ALL 7 /* For collectd-5.6 only */ -#define PLUGIN_TYPES 7 +#define PLUGIN_TYPES 8 #define PLUGIN_CONFIG 254 #define PLUGIN_DATASET 255 @@@ -104,16 -102,6 +104,16 @@@ /* this is defined in DynaLoader.a */ void boot_DynaLoader(PerlInterpreter *, CV *); +static XS(Collectd_plugin_register_read); +static XS(Collectd_plugin_register_write); +static XS(Collectd_plugin_register_log); +static XS(Collectd_plugin_register_notification); +static XS(Collectd_plugin_register_flush); +static XS(Collectd_plugin_unregister_read); +static XS(Collectd_plugin_unregister_write); +static XS(Collectd_plugin_unregister_log); +static XS(Collectd_plugin_unregister_notification); +static XS(Collectd_plugin_unregister_flush); static XS(Collectd_plugin_register_ds); static XS(Collectd_plugin_unregister_ds); static XS(Collectd_plugin_dispatch_values); @@@ -125,14 -113,6 +125,14 @@@ static XS(Collectd_plugin_log) static XS(Collectd__fc_register); static XS(Collectd_call_by_name); +static int perl_read(user_data_t *ud); +static int perl_write(const data_set_t *ds, const value_list_t *vl, + user_data_t *user_data); +static void perl_log(int level, const char *msg, user_data_t *user_data); +static int perl_notify(const notification_t *notif, user_data_t *user_data); +static int perl_flush(cdtime_t timeout, const char *identifier, + user_data_t *user_data); + /* * private data types */ @@@ -185,8 -165,6 +185,8 @@@ extern char **environ * private variables */ +static _Bool register_legacy_flush = 1; + /* if perl_threads != NULL perl_threads->head must * point to the "base" thread */ static c_ithread_list_t *perl_threads = NULL; @@@ -203,18 -181,6 +203,18 @@@ static struct char name[64]; XS((*f)); } api[] = { + {"Collectd::plugin_register_read", Collectd_plugin_register_read}, + {"Collectd::plugin_register_write", Collectd_plugin_register_write}, + {"Collectd::plugin_register_log", Collectd_plugin_register_log}, + {"Collectd::plugin_register_notification", + Collectd_plugin_register_notification}, + {"Collectd::plugin_register_flush", Collectd_plugin_register_flush}, + {"Collectd::plugin_unregister_read", Collectd_plugin_unregister_read}, + {"Collectd::plugin_unregister_write", Collectd_plugin_unregister_write}, + {"Collectd::plugin_unregister_log", Collectd_plugin_unregister_log}, + {"Collectd::plugin_unregister_notification", + Collectd_plugin_unregister_notification}, + {"Collectd::plugin_unregister_flush", Collectd_plugin_unregister_flush}, {"Collectd::plugin_register_data_set", Collectd_plugin_register_ds}, {"Collectd::plugin_unregister_data_set", Collectd_plugin_unregister_ds}, {"Collectd::plugin_dispatch_values", Collectd_plugin_dispatch_values}, @@@ -496,16 -462,15 +496,15 @@@ static int av2data_set(pTHX_ AV *array * meta => [ { name => , value => }, ... ] * } */ - static int av2notification_meta(pTHX_ AV *array, notification_meta_t **meta) { - notification_meta_t **m = meta; + static int av2notification_meta(pTHX_ AV *array, notification_meta_t **ret_meta) { + notification_meta_t *tail = NULL; int len = av_len(array); for (int i = 0; i <= len; ++i) { SV **tmp = av_fetch(array, i, 0); - HV *hash; - if (NULL == tmp) + if (tmp == NULL) return -1; if (!(SvROK(*tmp) && (SVt_PVHV == SvTYPE(SvRV(*tmp))))) { @@@ -514,42 -479,51 +513,51 @@@ continue; } - hash = (HV *)SvRV(*tmp); + HV *hash = (HV *)SvRV(*tmp); - *m = smalloc(sizeof(**m)); + notification_meta_t *m = calloc(1, sizeof(*m)); + if (m == NULL) + return ENOMEM; - if (NULL == (tmp = hv_fetch(hash, "name", 4, 0))) { + SV **name = hv_fetch(hash, "name", strlen("name"), 0); + if (name == NULL) { log_warn("av2notification_meta: Skipping invalid " "meta information."); - free(*m); + sfree(m); continue; } - sstrncpy((*m)->name, SvPV_nolen(*tmp), sizeof((*m)->name)); + sstrncpy(m->name, SvPV_nolen(*name), sizeof(m->name)); - if (NULL == (tmp = hv_fetch(hash, "value", 5, 0))) { + SV **value = hv_fetch(hash, "value", strlen("value"), 0); + if (value == NULL) { log_warn("av2notification_meta: Skipping invalid " "meta information."); - free(*m); + sfree(m); continue; } - if (SvNOK(*tmp)) { - (*m)->nm_value.nm_double = SvNVX(*tmp); - (*m)->type = NM_TYPE_DOUBLE; - } else if (SvUOK(*tmp)) { - (*m)->nm_value.nm_unsigned_int = SvUVX(*tmp); - (*m)->type = NM_TYPE_UNSIGNED_INT; - } else if (SvIOK(*tmp)) { - (*m)->nm_value.nm_signed_int = SvIVX(*tmp); - (*m)->type = NM_TYPE_SIGNED_INT; + if (SvNOK(*value)) { + m->nm_value.nm_double = SvNVX(*value); + m->type = NM_TYPE_DOUBLE; + } else if (SvUOK(*value)) { + m->nm_value.nm_unsigned_int = SvUVX(*value); + m->type = NM_TYPE_UNSIGNED_INT; + } else if (SvIOK(*value)) { + m->nm_value.nm_signed_int = SvIVX(*value); + m->type = NM_TYPE_SIGNED_INT; } else { - (*m)->nm_value.nm_string = sstrdup(SvPV_nolen(*tmp)); - (*m)->type = NM_TYPE_STRING; + m->nm_value.nm_string = sstrdup(SvPV_nolen(*value)); + m->type = NM_TYPE_STRING; } - (*m)->next = NULL; - m = &((*m)->next); + m->next = NULL; + if (tail == NULL) + *ret_meta = m; + else + tail->next = m; + tail = m; } + return 0; } /* static int av2notification_meta (AV *, notification_meta_t *) */ @@@ -999,7 -973,7 +1007,7 @@@ static int call_pv_locked(pTHX_ const c return 0; } - ret = call_pv(sub_name, G_SCALAR); + ret = call_pv(sub_name, G_SCALAR | G_EVAL); t->running = old_running; return ret; @@@ -1008,12 -982,11 +1016,12 @@@ /* * Call all working functions of the given type. */ -static int pplugin_call_all(pTHX_ int type, ...) { +static int pplugin_call(pTHX_ int type, ...) { int retvals = 0; va_list ap; int ret = 0; + char *subname; dSP; @@@ -1027,16 -1000,9 +1035,16 @@@ PUSHMARK(SP); - XPUSHs(sv_2mortal(newSViv((IV)type))); + if (PLUGIN_READ == type) { + subname = va_arg(ap, char *); + } else if (PLUGIN_WRITE == type) { + data_set_t *ds; + value_list_t *vl; - if (PLUGIN_WRITE == type) { + AV *pds = newAV(); + HV *pvl = newHV(); + + subname = va_arg(ap, char *); /* * $_[0] = $plugin_type; * @@@ -1062,6 -1028,12 +1070,6 @@@ * type_instance => $type_instance * }; */ - data_set_t *ds; - value_list_t *vl; - - AV *pds = newAV(); - HV *pvl = newHV(); - ds = va_arg(ap, data_set_t *); vl = va_arg(ap, value_list_t *); @@@ -1083,7 -1055,6 +1091,7 @@@ XPUSHs(sv_2mortal(newRV_noinc((SV *)pds))); XPUSHs(sv_2mortal(newRV_noinc((SV *)pvl))); } else if (PLUGIN_LOG == type) { + subname = va_arg(ap, char *); /* * $_[0] = $level; * @@@ -1092,10 -1063,6 +1100,10 @@@ XPUSHs(sv_2mortal(newSViv(va_arg(ap, int)))); XPUSHs(sv_2mortal(newSVpv(va_arg(ap, char *), 0))); } else if (PLUGIN_NOTIF == type) { + notification_t *n; + HV *notif = newHV(); + + subname = va_arg(ap, char *); /* * $_[0] = * { @@@ -1109,6 -1076,9 +1117,6 @@@ * type_instance => $type_instance * }; */ - notification_t *n; - HV *notif = newHV(); - n = va_arg(ap, notification_t *); if (-1 == notification2hv(aTHX_ n, notif)) { @@@ -1121,48 -1091,23 +1129,48 @@@ XPUSHs(sv_2mortal(newRV_noinc((SV *)notif))); } else if (PLUGIN_FLUSH == type) { cdtime_t timeout; + subname = va_arg(ap, char *); + /* + * $_[0] = $timeout; + * $_[1] = $identifier; + */ + timeout = va_arg(ap, cdtime_t); + XPUSHs(sv_2mortal(newSVnv(CDTIME_T_TO_DOUBLE(timeout)))); + XPUSHs(sv_2mortal(newSVpv(va_arg(ap, char *), 0))); + } else if (PLUGIN_FLUSH_ALL == type) { + cdtime_t timeout; + subname = "Collectd::plugin_call_all"; /* * $_[0] = $timeout; * $_[1] = $identifier; */ timeout = va_arg(ap, cdtime_t); + XPUSHs(sv_2mortal(newSViv((IV)PLUGIN_FLUSH))); XPUSHs(sv_2mortal(newSVnv(CDTIME_T_TO_DOUBLE(timeout)))); XPUSHs(sv_2mortal(newSVpv(va_arg(ap, char *), 0))); + } else if (PLUGIN_INIT == type) { + subname = "Collectd::plugin_call_all"; + XPUSHs(sv_2mortal(newSViv((IV)type))); + } else if (PLUGIN_SHUTDOWN == type) { + subname = "Collectd::plugin_call_all"; + XPUSHs(sv_2mortal(newSViv((IV)type))); + } else { /* Unknown type. Run 'plugin_call_all' and make compiler happy */ + subname = "Collectd::plugin_call_all"; + XPUSHs(sv_2mortal(newSViv((IV)type))); } PUTBACK; - retvals = call_pv_locked(aTHX_ "Collectd::plugin_call_all"); + retvals = call_pv_locked(aTHX_ subname); SPAGAIN; - if (0 < retvals) { + if (SvTRUE(ERRSV)) { + if (PLUGIN_LOG != type) + ERROR("perl: %s error: %s", subname, SvPV_nolen(ERRSV)); + ret = -1; + } else if (0 < retvals) { SV *tmp = POPs; if (!SvTRUE(tmp)) ret = -1; @@@ -1174,7 -1119,7 +1182,7 @@@ va_end(ap); return ret; -} /* static int pplugin_call_all (int, ...) */ +} /* static int pplugin_call (int, ...) */ /* * collectd's Perl interpreter based thread implementation. @@@ -1189,10 -1134,6 +1197,10 @@@ static void c_ithread_destroy(c_ithread assert(NULL != perl_threads); PERL_SET_CONTEXT(aTHX); + /* Mark as running to avoid deadlock: + c_ithread_destroy -> log_debug -> perl_log() + */ + ithread->running = 1; log_debug("Shutting down Perl interpreter %p...", aTHX); #if COLLECT_DEBUG @@@ -1406,10 -1347,7 +1414,10 @@@ static int fc_call(pTHX_ int type, int } SPAGAIN; - if (0 < retvals) { + if (SvTRUE(ERRSV)) { + ERROR("perl: Collectd::fc_call error: %s", SvPV_nolen(ERRSV)); + ret = -1; + } else if (0 < retvals) { SV *tmp = POPs; /* the exec callbacks return a status, while @@@ -1565,163 -1503,6 +1573,163 @@@ static target_proc_t ptarget = {ptarget * Exported Perl API. */ +static void _plugin_register_generic_userdata(pTHX, int type, + const char *desc) { + int ret = 0; + user_data_t userdata; + char *pluginname; + + dXSARGS; + + if (2 != items) { + log_err("Usage: Collectd::plugin_register_%s(pluginname, subname)", desc); + XSRETURN_EMPTY; + } + + if (!SvOK(ST(0))) { + log_err("Collectd::plugin_register_%s(pluginname, subname): " + "Invalid pluginname", + desc); + XSRETURN_EMPTY; + } + if (!SvOK(ST(1))) { + log_err("Collectd::plugin_register_%s(pluginname, subname): " + "Invalid subname", + desc); + XSRETURN_EMPTY; + } + + /* Use pluginname as-is to allow flush a single perl plugin */ + pluginname = SvPV_nolen(ST(0)); + + log_debug("Collectd::plugin_register_%s: " + "plugin = \"%s\", sub = \"%s\"", + desc, pluginname, SvPV_nolen(ST(1))); + + memset(&userdata, 0, sizeof(userdata)); + userdata.data = strdup(SvPV_nolen(ST(1))); + userdata.free_func = free; + + if (PLUGIN_READ == type) { + ret = plugin_register_complex_read( + "perl", /* group */ + pluginname, perl_read, plugin_get_interval(), /* Default interval */ + &userdata); + } else if (PLUGIN_WRITE == type) { + ret = plugin_register_write(pluginname, perl_write, &userdata); + } else if (PLUGIN_LOG == type) { + ret = plugin_register_log(pluginname, perl_log, &userdata); + } else if (PLUGIN_NOTIF == type) { + ret = plugin_register_notification(pluginname, perl_notify, &userdata); + } else if (PLUGIN_FLUSH == type) { + if (1 == register_legacy_flush) { /* For collectd-5.7 only, #1731 */ + register_legacy_flush = 0; + ret = plugin_register_flush("perl", perl_flush, /* user_data = */ NULL); + } + + if (0 == ret) + ret = plugin_register_flush(pluginname, perl_flush, &userdata); + } else { + ret = -1; + } + + if (0 == ret) + XSRETURN_YES; + else { + free(userdata.data); + XSRETURN_EMPTY; + } +} /* static void _plugin_register_generic_userdata ( ... ) */ + +/* + * Collectd::plugin_register_TYPE (pluginname, subname). + * + * pluginname: + * name of the perl plugin + * + * subname: + * name of the plugin's subroutine that does the work + */ + +static XS(Collectd_plugin_register_read) { + return _plugin_register_generic_userdata(aTHX, PLUGIN_READ, "read"); +} + +static XS(Collectd_plugin_register_write) { + return _plugin_register_generic_userdata(aTHX, PLUGIN_WRITE, "write"); +} + +static XS(Collectd_plugin_register_log) { + return _plugin_register_generic_userdata(aTHX, PLUGIN_LOG, "log"); +} + +static XS(Collectd_plugin_register_notification) { + return _plugin_register_generic_userdata(aTHX, PLUGIN_NOTIF, "notification"); +} + +static XS(Collectd_plugin_register_flush) { + return _plugin_register_generic_userdata(aTHX, PLUGIN_FLUSH, "flush"); +} + +typedef int perl_unregister_function_t(const char *name); + +static void _plugin_unregister_generic(pTHX, perl_unregister_function_t *unreg, + const char *desc) { + dXSARGS; + + if (1 != items) { + log_err("Usage: Collectd::plugin_unregister_%s(pluginname)", desc); + XSRETURN_EMPTY; + } + + if (!SvOK(ST(0))) { + log_err("Collectd::plugin_unregister_%s(pluginname): " + "Invalid pluginname", + desc); + XSRETURN_EMPTY; + } + + log_debug("Collectd::plugin_unregister_%s: plugin = \"%s\"", desc, + SvPV_nolen(ST(0))); + + unreg(SvPV_nolen(ST(0))); + + XSRETURN_EMPTY; + + return; +} /* static void _plugin_unregister_generic ( ... ) */ + +/* + * Collectd::plugin_unregister_TYPE (pluginname). + * + * TYPE: + * type of callback to be unregistered: read, write, log, notification, flush + * + * pluginname: + * name of the perl plugin + */ + +static XS(Collectd_plugin_unregister_read) { + return _plugin_unregister_generic(aTHX, plugin_unregister_read, "read"); +} + +static XS(Collectd_plugin_unregister_write) { + return _plugin_unregister_generic(aTHX, plugin_unregister_write, "write"); +} + +static XS(Collectd_plugin_unregister_log) { + return _plugin_unregister_generic(aTHX, plugin_unregister_log, "log"); +} + +static XS(Collectd_plugin_unregister_notification) { + return _plugin_unregister_generic(aTHX, plugin_unregister_notification, + "notification"); +} + +static XS(Collectd_plugin_unregister_flush) { + return _plugin_unregister_generic(aTHX, plugin_unregister_flush, "flush"); +} + /* * Collectd::plugin_register_data_set (type, dataset). * @@@ -2097,14 -1878,14 +2105,14 @@@ static int perl_init(void) assert(aTHX == perl_threads->head->interp); pthread_mutex_lock(&perl_threads->mutex); - status = pplugin_call_all(aTHX_ PLUGIN_INIT); + status = pplugin_call(aTHX_ PLUGIN_INIT); pthread_mutex_unlock(&perl_threads->mutex); return status; } /* static int perl_init (void) */ -static int perl_read(void) { +static int perl_read(user_data_t *user_data) { dTHX; if (NULL == perl_threads) @@@ -2127,12 -1908,11 +2135,12 @@@ log_debug("perl_read: c_ithread: interp = %p (active threads: %i)", aTHX, perl_threads->number_of_threads); - return pplugin_call_all(aTHX_ PLUGIN_READ); -} /* static int perl_read (void) */ + + return pplugin_call(aTHX_ PLUGIN_READ, user_data->data); +} /* static int perl_read (user_data_t *user_data) */ static int perl_write(const data_set_t *ds, const value_list_t *vl, - user_data_t __attribute__((unused)) * user_data) { + user_data_t *user_data) { int status; dTHX; @@@ -2157,7 -1937,7 +2165,7 @@@ log_debug("perl_write: c_ithread: interp = %p (active threads: %i)", aTHX, perl_threads->number_of_threads); - status = pplugin_call_all(aTHX_ PLUGIN_WRITE, ds, vl); + status = pplugin_call(aTHX_ PLUGIN_WRITE, user_data->data, ds, vl); if (aTHX == perl_threads->head->interp) pthread_mutex_unlock(&perl_threads->mutex); @@@ -2165,7 -1945,8 +2173,7 @@@ return status; } /* static int perl_write (const data_set_t *, const value_list_t *) */ -static void perl_log(int level, const char *msg, - user_data_t __attribute__((unused)) * user_data) { +static void perl_log(int level, const char *msg, user_data_t *user_data) { dTHX; if (NULL == perl_threads) @@@ -2189,7 -1970,7 +2197,7 @@@ if (aTHX == perl_threads->head->interp) pthread_mutex_lock(&perl_threads->mutex); - pplugin_call_all(aTHX_ PLUGIN_LOG, level, msg); + pplugin_call(aTHX_ PLUGIN_LOG, user_data->data, level, msg); if (aTHX == perl_threads->head->interp) pthread_mutex_unlock(&perl_threads->mutex); @@@ -2197,7 -1978,8 +2205,7 @@@ return; } /* static void perl_log (int, const char *) */ -static int perl_notify(const notification_t *notif, - user_data_t __attribute__((unused)) * user_data) { +static int perl_notify(const notification_t *notif, user_data_t *user_data) { dTHX; if (NULL == perl_threads) @@@ -2212,11 -1994,11 +2220,11 @@@ aTHX = t->interp; } - return pplugin_call_all(aTHX_ PLUGIN_NOTIF, notif); + return pplugin_call(aTHX_ PLUGIN_NOTIF, user_data->data, notif); } /* static int perl_notify (const notification_t *) */ static int perl_flush(cdtime_t timeout, const char *identifier, - user_data_t __attribute__((unused)) * user_data) { + user_data_t *user_data) { dTHX; if (NULL == perl_threads) @@@ -2231,12 -2013,7 +2239,12 @@@ aTHX = t->interp; } - return pplugin_call_all(aTHX_ PLUGIN_FLUSH, timeout, identifier); + + /* For collectd-5.6 only, #1731 */ + if (user_data == NULL || user_data->data == NULL) + return pplugin_call(aTHX_ PLUGIN_FLUSH_ALL, timeout, identifier); + + return pplugin_call(aTHX_ PLUGIN_FLUSH, user_data->data, timeout, identifier); } /* static int perl_flush (const int) */ static int perl_shutdown(void) { @@@ -2246,7 -2023,6 +2254,7 @@@ dTHX; plugin_unregister_complex_config("perl"); + plugin_unregister_read_group("perl"); if (NULL == perl_threads) return 0; @@@ -2262,10 -2038,14 +2270,10 @@@ log_debug("perl_shutdown: c_ithread: interp = %p (active threads: %i)", aTHX, perl_threads->number_of_threads); - plugin_unregister_log("perl"); - plugin_unregister_notification("perl"); plugin_unregister_init("perl"); - plugin_unregister_read("perl"); - plugin_unregister_write("perl"); - plugin_unregister_flush("perl"); + plugin_unregister_flush("perl"); /* For collectd-5.6 only, #1731 */ - ret = pplugin_call_all(aTHX_ PLUGIN_SHUTDOWN); + ret = pplugin_call(aTHX_ PLUGIN_SHUTDOWN); pthread_mutex_lock(&perl_threads->mutex); t = perl_threads->tail; @@@ -2468,7 -2248,15 +2476,7 @@@ static int init_pi(int argc, char **arg perl_run(aTHX); - plugin_register_log("perl", perl_log, /* user_data = */ NULL); - plugin_register_notification("perl", perl_notify, - /* user_data = */ NULL); plugin_register_init("perl", perl_init); - - plugin_register_read("perl", perl_read); - - plugin_register_write("perl", perl_write, /* user_data = */ NULL); - plugin_register_flush("perl", perl_flush, /* user_data = */ NULL); plugin_register_shutdown("perl", perl_shutdown); return 0; } /* static int init_pi (const char **, const int) */ @@@ -2678,8 -2466,6 +2686,8 @@@ static int perl_config(oconfig_item_t * current_status = perl_config_includedir(aTHX_ c); else if (0 == strcasecmp(c->key, "Plugin")) current_status = perl_config_plugin(aTHX_ c); + else if (0 == strcasecmp(c->key, "RegisterLegacyFlush")) + cf_util_get_boolean(c, ®ister_legacy_flush); else { log_warn("Ignoring unknown config key \"%s\".", c->key); current_status = 0;