Mercurial > dovecot > core-2.2
changeset 19721:9d2fa1afc222
auth: If auth_stats=yes, send statistics to stats process.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Mon, 08 Feb 2016 16:20:46 +0200 |
parents | c34f24c83729 |
children | 69cf950c6e6f |
files | src/auth/Makefile.am src/auth/auth-request-stats.c src/auth/auth-request-stats.h src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-settings.c src/auth/auth-settings.h src/auth/auth-stats.c src/auth/auth-stats.h src/auth/main.c src/auth/passdb-cache.c |
diffstat | 11 files changed, 270 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/Makefile.am Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/Makefile.am Mon Feb 08 16:20:46 2016 +0200 @@ -29,6 +29,7 @@ -I$(top_srcdir)/src/lib-dns \ -I$(top_srcdir)/src/lib-sql \ -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-stats \ -I$(top_srcdir)/src/lib-ntlm \ -I$(top_srcdir)/src/lib-otp \ -I$(top_srcdir)/src/lib-master \ @@ -70,8 +71,10 @@ auth-penalty.c \ auth-request.c \ auth-request-handler.c \ + auth-request-stats.c \ auth-request-var-expand.c \ auth-settings.c \ + auth-stats.c \ auth-fields.c \ auth-token.c \ auth-worker-client.c \ @@ -141,6 +144,7 @@ auth-request-handler.h \ auth-request-var-expand.h \ auth-settings.h \ + auth-stats.h \ auth-fields.h \ auth-token.h \ auth-worker-client.h \ @@ -195,6 +199,14 @@ checkpassword_reply_sources = \ checkpassword-reply.c +stats_moduledir = $(moduledir)/stats +stats_module_LTLIBRARIES = libstats_auth.la + +libstats_auth_la_LDFLAGS = -module -avoid-version +libstats_auth_la_LIBADD = auth-stats.lo $(LIBDOVECOT) +libstats_auth_la_DEPENDENCIES = auth-stats.lo +libstats_auth_la_SOURCES = + test_programs = \ test-auth-cache \ test-auth-request-var-expand \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-request-stats.c Mon Feb 08 16:20:46 2016 +0200 @@ -0,0 +1,77 @@ +/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */ + +#include "auth-common.h" +#include "str.h" +#include "strescape.h" +#include "buffer.h" +#include "base64.h" +#include "stats.h" +#include "stats-connection.h" +#include "auth-stats.h" +#include "auth-request.h" +#include "auth-request-stats.h" + +#define USER_STATS_SOCKET_NAME "stats-user" + +static struct stats_connection *auth_stats_conn = NULL; +static struct stats_item *auth_stats_item; + +struct auth_stats *auth_request_stats_get(struct auth_request *request) +{ + if (request->stats == NULL) + request->stats = stats_alloc(request->pool); + return stats_fill_ptr(request->stats, auth_stats_item); +} + +void auth_request_stats_add_tempfail(struct auth_request *request) +{ + struct auth_stats *stats = auth_request_stats_get(request); + + stats->auth_db_tempfail_count++; +} + +void auth_request_stats_send(struct auth_request *request) +{ + string_t *str; + buffer_t *buf; + + /* we'll send stats only when the request is finished. this reduces + memory usage and is a bit simpler. auth requests are typically + pretty short lived anyway. */ + i_assert(!request->stats_sent); + request->stats_sent = TRUE; + + if (request->stats == NULL) { + /* nothing happened in this request - don't send it */ + return; + } + if (!request->set->stats) + return; + + buf = buffer_create_dynamic(pool_datastack_create(), 128); + stats_export(buf, request->stats); + + str = t_str_new(256); + str_append(str, "ADD-USER\t"); + if (request->user != NULL) + str_append_tabescaped(str, request->user); + str_append_c(str, '\t'); + str_append_tabescaped(str, request->service); + str_append_c(str, '\t'); + base64_encode(buf->data, buf->used, str); + + str_append_c(str, '\n'); + stats_connection_send(auth_stats_conn, str); +} + +void auth_request_stats_init(void) +{ + auth_stats_conn = stats_connection_create(USER_STATS_SOCKET_NAME); + auth_stats_item = stats_register(&auth_stats_vfuncs); +} + +void auth_request_stats_deinit(void) +{ + stats_connection_unref(&auth_stats_conn); + stats_unregister(&auth_stats_item); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-request-stats.h Mon Feb 08 16:20:46 2016 +0200 @@ -0,0 +1,15 @@ +#ifndef AUTH_REQUEST_STATS_H +#define AUTH_REQUEST_STATS_H + +#include "auth-stats.h" + +struct auth_request; + +struct auth_stats *auth_request_stats_get(struct auth_request *request); +void auth_request_stats_add_tempfail(struct auth_request *request); +void auth_request_stats_send(struct auth_request *request); + +void auth_request_stats_init(void); +void auth_request_stats_deinit(void); + +#endif
--- a/src/auth/auth-request.c Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/auth-request.c Mon Feb 08 16:20:46 2016 +0200 @@ -15,6 +15,7 @@ #include "auth-cache.h" #include "auth-request.h" #include "auth-request-handler.h" +#include "auth-request-stats.h" #include "auth-client-connection.h" #include "auth-master-connection.h" #include "passdb.h" @@ -121,6 +122,8 @@ void auth_request_success(struct auth_request *request, const void *data, size_t data_size) { + struct auth_stats *stats; + i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); if (request->failed || !request->passdb_success) { @@ -137,6 +140,11 @@ return; } + stats = auth_request_stats_get(request); + stats->auth_success_count++; + if (request->master_user != NULL) + stats->auth_master_success_count++; + auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); auth_request_refresh_last_access(request); auth_request_handler_reply(request, AUTH_CLIENT_RESULT_SUCCESS, @@ -145,8 +153,13 @@ void auth_request_fail(struct auth_request *request) { + struct auth_stats *stats; + i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); + stats = auth_request_stats_get(request); + stats->auth_failure_count++; + auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); auth_request_refresh_last_access(request); auth_request_handler_reply(request, AUTH_CLIENT_RESULT_FAILURE, "", 0); @@ -172,6 +185,7 @@ if (--request->refcount > 0) return; + auth_request_stats_send(request); auth_request_state_count[request->state]--; auth_refresh_proctitle(); @@ -706,6 +720,7 @@ expired record. */ const char *cache_key = passdb->cache_key; + auth_request_stats_add_tempfail(request); if (passdb_cache_verify_plain(request, cache_key, request->mech_password, &result, TRUE)) { @@ -871,6 +886,7 @@ expired record. */ const char *cache_key = passdb->cache_key; + auth_request_stats_add_tempfail(request); if (passdb_cache_lookup_credentials(request, cache_key, &cache_cred, &cache_scheme, &result, TRUE)) { @@ -1004,6 +1020,7 @@ enum userdb_result *result_r, bool use_expired) { + struct auth_stats *stats = auth_request_stats_get(request); const char *value; struct auth_cache_node *node; bool expired, neg_expired; @@ -1011,11 +1028,13 @@ value = auth_cache_lookup(passdb_cache, request, key, &node, &expired, &neg_expired); if (value == NULL || (expired && !use_expired)) { + stats->auth_cache_miss_count++; auth_request_log_debug(request, AUTH_SUBSYS_DB, value == NULL ? "userdb cache miss" : "userdb cache expired"); return FALSE; } + stats->auth_cache_hit_count++; auth_request_log_debug(request, AUTH_SUBSYS_DB, "userdb cache hit: %s", value); @@ -1051,6 +1070,7 @@ result_rule = request->userdb->result_success; break; case USERDB_RESULT_INTERNAL_FAILURE: + auth_request_stats_add_tempfail(request); result_rule = request->userdb->result_internalfail; break; case USERDB_RESULT_USER_UNKNOWN:
--- a/src/auth/auth-request.h Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/auth-request.h Mon Feb 08 16:20:46 2016 +0200 @@ -61,6 +61,8 @@ struct auth_passdb *passdb; struct auth_userdb *userdb; + struct stats *stats; + /* passdb lookups have a handler, userdb lookups don't */ struct auth_request_handler *handler; struct auth_master_connection *master; @@ -138,6 +140,7 @@ /* userdb_* fields have been set by the passdb lookup, userdb prefetch will work. */ unsigned int userdb_prefetch_set:1; + unsigned int stats_sent:1; /* ... mechanism specific data ... */ };
--- a/src/auth/auth-settings.c Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/auth-settings.c Mon Feb 08 16:20:46 2016 +0200 @@ -230,6 +230,7 @@ DEF(SET_STR, proxy_self), DEF(SET_TIME, failure_delay), + DEF(SET_BOOL, stats), DEF(SET_BOOL, verbose), DEF(SET_BOOL, debug), DEF(SET_BOOL, debug_passwords), @@ -269,6 +270,7 @@ .proxy_self = "", .failure_delay = 2, + .stats = FALSE, .verbose = FALSE, .debug = FALSE, .debug_passwords = FALSE,
--- a/src/auth/auth-settings.h Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/auth-settings.h Mon Feb 08 16:20:46 2016 +0200 @@ -51,6 +51,7 @@ const char *proxy_self; unsigned int failure_delay; + bool stats; bool verbose, debug, debug_passwords; const char *verbose_passwords; bool ssl_require_client_cert;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-stats.c Mon Feb 08 16:20:46 2016 +0200 @@ -0,0 +1,116 @@ +/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "stats.h" +#include "stats-parser.h" +#include "auth-stats.h" + +static struct stats_parser_field auth_stats_fields[] = { +#define E(parsename, name, type) { parsename, offsetof(struct auth_stats, name), sizeof(((struct auth_stats *)0)->name), type } +#define EN(parsename, name) E(parsename, name, STATS_PARSER_TYPE_UINT) + EN("auth_successes", auth_success_count), + EN("auth_master_successes", auth_master_success_count), + EN("auth_failures", auth_failure_count), + EN("auth_db_tempfails", auth_db_tempfail_count), + + EN("auth_cache_hits", auth_cache_hit_count), + EN("auth_cache_misses", auth_cache_miss_count) +}; + +static size_t auth_stats_alloc_size(void) +{ + return sizeof(struct auth_stats); +} + +static unsigned int auth_stats_field_count(void) +{ + return N_ELEMENTS(auth_stats_fields); +} + +static const char *auth_stats_field_name(unsigned int n) +{ + i_assert(n < N_ELEMENTS(auth_stats_fields)); + + return auth_stats_fields[n].name; +} + +static void +auth_stats_field_value(string_t *str, const struct stats *stats, + unsigned int n) +{ + i_assert(n < N_ELEMENTS(auth_stats_fields)); + + stats_parser_value(str, &auth_stats_fields[n], stats); +} + +static bool +auth_stats_diff(const struct stats *stats1, const struct stats *stats2, + struct stats *diff_stats_r, const char **error_r) +{ + return stats_parser_diff(auth_stats_fields, N_ELEMENTS(auth_stats_fields), + stats1, stats2, diff_stats_r, error_r); +} + +static void auth_stats_add(struct stats *dest, const struct stats *src) +{ + stats_parser_add(auth_stats_fields, N_ELEMENTS(auth_stats_fields), + dest, src); +} + +static bool +auth_stats_have_changed(const struct stats *_prev, const struct stats *_cur) +{ + return memcmp(_prev, _cur, sizeof(struct auth_stats)) != 0; +} + +static void auth_stats_export(buffer_t *buf, const struct stats *_stats) +{ + const struct auth_stats *stats = (const struct auth_stats *)_stats; + + buffer_append(buf, stats, sizeof(*stats)); +} + +static bool +auth_stats_import(const unsigned char *data, size_t size, size_t *pos_r, + struct stats *_stats, const char **error_r) +{ + struct auth_stats *stats = (struct auth_stats *)_stats; + + if (size < sizeof(*stats)) { + *error_r = "auth_stats too small"; + return FALSE; + } + memcpy(stats, data, sizeof(*stats)); + *pos_r = sizeof(*stats); + return TRUE; +} + +const struct stats_vfuncs auth_stats_vfuncs = { + "auth", + auth_stats_alloc_size, + auth_stats_field_count, + auth_stats_field_name, + auth_stats_field_value, + auth_stats_diff, + auth_stats_add, + auth_stats_have_changed, + auth_stats_export, + auth_stats_import +}; + +/* for the stats_auth plugin: */ +void stats_auth_init(void); +void stats_auth_deinit(void); + +static struct stats_item *auth_stats_item; + +void stats_auth_init(void) +{ + auth_stats_item = stats_register(&auth_stats_vfuncs); +} + +void stats_auth_deinit(void) +{ + stats_unregister(&auth_stats_item); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-stats.h Mon Feb 08 16:20:46 2016 +0200 @@ -0,0 +1,16 @@ +#ifndef AUTH_STATS_H +#define AUTH_STATS_H + +struct auth_stats { + uint32_t auth_success_count; + uint32_t auth_master_success_count; + uint32_t auth_failure_count; + uint32_t auth_db_tempfail_count; + + uint32_t auth_cache_hit_count; + uint32_t auth_cache_miss_count; +}; + +extern const struct stats_vfuncs auth_stats_vfuncs; + +#endif
--- a/src/auth/main.c Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/main.c Mon Feb 08 16:20:46 2016 +0200 @@ -24,6 +24,7 @@ #include "auth-penalty.h" #include "auth-token.h" #include "auth-request-handler.h" +#include "auth-request-stats.h" #include "auth-worker-server.h" #include "auth-worker-client.h" #include "auth-master-connection.h" @@ -198,6 +199,7 @@ if (!worker) auth_penalty = auth_penalty_init(AUTH_PENALTY_ANVIL_PATH); + auth_request_stats_init(); mech_init(global_auth_settings); mech_reg = mech_register_init(global_auth_settings); dict_drivers_register_builtin(); @@ -293,6 +295,8 @@ passdbs_deinit(); passdb_cache_deinit(); password_schemes_deinit(); + auth_request_stats_deinit(); + sql_drivers_deinit(); random_deinit(); child_wait_deinit();
--- a/src/auth/passdb-cache.c Fri Feb 05 11:36:32 2016 -0700 +++ b/src/auth/passdb-cache.c Mon Feb 08 16:20:46 2016 +0200 @@ -2,11 +2,11 @@ #include "auth-common.h" #include "restrict-process-size.h" +#include "auth-request-stats.h" #include "password-scheme.h" #include "passdb.h" #include "passdb-cache.h" - struct auth_cache *passdb_cache = NULL; static void @@ -28,6 +28,7 @@ bool use_expired, struct auth_cache_node **node_r, const char **value_r, bool *neg_expired_r) { + struct auth_stats *stats = auth_request_stats_get(request); const char *value; bool expired; @@ -35,11 +36,13 @@ value = auth_cache_lookup(passdb_cache, request, key, node_r, &expired, neg_expired_r); if (value == NULL || (expired && !use_expired)) { + stats->auth_cache_miss_count++; auth_request_log_debug(request, AUTH_SUBSYS_DB, value == NULL ? "cache miss" : "cache expired"); return FALSE; } + stats->auth_cache_hit_count++; passdb_cache_log_hit(request, value); *value_r = value;