Merge branch 'collectd-5.7' into collectd-5.8
[collectd.git] / src / utils_latency_config.c
1 /**
2  * collectd - src/utils_latency_config.c
3  * Copyright (C) 2013-2016   Florian octo 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 octo Forster <octo at collectd.org>
25  *   Pavel Rochnyack <pavel2000 at ngs.ru>
26  */
27
28 #include "utils_latency_config.h"
29 #include "common.h"
30 #include "collectd.h"
31
32 static int latency_config_add_percentile(latency_config_t *conf,
33                                          oconfig_item_t *ci,
34                                          const char *plugin) {
35   double percent;
36   int status = cf_util_get_double(ci, &percent);
37   if (status != 0)
38     return status;
39
40   if ((percent <= 0.0) || (percent >= 100)) {
41     ERROR("%s plugin: The value for \"%s\" must be between 0 and 100, "
42           "exclusively.",
43           plugin, ci->key);
44     return ERANGE;
45   }
46
47   double *tmp = realloc(conf->percentile,
48                         sizeof(*conf->percentile) * (conf->percentile_num + 1));
49   if (tmp == NULL) {
50     ERROR("%s plugin: realloc failed.", plugin);
51     return ENOMEM;
52   }
53   conf->percentile = tmp;
54   conf->percentile[conf->percentile_num] = percent;
55   conf->percentile_num++;
56
57   return 0;
58 } /* int latency_config_add_percentile */
59
60 static int latency_config_add_bucket(latency_config_t *conf, oconfig_item_t *ci,
61                                      const char *plugin) {
62   if ((ci->values_num != 2) || (ci->values[0].type != OCONFIG_TYPE_NUMBER) ||
63       (ci->values[1].type != OCONFIG_TYPE_NUMBER)) {
64     ERROR("%s plugin: \"%s\" requires exactly two numeric arguments.", plugin,
65           ci->key);
66     return EINVAL;
67   }
68
69   if (ci->values[1].value.number &&
70       ci->values[1].value.number <= ci->values[0].value.number) {
71     ERROR("%s plugin: MIN must be less than MAX in \"%s\".", plugin, ci->key);
72     return ERANGE;
73   }
74
75   if (ci->values[0].value.number < 0) {
76     ERROR("%s plugin: MIN must be greater then or equal to zero in \"%s\".",
77           plugin, ci->key);
78     return ERANGE;
79   }
80
81   latency_bucket_t *tmp =
82       realloc(conf->buckets, sizeof(*conf->buckets) * (conf->buckets_num + 1));
83   if (tmp == NULL) {
84     ERROR("%s plugin: realloc failed.", plugin);
85     return ENOMEM;
86   }
87   conf->buckets = tmp;
88   conf->buckets[conf->buckets_num].lower_bound =
89       DOUBLE_TO_CDTIME_T(ci->values[0].value.number);
90   conf->buckets[conf->buckets_num].upper_bound =
91       DOUBLE_TO_CDTIME_T(ci->values[1].value.number);
92   conf->buckets_num++;
93
94   return 0;
95 } /* int latency_config_add_bucket */
96
97 int latency_config(latency_config_t *conf, oconfig_item_t *ci,
98                    char const *plugin) {
99   int status = 0;
100
101   for (int i = 0; i < ci->children_num; i++) {
102     oconfig_item_t *child = ci->children + i;
103
104     if (strcasecmp("Percentile", child->key) == 0)
105       status = latency_config_add_percentile(conf, child, plugin);
106     else if (strcasecmp("Bucket", child->key) == 0)
107       status = latency_config_add_bucket(conf, child, plugin);
108     else if (strcasecmp("BucketType", child->key) == 0)
109       status = cf_util_get_string(child, &conf->bucket_type);
110     else
111       WARNING("%s plugin: \"%s\" is not a valid option within a \"%s\" block.",
112               plugin, child->key, ci->key);
113
114     if (status != 0)
115       return status;
116   }
117
118   if ((status == 0) && (conf->percentile_num == 0) &&
119       (conf->buckets_num == 0)) {
120     ERROR("%s plugin: The \"%s\" block must contain at least one "
121           "\"Percentile\" or \"Bucket\" option.",
122           plugin, ci->key);
123     return EINVAL;
124   }
125
126   return 0;
127 }
128
129 int latency_config_copy(latency_config_t *dst, const latency_config_t src) {
130   *dst = (latency_config_t){
131       .percentile_num = src.percentile_num, .buckets_num = src.buckets_num,
132   };
133
134   dst->percentile = calloc(dst->percentile_num, sizeof(*dst->percentile));
135   dst->buckets = calloc(dst->buckets_num, sizeof(*dst->buckets));
136
137   if ((dst->percentile == NULL) || (dst->buckets == NULL)) {
138     latency_config_free(*dst);
139     return ENOMEM;
140   }
141
142   if (src.bucket_type != NULL) {
143     dst->bucket_type = strdup(src.bucket_type);
144     if (dst->bucket_type == NULL) {
145       latency_config_free(*dst);
146       return ENOMEM;
147     }
148   }
149
150   memmove(dst->percentile, src.percentile,
151           dst->percentile_num * sizeof(*dst->percentile));
152   memmove(dst->buckets, src.buckets, dst->buckets_num * sizeof(*dst->buckets));
153
154   return 0;
155 } /* int latency_config_copy */
156
157 void latency_config_free(latency_config_t conf) {
158   sfree(conf.percentile);
159   sfree(conf.buckets);
160   sfree(conf.bucket_type);
161 } /* void latency_config_free */