treewide: add blank line below collectd.h
[collectd.git] / src / utils_curl_stats.c
1 /**
2  * collectd - src/utils_curl_stats.c
3  * Copyright (C) 2015       Sebastian 'tokkee' Harl
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  *   Sebastian Harl <sh@tokkee.org>
25  **/
26
27 #include "collectd.h"
28
29 #include "common.h"
30 #include "utils_curl_stats.h"
31
32 #include <stdbool.h>
33 #include <stddef.h>
34
35 struct curl_stats_s
36 {
37         bool total_time;
38         bool namelookup_time;
39         bool connect_time;
40         bool pretransfer_time;
41         bool size_upload;
42         bool size_download;
43         bool speed_download;
44         bool speed_upload;
45         bool header_size;
46         bool request_size;
47         bool content_length_download;
48         bool content_length_upload;
49         bool starttransfer_time;
50         bool redirect_time;
51         bool redirect_count;
52         bool num_connects;
53         bool appconnect_time;
54 };
55
56 /*
57  * Private functions
58  */
59
60 static int dispatch_gauge (CURL *curl, CURLINFO info, value_list_t *vl)
61 {
62         CURLcode code;
63         value_t v;
64
65         code = curl_easy_getinfo (curl, info, &v.gauge);
66         if (code != CURLE_OK)
67                 return -1;
68
69         vl->values = &v;
70         vl->values_len = 1;
71
72         return plugin_dispatch_values (vl);
73 } /* dispatch_gauge */
74
75 /* dispatch a speed, in bytes/second */
76 static int dispatch_speed (CURL *curl, CURLINFO info, value_list_t *vl)
77 {
78         CURLcode code;
79         value_t v;
80
81         code = curl_easy_getinfo (curl, info, &v.gauge);
82         if (code != CURLE_OK)
83                 return -1;
84
85         v.gauge *= 8;
86
87         vl->values = &v;
88         vl->values_len = 1;
89
90         return plugin_dispatch_values (vl);
91 } /* dispatch_speed */
92
93 /* dispatch a size/count, reported as a long value */
94 static int dispatch_size (CURL *curl, CURLINFO info, value_list_t *vl)
95 {
96         CURLcode code;
97         value_t v;
98         long raw;
99
100         code = curl_easy_getinfo (curl, info, &raw);
101         if (code != CURLE_OK)
102                 return -1;
103
104         v.gauge = (double)raw;
105
106         vl->values = &v;
107         vl->values_len = 1;
108
109         return plugin_dispatch_values (vl);
110 } /* dispatch_size */
111
112 static struct {
113         const char *name;
114         const char *config_key;
115         size_t offset;
116
117         int (*dispatcher)(CURL *, CURLINFO, value_list_t *);
118         const char *type;
119         CURLINFO info;
120 } field_specs[] = {
121 #define SPEC(name, config_key, dispatcher, type, info) \
122         { #name, config_key, offsetof (curl_stats_t, name), dispatcher, type, info }
123
124         SPEC (total_time,              "TotalTime",              dispatch_gauge, "duration", CURLINFO_TOTAL_TIME),
125         SPEC (namelookup_time,         "NamelookupTime",         dispatch_gauge, "duration", CURLINFO_NAMELOOKUP_TIME),
126         SPEC (connect_time,            "ConnectTime",            dispatch_gauge, "duration", CURLINFO_CONNECT_TIME),
127         SPEC (pretransfer_time,        "PretransferTime",        dispatch_gauge, "duration", CURLINFO_PRETRANSFER_TIME),
128         SPEC (size_upload,             "SizeUpload",             dispatch_gauge, "bytes",    CURLINFO_SIZE_UPLOAD),
129         SPEC (size_download,           "SizeDownload",           dispatch_gauge, "bytes",    CURLINFO_SIZE_DOWNLOAD),
130         SPEC (speed_download,          "SpeedDownload",          dispatch_speed, "bitrate",  CURLINFO_SPEED_DOWNLOAD),
131         SPEC (speed_upload,            "SpeedUpload",            dispatch_speed, "bitrate",  CURLINFO_SPEED_UPLOAD),
132         SPEC (header_size,             "HeaderSize",             dispatch_size,  "bytes",    CURLINFO_HEADER_SIZE),
133         SPEC (request_size,            "RequestSize",            dispatch_size,  "bytes",    CURLINFO_REQUEST_SIZE),
134         SPEC (content_length_download, "ContentLengthDownload",  dispatch_gauge, "bytes",    CURLINFO_CONTENT_LENGTH_DOWNLOAD),
135         SPEC (content_length_upload,   "ContentLengthUpload",    dispatch_gauge, "bytes",    CURLINFO_CONTENT_LENGTH_UPLOAD),
136         SPEC (starttransfer_time,      "StarttransferTime",      dispatch_gauge, "duration", CURLINFO_STARTTRANSFER_TIME),
137         SPEC (redirect_time,           "RedirectTime",           dispatch_gauge, "duration", CURLINFO_REDIRECT_TIME),
138         SPEC (redirect_count,          "RedirectCount",          dispatch_size,  "count",    CURLINFO_REDIRECT_COUNT),
139         SPEC (num_connects,            "NumConnects",            dispatch_size,  "count",    CURLINFO_NUM_CONNECTS),
140 #ifdef HAVE_CURLINFO_APPCONNECT_TIME
141         SPEC (appconnect_time,         "AppconnectTime",         dispatch_gauge, "duration", CURLINFO_APPCONNECT_TIME),
142 #endif
143
144 #undef SPEC
145 };
146
147 static void enable_field (curl_stats_t *s, size_t offset)
148 {
149         *(bool *)((char *)s + offset) = true;
150 } /* enable_field */
151
152 static bool field_enabled (curl_stats_t *s, size_t offset)
153 {
154         return *(bool *)((char *)s + offset);
155 } /* field_enabled */
156
157 /*
158  * Public API
159  */
160 curl_stats_t *curl_stats_from_config (oconfig_item_t *ci)
161 {
162         curl_stats_t *s;
163         int i;
164
165         if (ci == NULL)
166                 return NULL;
167
168         s = calloc (1, sizeof (*s));
169         if (s == NULL)
170                 return NULL;
171
172         for (i = 0; i < ci->children_num; ++i)
173         {
174                 oconfig_item_t *c = ci->children + i;
175                 size_t field;
176
177                 _Bool enabled = 0;
178
179                 for (field = 0; field < STATIC_ARRAY_SIZE (field_specs); ++field) {
180                         if (! strcasecmp (c->key, field_specs[field].config_key))
181                                 break;
182                         if (! strcasecmp (c->key, field_specs[field].name))
183                                 break;
184                 }
185                 if (field >= STATIC_ARRAY_SIZE (field_specs))
186                 {
187                         ERROR ("curl stats: Unknown field name %s", c->key);
188                         free (s);
189                         return NULL;
190                 }
191
192
193                 if (cf_util_get_boolean (c, &enabled) != 0) {
194                         free (s);
195                         return NULL;
196                 }
197                 if (enabled)
198                         enable_field (s, field_specs[field].offset);
199         }
200
201         return s;
202 } /* curl_stats_from_config */
203
204 void curl_stats_destroy (curl_stats_t *s)
205 {
206         if (s != NULL)
207                 free (s);
208 } /* curl_stats_destroy */
209
210 int curl_stats_dispatch (curl_stats_t *s, CURL *curl,
211                 const char *hostname, const char *plugin, const char *plugin_instance)
212 {
213         value_list_t vl = VALUE_LIST_INIT;
214         size_t field;
215
216         if (s == NULL)
217                 return 0;
218         if ((curl == NULL) || (hostname == NULL) || (plugin == NULL))
219         {
220                 ERROR ("curl stats: dispatch() called with missing arguments "
221                                 "(curl=%p; hostname=%s; plugin=%s)", curl,
222                                 hostname == NULL ? "<NULL>" : hostname,
223                                 plugin == NULL ? "<NULL>" : plugin);
224                 return -1;
225         }
226
227         sstrncpy (vl.host, hostname, sizeof (vl.host));
228         sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
229         if (plugin_instance != NULL)
230                 sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
231
232         for (field = 0; field < STATIC_ARRAY_SIZE (field_specs); ++field)
233         {
234                 int status;
235
236                 if (! field_enabled (s, field_specs[field].offset))
237                         continue;
238
239                 sstrncpy (vl.type, field_specs[field].type, sizeof (vl.type));
240                 sstrncpy (vl.type_instance, field_specs[field].name, sizeof (vl.type_instance));
241
242                 vl.values = NULL;
243                 vl.values_len = 0;
244                 status = field_specs[field].dispatcher (curl, field_specs[field].info, &vl);
245                 if (status < 0)
246                         return status;
247         }
248
249         return 0;
250 } /* curl_stats_dispatch */