/**
* collectd - src/memcached.c, based on src/hddtemp.c
- * Copyright (C) 2007 Antony Dovgal
- * Copyright (C) 2005,2006 Vincent Stehlé
+ * Copyright (C) 2007 Antony Dovgal
+ * Copyright (C) 2007-2009 Florian Forster
+ * Copyright (C) 2009 Doug MacEachern
+ * Copyright (C) 2009 Franck Lombardi
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
*
* Authors:
* Antony Dovgal <tony at daylessday dot org>
- * Vincent Stehlé <vincent.stehle at free.fr>
* Florian octo Forster <octo at verplant.org>
+ * Doug MacEachern <dougm at hyperic.com>
+ * Franck Lombardi
**/
#include "collectd.h"
# include <poll.h>
# include <netdb.h>
# include <sys/socket.h>
+# include <sys/un.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
static const char *config_keys[] =
{
+ "Socket",
"Host",
"Port"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+static char *memcached_socket = NULL;
static char *memcached_host = NULL;
static char memcached_port[16];
int fd;
ssize_t status;
int buffer_fill;
+ int i = 0;
- const char *host;
- const char *port;
+ if (memcached_socket != NULL) {
+ struct sockaddr_un serv_addr;
- struct addrinfo ai_hints;
- struct addrinfo *ai_list, *ai_ptr;
- int ai_return, i = 0;
+ 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));
- 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;
+ /* 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;
+ }
- host = memcached_host;
- if (host == NULL) {
- host = MEMCACHED_DEF_HOST;
+ /* 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;
- port = memcached_port;
- if (strlen (port) == 0) {
- port = MEMCACHED_DEF_PORT;
- }
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list, *ai_ptr;
+ int ai_return = 0;
- if ((ai_return = getaddrinfo (host, port, NULL, &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;
- }
+ 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;
- fd = -1;
- for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
- /* create our socket descriptor */
- if ((fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->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, NULL, &ai_list)) != 0) {
char errbuf[1024];
- ERROR ("memcached: socket: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
- continue;
+ ERROR ("memcached: getaddrinfo (%s, %s): %s",
+ host, port,
+ (ai_return == EAI_SYSTEM)
+ ? sstrerror (errno, errbuf, sizeof (errbuf))
+ : gai_strerror (ai_return));
+ return -1;
}
- /* connect to the memcached daemon */
- if (connect (fd, (struct sockaddr *) ai_ptr->ai_addr, ai_ptr->ai_addrlen)) {
- shutdown(fd, SHUT_RDWR);
- close(fd);
- fd = -1;
- continue;
+ 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;
}
- /* A socket could be opened and connecting succeeded. We're
- * done. */
- break;
+ freeaddrinfo (ai_list);
}
- freeaddrinfo (ai_list);
-
if (fd < 0) {
ERROR ("memcached: Could not connect to daemon.");
return -1;
static int memcached_config (const char *key, const char *value) /* {{{ */
{
- if (strcasecmp (key, "Host") == 0) {
+ if (strcasecmp (key, "Socket") == 0) {
+ if (memcached_socket != NULL) {
+ free (memcached_socket);
+ }
+ memcached_socket = strdup (value);
+ } else if (strcasecmp (key, "Host") == 0) {
if (memcached_host != NULL) {
free (memcached_host);
}
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
gauge_t bytes_used = NAN;
gauge_t bytes_total = NAN;
+ gauge_t hits = NAN;
+ gauge_t gets = NAN;
counter_t rusage_user = 0;
counter_t rusage_syst = 0;
counter_t octets_rx = 0;
#define FIELD_IS(cnst) \
(((sizeof(cnst) - 1) == name_len) && (strcmp (cnst, fields[1]) == 0))
- ptr = buf;
- saveptr = NULL;
- while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
+ ptr = buf;
+ saveptr = NULL;
+ while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
{
int name_len;
- ptr = NULL;
+ ptr = NULL;
fields_num = strsplit(line, fields, 3);
if (fields_num != 3)
{
rusage_syst = atoll(fields[2]);
}
-
+
/*
* Number of threads of this instance
*/
{
submit_gauge ("memcached_items", "current", atof (fields[2]));
}
-/*
- else if (FIELD_IS ("total_items"))
- {
- total_items = atoll(fields[2]);
- }
- */
/*
* Number of bytes used and available (total - used)
{
submit_gauge ("memcached_connections", "current", atof (fields[2]));
}
-/*
- else if (FIELD_IS("total_connections"))
- {
- total_connections = atoll(fields[2]);
- }
-*/
-
-/*
- * ``Number of connection structures allocated by the server''
- else if (FIELD_IS ("connection_structures"))
- {
- connection_structures = atof(fields[2]);
- }
- */
/*
* Commands
{
const char *name = fields[1] + 4;
submit_counter ("memcached_command", name, atoll (fields[2]));
+ if (strcmp (name, "get") == 0)
+ gets = atof (fields[2]);
}
/*
else if (FIELD_IS ("get_hits"))
{
submit_counter ("memcached_ops", "hits", atoll (fields[2]));
+ hits = atof (fields[2]);
}
else if (FIELD_IS ("get_misses"))
{
if (!isnan (bytes_used) && !isnan (bytes_total) && (bytes_used <= bytes_total))
submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used);
-
+
if ((rusage_user != 0) || (rusage_syst != 0))
submit_counter2 ("ps_cputime", NULL, rusage_user, rusage_syst);
if ((octets_rx != 0) || (octets_tx != 0))
submit_counter2 ("memcached_octets", NULL, octets_rx, octets_tx);
-
+
+ if (!isnan (gets) && !isnan (hits))
+ {
+ gauge_t rate = NAN;
+
+ if (gets != 0.0)
+ rate = 100.0 * hits / gets;
+
+ submit_gauge ("percent", "hitratio", rate);
+ }
+
return 0;
}
/* }}} */
* tab-width: 4
* c-basic-offset: 4
* End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
+ * vim600: sw=4 ts=4 fdm=marker noexpandtab
+ * vim<600: sw=4 ts=4 noexpandtab
*/