27 #ifdef HAVE_COLLECTDC_H
28 #include <collectd/client.h>
29 #include <freeradius-devel/radsniff.h>
54 static void _copy_double_to_double(
UNUSED rs_t *
conf, rs_stats_value_tmpl_t *tmpl)
59 *((
double *) tmpl->dst) = *((
double*) tmpl->src);
79 static rs_stats_tmpl_t *rs_stats_collectd_init(TALLOC_CTX *ctx,
rs_t *
conf,
80 char const *plugin_instance,
81 char const *type,
char const *type_instance,
83 rs_stats_value_tmpl_t
const *values)
86 static char fqdn[LCC_NAME_LEN];
92 rs_stats_tmpl_t *tmpl;
93 lcc_value_list_t *value;
97 assert(type_instance);
99 for (len = 0; values[len].src; len++) {} ;
107 struct addrinfo hints, *info = NULL;
109 if (gethostname(hostname,
sizeof(hostname)) < 0) {
115 memset(&hints, 0,
sizeof hints);
116 hints.ai_family = AF_UNSPEC;
117 hints.ai_socktype = SOCK_STREAM;
118 hints.ai_flags = AI_CANONNAME;
120 if ((ret =
getaddrinfo(hostname,
"radius", &hints, &info)) != 0) {
125 strlcpy(fqdn, info->ai_canonname,
sizeof(fqdn));
130 tmpl = talloc_zero(ctx, rs_stats_tmpl_t);
135 tmpl->value_tmpl = talloc_zero_array(tmpl, rs_stats_value_tmpl_t, len);
136 if (!tmpl->value_tmpl) {
142 value = talloc_zero(tmpl, lcc_value_list_t);
148 value->interval = conf->
stats.interval;
149 value->values_len = len;
151 value->values_types = talloc_zero_array(value,
int, len);
152 if (!value->values_types) {
156 value->values = talloc_zero_array(value, value_t, len);
157 if (!value->values) {
161 for (i = 0; i < (int) len; i++) {
162 assert(values[i].src);
163 assert(values[i].cb);
165 tmpl->value_tmpl[i] = values[i];
166 switch (tmpl->value_tmpl[i].type) {
167 case LCC_TYPE_COUNTER:
168 tmpl->value_tmpl[i].dst = &value->values[i].counter;
172 tmpl->value_tmpl[i].dst = &value->values[i].gauge;
175 case LCC_TYPE_DERIVE:
176 tmpl->value_tmpl[i].dst = &value->values[i].derive;
179 case LCC_TYPE_ABSOLUTE:
180 tmpl->value_tmpl[i].dst = &value->values[i].absolute;
186 value->values_types[i] = tmpl->value_tmpl[i].type;
192 strlcpy(value->identifier.host, fqdn,
sizeof(value->identifier.host));
197 fr_snprint(value->identifier.plugin,
sizeof(value->identifier.plugin),
198 conf->
stats.prefix, strlen(conf->
stats.prefix),
'\0');
199 for (p = value->identifier.plugin; *p; ++p) {
200 if ((*p ==
'-') || (*p ==
'/'))*p =
'_';
206 fr_snprint(value->identifier.plugin_instance,
sizeof(value->identifier.plugin_instance),
207 plugin_instance, strlen(plugin_instance),
'\0');
208 for (p = value->identifier.plugin_instance; *p; ++p) {
209 if ((*p ==
'-') || (*p ==
'/')) *p =
'_';
215 fr_snprint(value->identifier.type,
sizeof(value->identifier.type),
216 type, strlen(type),
'\0');
217 for (p = value->identifier.type; *p; ++p) {
218 if ((*p ==
'-') || (*p ==
'/')) *p =
'_';
221 fr_snprint(value->identifier.type_instance,
sizeof(value->identifier.type_instance),
222 type_instance, strlen(type_instance),
'\0');
223 for (p = value->identifier.type_instance; *p; ++p) {
224 if ((*p ==
'-') || (*p ==
'/')) *p =
'_';
239 rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out,
rs_t *conf,
242 rs_stats_tmpl_t **tmpl, *last;
244 char buffer[LCC_NAME_LEN];
251 rs_stats_value_tmpl_t
const _packet_count[] = {
252 { &stats->
interval.received, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
253 { &stats->
interval.linked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
254 { &stats->
interval.unlinked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
255 { &stats->
interval.reused, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
256 { NULL, 0, NULL, NULL }
259 rs_stats_value_tmpl_t
const _latency[] = {
261 { &stats->
interval.latency_average, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
262 { &stats->
interval.latency_high, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
263 { &stats->
interval.latency_low, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
264 { NULL, 0, NULL, NULL }
267 #define INIT_STATS(_ti, _v) do {\
268 strlcpy(buffer, fr_packet_codes[code], sizeof(buffer)); \
269 for (p = buffer; *p; ++p) *p = tolower(*p);\
270 last = *tmpl = rs_stats_collectd_init(ctx, conf, type, _ti, buffer, stats, _v);\
275 tmpl = &(*tmpl)->next;\
280 INIT_STATS(
"radius_count", _packet_count);
281 INIT_STATS(
"radius_latency", _latency);
284 rtx[i].src = &stats->
interval.rt[i];
285 rtx[i].type = LCC_TYPE_GAUGE;
286 rtx[i].cb = _copy_double_to_double;
291 rtx[i].type = LCC_TYPE_GAUGE;
292 rtx[i].cb = _copy_double_to_double;
295 memset(&rtx[++i], 0,
sizeof(rs_stats_value_tmpl_t));
297 INIT_STATS(
"radius_rtx", rtx);
305 void rs_stats_collectd_do_stats(
rs_t *conf, rs_stats_tmpl_t *tmpls,
struct timeval *now)
307 rs_stats_tmpl_t *tmpl = tmpls;
308 char identifier[6 * LCC_NAME_LEN];
315 for (i = 0; i < (int) tmpl->value->values_len; i++) {
316 tmpl->value_tmpl[i].cb(conf, &tmpl->value_tmpl[i]);
319 tmpl->value->time = now->tv_sec;
321 lcc_identifier_to_string(conf->
stats.handle, identifier,
sizeof(identifier), &tmpl->value->identifier);
323 if (lcc_putval(conf->
stats.handle, tmpl->value) < 0) {
326 error = lcc_strerror(conf->
stats.handle);
327 ERROR(
"Failed PUTVAL \"%s\" interval=%i %" PRIu64
" : %s",
329 (
int) tmpl->value->interval,
330 (uint64_t) tmpl->value->time,
331 error ? error :
"unknown error");
345 int rs_stats_collectd_open(
rs_t *conf)
347 assert(conf->
stats.collectd);
352 rs_stats_collectd_close(conf);
358 if (lcc_connect(conf->
stats.collectd, &conf->
stats.handle) < 0) {
362 DEBUG2(
"Connected to \"%s\"", conf->
stats.collectd);
364 assert(conf->
stats.handle);
375 int rs_stats_collectd_close(
rs_t *conf)
377 assert(conf->
stats.collectd);
381 if (conf->
stats.handle) {
382 ret = lcc_disconnect(conf->
stats.handle);
383 conf->
stats.handle = NULL;
char const * gai_strerror(int ecode)
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
struct rs_latency::@8 interval
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
void freeaddrinfo(struct addrinfo *ai)
#define RS_RETRANSMIT_MAX
Maximum number of times we expect to see a packet retransmitted.
double latency_smoothed
Smoothed moving average.
size_t strlcpy(char *dst, char const *src, size_t siz)
PW_CODE
RADIUS packet codes.
int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
Stats for a single interval.