void latency_counter_add (latency_counter_t *lc, cdtime_t latency) /* {{{ */ { size_t latency_ms; if ((lc == NULL) || (latency == 0)) return; lc->sum += latency; lc->num++; if ((lc->min == 0) && (lc->max == 0)) lc->min = lc->max = latency; if (lc->min > latency) lc->min = latency; if (lc->max < latency) lc->max = latency; /* A latency of _exactly_ 1.0 ms should be stored in the buffer 0, so * subtract one from the cdtime_t value so that exactly 1.0 ms get sorted * accordingly. */ latency_ms = (size_t) CDTIME_T_TO_MS (latency - 1); if (latency_ms < STATIC_ARRAY_SIZE (lc->histogram)) lc->histogram[latency_ms]++; } /* }}} void latency_counter_add */
static int cc_page_init_curl (web_page_t *wp) /* {{{ */ { wp->curl = curl_easy_init (); if (wp->curl == NULL) { ERROR ("curl plugin: curl_easy_init failed."); return (-1); } curl_easy_setopt (wp->curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (wp->curl, CURLOPT_WRITEFUNCTION, cc_curl_callback); curl_easy_setopt (wp->curl, CURLOPT_WRITEDATA, wp); curl_easy_setopt (wp->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT); curl_easy_setopt (wp->curl, CURLOPT_ERRORBUFFER, wp->curl_errbuf); curl_easy_setopt (wp->curl, CURLOPT_URL, wp->url); curl_easy_setopt (wp->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt (wp->curl, CURLOPT_MAXREDIRS, 50L); if (wp->user != NULL) { #ifdef HAVE_CURLOPT_USERNAME curl_easy_setopt (wp->curl, CURLOPT_USERNAME, wp->user); curl_easy_setopt (wp->curl, CURLOPT_PASSWORD, (wp->pass == NULL) ? "" : wp->pass); #else size_t credentials_size; credentials_size = strlen (wp->user) + 2; if (wp->pass != NULL) credentials_size += strlen (wp->pass); wp->credentials = malloc (credentials_size); if (wp->credentials == NULL) { ERROR ("curl plugin: malloc failed."); return (-1); } ssnprintf (wp->credentials, credentials_size, "%s:%s", wp->user, (wp->pass == NULL) ? "" : wp->pass); curl_easy_setopt (wp->curl, CURLOPT_USERPWD, wp->credentials); #endif if (wp->digest) curl_easy_setopt (wp->curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); } curl_easy_setopt (wp->curl, CURLOPT_SSL_VERIFYPEER, (long) wp->verify_peer); curl_easy_setopt (wp->curl, CURLOPT_SSL_VERIFYHOST, wp->verify_host ? 2L : 0L); if (wp->cacert != NULL) curl_easy_setopt (wp->curl, CURLOPT_CAINFO, wp->cacert); if (wp->headers != NULL) curl_easy_setopt (wp->curl, CURLOPT_HTTPHEADER, wp->headers); if (wp->post_body != NULL) curl_easy_setopt (wp->curl, CURLOPT_POSTFIELDS, wp->post_body); #ifdef HAVE_CURLOPT_TIMEOUT_MS if (wp->timeout >= 0) curl_easy_setopt (wp->curl, CURLOPT_TIMEOUT_MS, (long) wp->timeout); else curl_easy_setopt (wp->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval())); #endif return (0); } /* }}} int cc_page_init_curl */
static int memcached_query_daemon (char *buffer, int buffer_size) /* {{{ */ { int fd; ssize_t status; int buffer_fill; int i = 0; if (memcached_socket != NULL) { struct sockaddr_un serv_addr; memset (&serv_addr, 0, sizeof (serv_addr)); serv_addr.sun_family = AF_UNIX; sstrncpy (serv_addr.sun_path, memcached_socket, sizeof (serv_addr.sun_path)); /* create our socket descriptor */ fd = socket (AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { char errbuf[1024]; ERROR ("memcached: unix socket: %s", sstrerror (errno, errbuf, sizeof (errbuf))); return -1; } /* connect to the memcached daemon */ status = (ssize_t) connect (fd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)); if (status != 0) { shutdown (fd, SHUT_RDWR); close (fd); fd = -1; } } else { /* if (memcached_socket == NULL) */ const char *host; const char *port; struct addrinfo ai_hints; struct addrinfo *ai_list, *ai_ptr; int ai_return = 0; memset (&ai_hints, '\0', sizeof (ai_hints)); ai_hints.ai_flags = 0; #ifdef AI_ADDRCONFIG /* ai_hints.ai_flags |= AI_ADDRCONFIG; */ #endif ai_hints.ai_family = AF_INET; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = 0; host = memcached_host; if (host == NULL) { host = MEMCACHED_DEF_HOST; } port = memcached_port; if (strlen (port) == 0) { port = MEMCACHED_DEF_PORT; } if ((ai_return = getaddrinfo (host, port, &ai_hints, &ai_list)) != 0) { char errbuf[1024]; ERROR ("memcached: getaddrinfo (%s, %s): %s", host, port, (ai_return == EAI_SYSTEM) ? sstrerror (errno, errbuf, sizeof (errbuf)) : gai_strerror (ai_return)); return -1; } fd = -1; for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) { /* create our socket descriptor */ fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); if (fd < 0) { char errbuf[1024]; ERROR ("memcached: socket: %s", sstrerror (errno, errbuf, sizeof (errbuf))); continue; } /* connect to the memcached daemon */ status = (ssize_t) connect (fd, (struct sockaddr *) ai_ptr->ai_addr, ai_ptr->ai_addrlen); if (status != 0) { shutdown (fd, SHUT_RDWR); close (fd); fd = -1; continue; } /* A socket could be opened and connecting succeeded. We're * done. */ break; } freeaddrinfo (ai_list); } if (fd < 0) { ERROR ("memcached: Could not connect to daemon."); return -1; } if (send(fd, "stats\r\n", sizeof("stats\r\n") - 1, MSG_DONTWAIT) != (sizeof("stats\r\n") - 1)) { ERROR ("memcached: Could not send command to the memcached daemon."); return -1; } { struct pollfd p; int status; memset (&p, 0, sizeof (p)); p.fd = fd; p.events = POLLIN | POLLERR | POLLHUP; p.revents = 0; status = poll (&p, /* nfds = */ 1, /* timeout = */ CDTIME_T_TO_MS (interval_g)); if (status <= 0) { if (status == 0) { ERROR ("memcached: poll(2) timed out after %.3f seconds.", CDTIME_T_TO_DOUBLE (interval_g)); } else { char errbuf[1024]; ERROR ("memcached: poll(2) failed: %s", sstrerror (errno, errbuf, sizeof (errbuf))); } shutdown (fd, SHUT_RDWR); close (fd); return (-1); } } /* receive data from the memcached daemon */ memset (buffer, '\0', buffer_size); buffer_fill = 0; while ((status = recv (fd, buffer + buffer_fill, buffer_size - buffer_fill, MSG_DONTWAIT)) != 0) { if (i > MEMCACHED_RETRY_COUNT) { ERROR("recv() timed out"); break; } i++; if (status == -1) { char errbuf[1024]; if (errno == EAGAIN) { continue; } ERROR ("memcached: Error reading from socket: %s", sstrerror (errno, errbuf, sizeof (errbuf))); shutdown(fd, SHUT_RDWR); close (fd); return -1; } buffer_fill += status; if (buffer_fill > 3 && buffer[buffer_fill-5] == 'E' && buffer[buffer_fill-4] == 'N' && buffer[buffer_fill-3] == 'D') { /* we got all the data */ break; } } if (buffer_fill >= buffer_size) { buffer[buffer_size - 1] = '\0'; WARNING ("memcached: Message from memcached has been truncated."); } else if (buffer_fill == 0) { WARNING ("memcached: Peer has unexpectedly shut down the socket. " "Buffer: `%s'", buffer); shutdown(fd, SHUT_RDWR); close(fd); return -1; } shutdown(fd, SHUT_RDWR); close(fd); return 0; }
static int dns_run_pcap_loop (void) { pcap_t *pcap_obj; char pcap_error[PCAP_ERRBUF_SIZE]; struct bpf_program fp = { 0 }; int status; /* Don't block any signals */ { sigset_t sigmask; sigemptyset (&sigmask); pthread_sigmask (SIG_SETMASK, &sigmask, NULL); } /* Passing `pcap_device == NULL' is okay and the same as passign "any" */ DEBUG ("dns plugin: Creating PCAP object.."); pcap_obj = pcap_open_live ((pcap_device != NULL) ? pcap_device : "any", PCAP_SNAPLEN, 0 /* Not promiscuous */, (int) CDTIME_T_TO_MS (plugin_get_interval () / 2), pcap_error); if (pcap_obj == NULL) { ERROR ("dns plugin: Opening interface `%s' " "failed: %s", (pcap_device != NULL) ? pcap_device : "any", pcap_error); return (PCAP_ERROR); } status = pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0); if (status < 0) { ERROR ("dns plugin: pcap_compile failed: %s", pcap_statustostr (status)); return (status); } status = pcap_setfilter (pcap_obj, &fp); if (status < 0) { ERROR ("dns plugin: pcap_setfilter failed: %s", pcap_statustostr (status)); return (status); } DEBUG ("dns plugin: PCAP object created."); dnstop_set_pcap_obj (pcap_obj); dnstop_set_callback (dns_child_callback); status = pcap_loop (pcap_obj, -1 /* loop forever */, handle_pcap /* callback */, NULL /* user data */); INFO ("dns plugin: pcap_loop exited with status %i.", status); /* We need to handle "PCAP_ERROR" specially because libpcap currently * doesn't return PCAP_ERROR_IFACE_NOT_UP for compatibility reasons. */ if (status == PCAP_ERROR) status = PCAP_ERROR_IFACE_NOT_UP; pcap_close (pcap_obj); return (status); } /* int dns_run_pcap_loop */
/* * Functions */ static bson *wm_create_bson (const data_set_t *ds, /* {{{ */ const value_list_t *vl, _Bool store_rates) { bson *ret; gauge_t *rates; ret = bson_alloc (); /* matched by bson_dealloc() */ if (ret == NULL) { ERROR ("write_mongodb plugin: bson_create failed."); return (NULL); } if (store_rates) { rates = uc_get_rate (ds, vl); if (rates == NULL) { ERROR ("write_mongodb plugin: uc_get_rate() failed."); return (NULL); } } else { rates = NULL; } bson_init (ret); /* matched by bson_destroy() */ bson_append_date (ret, "time", (bson_date_t) CDTIME_T_TO_MS (vl->time)); bson_append_string (ret, "host", vl->host); bson_append_string (ret, "plugin", vl->plugin); bson_append_string (ret, "plugin_instance", vl->plugin_instance); bson_append_string (ret, "type", vl->type); bson_append_string (ret, "type_instance", vl->type_instance); bson_append_start_array (ret, "values"); /* {{{ */ for (int i = 0; i < ds->ds_num; i++) { char key[16]; ssnprintf (key, sizeof (key), "%i", i); if (ds->ds[i].type == DS_TYPE_GAUGE) bson_append_double(ret, key, vl->values[i].gauge); else if (store_rates) bson_append_double(ret, key, (double) rates[i]); else if (ds->ds[i].type == DS_TYPE_COUNTER) bson_append_long(ret, key, vl->values[i].counter); else if (ds->ds[i].type == DS_TYPE_DERIVE) bson_append_long(ret, key, vl->values[i].derive); else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) bson_append_long(ret, key, vl->values[i].absolute); else assert (23 == 42); } bson_append_finish_array (ret); /* }}} values */ bson_append_start_array (ret, "dstypes"); /* {{{ */ for (int i = 0; i < ds->ds_num; i++) { char key[16]; ssnprintf (key, sizeof (key), "%i", i); if (store_rates) bson_append_string (ret, key, "gauge"); else bson_append_string (ret, key, DS_TYPE_TO_STRING (ds->ds[i].type)); } bson_append_finish_array (ret); /* }}} dstypes */ bson_append_start_array (ret, "dsnames"); /* {{{ */ for (int i = 0; i < ds->ds_num; i++) { char key[16]; ssnprintf (key, sizeof (key), "%i", i); bson_append_string (ret, key, ds->ds[i].name); } bson_append_finish_array (ret); /* }}} dsnames */ bson_finish (ret); sfree (rates); return (ret); } /* }}} bson *wm_create_bson */
static int values_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */ const data_set_t *ds, const value_list_t *vl, int store_rates, size_t ds_idx) { size_t offset = 0; gauge_t *rates = NULL; memset(buffer, 0, buffer_size); #define BUFFER_ADD(...) \ do { \ int status; \ status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) { \ sfree(rates); \ return -1; \ } else if (((size_t)status) >= (buffer_size - offset)) { \ sfree(rates); \ return -ENOMEM; \ } else \ offset += ((size_t)status); \ } while (0) if (ds->ds[ds_idx].type == DS_TYPE_GAUGE) { if (isfinite(vl->values[ds_idx].gauge)) { BUFFER_ADD("[["); BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time)); BUFFER_ADD(","); BUFFER_ADD(JSON_GAUGE_FORMAT, vl->values[ds_idx].gauge); } else { DEBUG("utils_format_kairosdb: invalid vl->values[ds_idx].gauge for " "%s|%s|%s|%s|%s", vl->plugin, vl->plugin_instance, vl->type, vl->type_instance, ds->ds[ds_idx].name); return -1; } } else if (store_rates) { if (rates == NULL) rates = uc_get_rate(ds, vl); if (rates == NULL) { WARNING("utils_format_kairosdb: uc_get_rate failed for %s|%s|%s|%s|%s", vl->plugin, vl->plugin_instance, vl->type, vl->type_instance, ds->ds[ds_idx].name); return -1; } if (isfinite(rates[ds_idx])) { BUFFER_ADD("[["); BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time)); BUFFER_ADD(","); BUFFER_ADD(JSON_GAUGE_FORMAT, rates[ds_idx]); } else { WARNING("utils_format_kairosdb: invalid rates[ds_idx] for %s|%s|%s|%s|%s", vl->plugin, vl->plugin_instance, vl->type, vl->type_instance, ds->ds[ds_idx].name); sfree(rates); return -1; } } else if (ds->ds[ds_idx].type == DS_TYPE_COUNTER) { BUFFER_ADD("[["); BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time)); BUFFER_ADD(","); BUFFER_ADD("%" PRIu64, (uint64_t)vl->values[ds_idx].counter); } else if (ds->ds[ds_idx].type == DS_TYPE_DERIVE) { BUFFER_ADD("[["); BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time)); BUFFER_ADD(","); BUFFER_ADD("%" PRIi64, vl->values[ds_idx].derive); } else if (ds->ds[ds_idx].type == DS_TYPE_ABSOLUTE) { BUFFER_ADD("[["); BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time)); BUFFER_ADD(","); BUFFER_ADD("%" PRIu64, vl->values[ds_idx].absolute); } else { ERROR("format_kairosdb: Unknown data source type: %i", ds->ds[ds_idx].type); sfree(rates); return -1; } BUFFER_ADD("]]"); #undef BUFFER_ADD DEBUG("format_kairosdb: values_to_kairosdb: buffer = %s;", buffer); sfree(rates); return 0; } /* }}} int values_to_kairosdb */
/* initialize curl for each host */ static int init_host (apache_t *st) /* {{{ */ { assert (st->url != NULL); /* (Assured by `config_add') */ if (st->curl != NULL) { curl_easy_cleanup (st->curl); st->curl = NULL; } if ((st->curl = curl_easy_init ()) == NULL) { ERROR ("apache plugin: init_host: `curl_easy_init' failed."); return (-1); } curl_easy_setopt (st->curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (st->curl, CURLOPT_WRITEFUNCTION, apache_curl_callback); curl_easy_setopt (st->curl, CURLOPT_WRITEDATA, st); /* not set as yet if the user specified string doesn't match apache or * lighttpd, then ignore it. Headers will be parsed to find out the * server type */ st->server_type = -1; if (st->server != NULL) { if (strcasecmp(st->server, "apache") == 0) st->server_type = APACHE; else if (strcasecmp(st->server, "lighttpd") == 0) st->server_type = LIGHTTPD; else if (strcasecmp(st->server, "ibm_http_server") == 0) st->server_type = APACHE; else WARNING ("apache plugin: Unknown `Server' setting: %s", st->server); } /* if not found register a header callback to determine the server_type */ if (st->server_type == -1) { curl_easy_setopt (st->curl, CURLOPT_HEADERFUNCTION, apache_header_callback); curl_easy_setopt (st->curl, CURLOPT_WRITEHEADER, st); } curl_easy_setopt (st->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT); curl_easy_setopt (st->curl, CURLOPT_ERRORBUFFER, st->apache_curl_error); if (st->user != NULL) { #ifdef HAVE_CURLOPT_USERNAME curl_easy_setopt (st->curl, CURLOPT_USERNAME, st->user); curl_easy_setopt (st->curl, CURLOPT_PASSWORD, (st->pass == NULL) ? "" : st->pass); #else static char credentials[1024]; int status; status = ssnprintf (credentials, sizeof (credentials), "%s:%s", st->user, (st->pass == NULL) ? "" : st->pass); if ((status < 0) || ((size_t) status >= sizeof (credentials))) { ERROR ("apache plugin: init_host: Returning an error " "because the credentials have been " "truncated."); curl_easy_cleanup (st->curl); st->curl = NULL; return (-1); } curl_easy_setopt (st->curl, CURLOPT_USERPWD, credentials); #endif } curl_easy_setopt (st->curl, CURLOPT_URL, st->url); curl_easy_setopt (st->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt (st->curl, CURLOPT_MAXREDIRS, 50L); curl_easy_setopt (st->curl, CURLOPT_SSL_VERIFYPEER, (long) st->verify_peer); curl_easy_setopt (st->curl, CURLOPT_SSL_VERIFYHOST, st->verify_host ? 2L : 0L); if (st->cacert != NULL) curl_easy_setopt (st->curl, CURLOPT_CAINFO, st->cacert); if (st->ssl_ciphers != NULL) curl_easy_setopt (st->curl, CURLOPT_SSL_CIPHER_LIST,st->ssl_ciphers); #ifdef HAVE_CURLOPT_TIMEOUT_MS if (st->timeout >= 0) curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS, (long) st->timeout); else curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval())); #endif return (0); } /* }}} int init_host */