]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-sql: Add events
authorAki Tuomi <aki.tuomi@dovecot.fi>
Thu, 30 Aug 2018 11:23:10 +0000 (14:23 +0300)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Wed, 14 Nov 2018 08:13:11 +0000 (10:13 +0200)
src/lib-sql/sql-api-private.h
src/lib-sql/sql-api.c
src/lib-sql/sql-api.h

index bbc763ce0a4c3b79ec35fc18e32208714dfed383..5355f31635b8deeb9440e533299cc82af007ab22 100644 (file)
@@ -35,6 +35,15 @@ enum sql_db_state {
        ((db)->state == SQL_DB_STATE_IDLE)
 #define SQL_ERRSTR_NOT_CONNECTED "Not connected to database"
 
+/* What is considered slow query */
+#define SQL_SLOW_QUERY_MSEC 1000
+
+#define SQL_QUERY_FINISHED "sql_query_finished"
+#define SQL_CONNECTION_FINISHED "sql_connection_finished"
+#define SQL_TRANSACTION_FINISHED "sql_transaction_finished"
+
+#define SQL_QUERY_FINISHED_FMT "Finished query '%s' in %u msecs"
+
 struct sql_db_module_register {
        unsigned int id;
 };
@@ -45,6 +54,8 @@ union sql_db_module_context {
 
 extern struct sql_db_module_register sql_db_module_register;
 
+extern struct event_category event_category_sql;
+
 struct sql_transaction_query {
        struct sql_transaction_query *next;
        struct sql_transaction_context *trans;
@@ -121,6 +132,8 @@ struct sql_db {
                                      void *context);
        void *state_change_context;
 
+       struct event *event;
+
        enum sql_db_state state;
        /* last time we started connecting to this server
           (which may or may not have succeeded) */
@@ -129,6 +142,11 @@ struct sql_db {
        unsigned int connect_failure_count;
        struct timeout *to_reconnect;
 
+       uint64_t succeeded_queries;
+       uint64_t failed_queries;
+       /* includes both succeeded and failed */
+       uint64_t slow_queries;
+
        bool no_reconnect:1;
 };
 
@@ -183,6 +201,7 @@ struct sql_result {
        unsigned int map_size;
        struct sql_field_map *map;
        void *fetch_dest;
+       struct event *event;
        size_t fetch_dest_size;
        enum sql_result_error_type error_type;
 
@@ -193,6 +212,7 @@ struct sql_result {
 
 struct sql_transaction_context {
        struct sql_db *db;
+       struct event *event;
 
        /* commit() must use this query list if head is non-NULL. */
        struct sql_transaction_query *head, *tail;
@@ -214,4 +234,9 @@ void sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool,
                               const char *query, unsigned int *affected_rows);
 const char *sql_statement_get_query(struct sql_statement *stmt);
 
+void sql_connection_log_finished(struct sql_db *db);
+struct event_passthrough *
+sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
+                        bool success, int *duration_r);
+struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx);
 #endif
index 95ce32b991520510077b5ae9f0ca34c8f50107a7..7be2230757ee21cd569f2582ab0ddc826c10b208 100644 (file)
@@ -4,6 +4,7 @@
 #include "array.h"
 #include "ioloop.h"
 #include "str.h"
+#include "time-util.h"
 #include "sql-api-private.h"
 
 #include <time.h>
@@ -13,6 +14,10 @@ struct default_sql_prepared_statement {
        char *query_template;
 };
 
+struct event_category event_category_sql = {
+       .name = "sql",
+};
+
 struct sql_db_module_register sql_db_module_register = { 0 };
 ARRAY_TYPE(sql_drivers) sql_drivers;
 
@@ -92,9 +97,11 @@ int sql_init_full(const struct sql_settings *set, struct sql_db **db_r,
        }
 
        if ((driver->flags & SQL_DB_FLAG_POOLED) == 0) {
-               if (driver->v.init_full == NULL)
+               if (driver->v.init_full == NULL) {
                        db = driver->v.init(set->connect_string);
-               else
+                       db->event = event_create(set->event_parent);
+                       event_add_category(db->event, &event_category_sql);
+               } else
                        ret = driver->v.init_full(set, &db, error_r);
        } else
                ret = driver_sqlpool_init_full(set, driver, &db, error_r);
@@ -719,6 +726,51 @@ void sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool,
        ctx->tail = tquery;
 }
 
+void sql_connection_log_finished(struct sql_db *db)
+{
+       struct event_passthrough *e = event_create_passthrough(db->event)->
+               set_name(SQL_CONNECTION_FINISHED);
+       e_debug(e->event(),
+               "Connection finished (queries=%"PRIu64", slow queries=%"PRIu64")",
+               db->succeeded_queries + db->failed_queries,
+               db->slow_queries);
+}
+
+struct event_passthrough *
+sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
+                        bool success, int *duration_r)
+{
+       int diff;
+       struct timeval tv;
+       event_get_create_time(event, &tv);
+       struct event_passthrough *e = event_create_passthrough(event)->
+                       set_name(SQL_QUERY_FINISHED)->
+                       add_str("query_first_word", t_strcut(query, ' '));
+       diff = timeval_diff_msecs(&ioloop_timeval, &tv);
+
+       if (!success) {
+               db->failed_queries++;
+       } else {
+               db->succeeded_queries++;
+       }
+
+       if (diff >= SQL_SLOW_QUERY_MSEC) {
+               e->add_str("slow_query", "y");
+               db->slow_queries++;
+       }
+
+       if (duration_r != NULL)
+               *duration_r = diff;
+
+       return e;
+}
+
+struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx)
+{
+       return event_create_passthrough(ctx->event)->
+               set_name(SQL_TRANSACTION_FINISHED);
+}
+
 struct sql_result sql_not_connected_result = {
        .v = {
                sql_result_not_connected_free,
index 7e4fd33800b4216fc55e2b341fdd19a904ba3209..f2aca6927d1ba1dc33f6cdd88a3b2b5a2db3af6f 100644 (file)
@@ -73,6 +73,7 @@ struct sql_commit_result {
 struct sql_settings {
        const char *driver;
        const char *connect_string;
+       struct event *event_parent;
 };
 
 typedef void sql_query_callback_t(struct sql_result *result, void *context);