Mercurial > dovecot > core-2.2
view src/plugins/stats/stats-connection.c @ 13294:c51fbe64eae1
Initial implementation of statistics gathering daemon and plugins to feed it.
Some statistics are still missing, some of the code is a bit ugly and the
internal protocols will probably still change.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 26 Aug 2011 05:15:12 +0300 |
parents | |
children | 07f02f421588 |
line wrap: on
line source
/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "network.h" #include "str.h" #include "strescape.h" #include "mail-storage.h" #include "stats-plugin.h" #include "stats-connection.h" struct stats_connection { int refcount; int fd; char *path; }; struct stats_connection * stats_connection_create(const char *path) { struct stats_connection *conn; conn = i_new(struct stats_connection, 1); conn->refcount = 1; conn->path = i_strdup(path); conn->fd = open(path, O_WRONLY); if (conn->fd == -1) i_error("stats: open(%s) failed: %m", path); return conn; } void stats_connection_ref(struct stats_connection *conn) { conn->refcount++; } void stats_connection_unref(struct stats_connection **_conn) { struct stats_connection *conn = *_conn; i_assert(conn->refcount > 0); if (--conn->refcount > 0) return; *_conn = NULL; if (conn->fd != -1) { if (close(conn->fd) < 0) i_error("close(%s) failed: %m", conn->path); } i_free(conn->path); i_free(conn); } void stats_connection_send(struct stats_connection *conn, const string_t *str) { static bool pipe_warned = FALSE; ssize_t ret; if (conn->fd == -1) return; if (str_len(str) > PIPE_BUF && !pipe_warned) { i_warning("stats update sent more bytes that PIPE_BUF " "(%"PRIuSIZE_T" > %u), this may break statistics", str_len(str), (unsigned int)PIPE_BUF); pipe_warned = TRUE; } ret = write(conn->fd, str_data(str), str_len(str)); if (ret != (ssize_t)str_len(str)) { if (ret < 0) i_error("write(%s) failed: %m", conn->path); else if ((size_t)ret != str_len(str)) i_error("write(%s) wrote partial update", conn->path); /* this shouldn't happen, just stop sending updates */ if (close(conn->fd) < 0) i_error("close(%s) failed: %m", conn->path); conn->fd = -1; } } void stats_connection_connect(struct stats_connection *conn, struct mail_user *user) { struct stats_user *suser = STATS_USER_CONTEXT(user); string_t *str = t_str_new(128); str_append(str, "CONNECT\t"); /* required fields */ str_append(str, guid_128_to_string(suser->session_guid)); str_append_c(str, '\t'); str_tabescape_write(str, user->username); str_append_c(str, '\t'); str_tabescape_write(str, user->service); /* optional fields */ if (user->local_ip != NULL) { str_append(str, "\tlip="); str_append(str, net_ip2addr(user->local_ip)); } if (user->remote_ip != NULL) { str_append(str, "\trip="); str_append(str, net_ip2addr(user->remote_ip)); } str_append_c(str, '\n'); stats_connection_send(conn, str); } void stats_connection_disconnect(struct stats_connection *conn, struct mail_user *user) { struct stats_user *suser = STATS_USER_CONTEXT(user); string_t *str = t_str_new(128); str_append(str, "DISCONNECT\t"); str_append(str, guid_128_to_string(suser->session_guid)); str_append_c(str, '\n'); stats_connection_send(conn, str); } void stats_connection_send_session(struct stats_connection *conn, struct mail_user *user, const struct mail_stats *stats) { struct stats_user *suser = STATS_USER_CONTEXT(user); string_t *str = t_str_new(128); str_append(str, "UPDATE-SESSION\t"); str_append(str, guid_128_to_string(suser->session_guid)); mail_stats_export(str, stats); str_append_c(str, '\n'); stats_connection_send(conn, str); }