summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--output/Makefile.am6
-rw-r--r--output/ulogd_output_GRAPHITE.c246
-rw-r--r--ulogd.conf.in10
3 files changed, 261 insertions, 1 deletions
diff --git a/output/Makefile.am b/output/Makefile.am
index fe0a19c..17427d0 100644
--- a/output/Makefile.am
+++ b/output/Makefile.am
@@ -6,7 +6,8 @@ SUBDIRS= pcap mysql pgsql sqlite3 dbi
pkglib_LTLIBRARIES = ulogd_output_LOGEMU.la ulogd_output_SYSLOG.la \
ulogd_output_OPRINT.la ulogd_output_GPRINT.la \
- ulogd_output_NACCT.la ulogd_output_XML.la
+ ulogd_output_NACCT.la ulogd_output_XML.la \
+ ulogd_output_GRAPHITE.la
ulogd_output_GPRINT_la_SOURCES = ulogd_output_GPRINT.c
ulogd_output_GPRINT_la_LDFLAGS = -avoid-version -module
@@ -28,3 +29,6 @@ ulogd_output_XML_la_LIBADD = ${LIBNETFILTER_LOG_LIBS} \
${LIBNETFILTER_CONNTRACK_LIBS} \
${LIBNETFILTER_ACCT_LIBS}
ulogd_output_XML_la_LDFLAGS = -avoid-version -module
+
+ulogd_output_GRAPHITE_la_SOURCES = ulogd_output_GRAPHITE.c
+ulogd_output_GRAPHITE_la_LDFLAGS = -avoid-version -module
diff --git a/output/ulogd_output_GRAPHITE.c b/output/ulogd_output_GRAPHITE.c
new file mode 100644
index 0000000..25b578e
--- /dev/null
+++ b/output/ulogd_output_GRAPHITE.c
@@ -0,0 +1,246 @@
+/* ulogd_GRAPHITE.c
+ *
+ * ulogd output target to feed data to a graphite system
+ *
+ * (C) 2012 by Eric Leblond <eric@regit.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+
+
+enum {
+ KEY_SUM_NAME,
+ KEY_SUM_PKTS,
+ KEY_SUM_BYTES,
+ KEY_OOB_TIME_SEC,
+};
+
+
+static struct ulogd_key graphite_inp[] = {
+ [KEY_SUM_NAME] {
+ .type = ULOGD_RET_STRING,
+ .name = "sum.name",
+ },
+ [KEY_SUM_PKTS] {
+ .type = ULOGD_RET_UINT64,
+ .name = "sum.pkts",
+ },
+ [KEY_SUM_BYTES] {
+ .type = ULOGD_RET_UINT64,
+ .name = "sum.bytes",
+ },
+ [KEY_OOB_TIME_SEC] {
+ .type = ULOGD_RET_UINT32,
+ .name = "oob.time.sec",
+ },
+};
+
+
+static struct config_keyset graphite_kset = {
+ .num_ces = 3,
+ .ces = {
+ {
+ .key = "host",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ },
+ {
+ .key = "port",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ },
+ {
+ .key = "prefix",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_NONE,
+ },
+ },
+};
+
+#define host_ce(x) (x->ces[0])
+#define port_ce(x) (x->ces[1])
+#define prefix_ce(x) (x->ces[2])
+
+struct graphite_instance {
+ int sck;
+};
+
+static int _connect_graphite(struct ulogd_pluginstance *pi)
+{
+ struct graphite_instance *li = (struct graphite_instance *) &pi->private;
+ char *host;
+ char * port;
+ struct addrinfo hints;
+ struct addrinfo *result, *rp;
+ int sfd, s;
+
+ ulogd_log(ULOGD_DEBUG, "connecting to graphite\n");
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = 0;
+
+ host = host_ce(pi->config_kset).u.string;
+ port = port_ce(pi->config_kset).u.string;
+ s = getaddrinfo(host, port, &hints, &result);
+ if (s != 0) {
+ ulogd_log(ULOGD_ERROR, "getaddrinfo: %s\n", gai_strerror(s));
+ return -1;
+ }
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ int on = 1;
+
+ sfd = socket(rp->ai_family, rp->ai_socktype,
+ rp->ai_protocol);
+ if (sfd == -1)
+ continue;
+
+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &on, sizeof(on));
+
+ if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+ break;
+
+ close(sfd);
+ }
+
+ freeaddrinfo(result);
+
+ if (rp == NULL) {
+ ulogd_log(ULOGD_ERROR, "Could not connect\n");
+ return -1;
+ }
+
+ li->sck = sfd;
+
+ return 0;
+}
+
+static int _output_graphite(struct ulogd_pluginstance *upi)
+{
+ struct graphite_instance *li = (struct graphite_instance *) &upi->private;
+ struct ulogd_key *inp = upi->input.keys;
+ static char buf[256];
+ int ret;
+
+ time_t now;
+ int msg_size = 0;
+
+ if (ikey_get_u32(&inp[KEY_OOB_TIME_SEC]))
+ now = (time_t) ikey_get_u32(&inp[KEY_OOB_TIME_SEC]);
+ else
+ now = time(NULL);
+
+ msg_size = snprintf(buf, sizeof(buf), "%s.%s.pkts %" PRIu64
+ " %" PRIu64 "\n%s.%s.bytes %" PRIu64 " %" PRIu64 "\n",
+ prefix_ce(upi->config_kset).u.string,
+ (char *)ikey_get_ptr(&inp[KEY_SUM_NAME]),
+ ikey_get_u64(&inp[KEY_SUM_PKTS]),
+ now,
+ prefix_ce(upi->config_kset).u.string,
+ (char *)ikey_get_ptr(&inp[KEY_SUM_NAME]),
+ ikey_get_u64(&inp[KEY_SUM_BYTES]),
+ now
+ );
+ if (msg_size == -1) {
+ ulogd_log(ULOGD_ERROR, "Could not create message\n");
+ return ULOGD_IRET_ERR;
+ }
+ ret = send(li->sck, buf, msg_size, MSG_NOSIGNAL);
+ if (ret != msg_size) {
+ ulogd_log(ULOGD_ERROR, "Failure sending message\n");
+ if (ret == -1) {
+ return _connect_graphite(upi);
+ }
+ }
+
+ return ULOGD_IRET_OK;
+}
+
+static int start_graphite(struct ulogd_pluginstance *pi)
+{
+ char *host;
+ char *port;
+
+ ulogd_log(ULOGD_DEBUG, "starting graphite\n");
+
+ host = host_ce(pi->config_kset).u.string;
+ if (host == NULL)
+ return -1;
+ port = port_ce(pi->config_kset).u.string;
+ if (port == NULL)
+ return -1;
+ return _connect_graphite(pi);
+}
+
+static int fini_graphite(struct ulogd_pluginstance *pi) {
+ struct graphite_instance *li = (struct graphite_instance *) &pi->private;
+
+ close(li->sck);
+ li->sck = 0;
+
+ return 0;
+}
+
+static int configure_graphite(struct ulogd_pluginstance *pi,
+ struct ulogd_pluginstance_stack *stack)
+{
+ ulogd_log(ULOGD_DEBUG, "parsing config file section %s\n", pi->id);
+ return config_parse_file(pi->id, pi->config_kset);
+}
+
+static struct ulogd_plugin graphite_plugin = {
+ .name = "GRAPHITE",
+ .input = {
+ .keys = graphite_inp,
+ .num_keys = ARRAY_SIZE(graphite_inp),
+ .type = ULOGD_DTYPE_SUM,
+ },
+ .output = {
+ .type = ULOGD_DTYPE_SINK,
+ },
+ .config_kset = &graphite_kset,
+ .priv_size = sizeof(struct graphite_instance),
+
+ .configure = &configure_graphite,
+ .start = &start_graphite,
+ .stop = &fini_graphite,
+
+ .interp = &_output_graphite,
+ .version = VERSION,
+};
+
+void __attribute__ ((constructor)) init(void);
+
+void init(void)
+{
+ ulogd_register_plugin(&graphite_plugin);
+}
diff --git a/ulogd.conf.in b/ulogd.conf.in
index c630b88..6aff802 100644
--- a/ulogd.conf.in
+++ b/ulogd.conf.in
@@ -49,6 +49,7 @@ plugin="@pkglibdir@/ulogd_output_GPRINT.so"
#plugin="@pkglibdir@/ulogd_output_DBI.so"
plugin="@pkglibdir@/ulogd_raw2packet_BASE.so"
plugin="@pkglibdir@/ulogd_inpflow_NFACCT.so"
+plugin="@pkglibdir@/ulogd_output_GRAPHITE.so"
# this is a stack for logging packet send by system via LOGEMU
#stack=log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU
@@ -80,6 +81,9 @@ plugin="@pkglibdir@/ulogd_inpflow_NFACCT.so"
# this is a stack for accounting-based logging via XML
#stack=acct1:NFACCT,xml1:XML
+# this is a stack for accounting-based logging to a Graphite server
+#stack=acct1:NFACCT,graphite1:GRAPHITE
+
# this is a stack for NFLOG packet-based logging to PCAP
#stack=log2:NFLOG,base1:BASE,pcap1:PCAP
@@ -280,3 +284,9 @@ pollinterval = 2
# Set timestamp (default is 0, which means not set). This timestamp can be
# interpreted by the output plugin.
#timestamp = 1
+
+[graphite1]
+host="127.0.0.1"
+port="2003"
+# Prefix of data name sent to graphite server
+prefix="netfilter.nfacct"