1/* Copyright (C) 2012 Monty Program Ab.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16#include <mysql/plugin_audit.h>
17#include <stdio.h>
18#include <time.h>
19#include <mysql/service_logger.h>
20
21/*
22 Disable __attribute__() on non-gcc compilers.
23*/
24#if !defined(__attribute__) && !defined(__GNUC__)
25#define __attribute__(A)
26#endif
27
28#ifdef _WIN32
29#define localtime_r(a, b) localtime_s(b, a)
30#endif /*WIN32*/
31
32/*
33 rate 0 means the logging was disabled.
34*/
35
36
37static char *filename;
38static unsigned int rate;
39static unsigned long long size_limit;
40static unsigned int rotations;
41static char rotate;
42
43static unsigned int count;
44LOGGER_HANDLE *logfile;
45
46static void rotate_log(MYSQL_THD thd, struct st_mysql_sys_var *var,
47 void *var_ptr, const void *save);
48
49static MYSQL_SYSVAR_UINT(rate, rate, PLUGIN_VAR_RQCMDARG,
50 "Sampling rate. If set to 0(zero), the logging is disabled.", NULL, NULL,
51 1, 0, 1000000, 1);
52
53static MYSQL_SYSVAR_ULONGLONG(size_limit, size_limit,
54 PLUGIN_VAR_READONLY, "Log file size limit", NULL, NULL,
55 1000000, 100, ((long long) 0x7FFFFFFFFFFFFFFFLL), 1);
56
57static MYSQL_SYSVAR_UINT(rotations, rotations,
58 PLUGIN_VAR_READONLY, "Number of rotations before log is removed.",
59 NULL, NULL, 9, 1, 999, 1);
60
61static MYSQL_SYSVAR_BOOL(rotate, rotate,
62 PLUGIN_VAR_OPCMDARG, "Force log rotation", NULL, rotate_log,
63 0);
64
65static MYSQL_SYSVAR_STR(filename, filename,
66 PLUGIN_VAR_READONLY | PLUGIN_VAR_RQCMDARG,
67 "The file to log sql errors to", NULL, NULL,
68 "sql_errors.log");
69
70static struct st_mysql_sys_var* vars[] = {
71 MYSQL_SYSVAR(rate),
72 MYSQL_SYSVAR(size_limit),
73 MYSQL_SYSVAR(rotations),
74 MYSQL_SYSVAR(rotate),
75 MYSQL_SYSVAR(filename),
76 NULL
77};
78
79
80static void log_sql_errors(MYSQL_THD thd __attribute__((unused)),
81 unsigned int event_class __attribute__((unused)),
82 const void *ev)
83{
84 const struct mysql_event_general *event =
85 (const struct mysql_event_general*)ev;
86 if (rate &&
87 event->event_subclass == MYSQL_AUDIT_GENERAL_ERROR)
88 {
89 if (++count >= rate)
90 {
91 struct tm t;
92 time_t event_time = event->general_time;
93
94 count = 0;
95 (void) localtime_r(&event_time, &t);
96 logger_printf(logfile, "%04d-%02d-%02d %2d:%02d:%02d "
97 "%s ERROR %d: %s : %s\n",
98 t.tm_year + 1900, t.tm_mon + 1,
99 t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
100 event->general_user, event->general_error_code,
101 event->general_command, event->general_query);
102 }
103 }
104}
105
106
107static int sql_error_log_init(void *p __attribute__((unused)))
108{
109 logger_init_mutexes();
110
111 logfile= logger_open(filename, size_limit, rotations);
112 if (logfile == NULL) {
113 fprintf(stderr, "Could not create file '%s'\n",
114 filename);
115 return 1;
116 }
117 count = 0;
118 return 0;
119}
120
121
122static int sql_error_log_deinit(void *p __attribute__((unused)))
123{
124 if (logfile)
125 logger_close(logfile);
126 return 0;
127}
128
129
130static void rotate_log(MYSQL_THD thd __attribute__((unused)),
131 struct st_mysql_sys_var *var __attribute__((unused)),
132 void *var_ptr __attribute__((unused)),
133 const void *save __attribute__((unused)))
134{
135 (void) logger_rotate(logfile);
136}
137
138
139static struct st_mysql_audit descriptor =
140{
141 MYSQL_AUDIT_INTERFACE_VERSION,
142 NULL,
143 log_sql_errors,
144 { MYSQL_AUDIT_GENERAL_CLASSMASK }
145};
146
147maria_declare_plugin(sql_errlog)
148{
149 MYSQL_AUDIT_PLUGIN,
150 &descriptor,
151 "SQL_ERROR_LOG",
152 "Alexey Botchkov",
153 "Log SQL level errors to a file with rotation",
154 PLUGIN_LICENSE_GPL,
155 sql_error_log_init,
156 sql_error_log_deinit,
157 0x0100,
158 NULL,
159 vars,
160 "1.0",
161 MariaDB_PLUGIN_MATURITY_STABLE
162}
163maria_declare_plugin_end;
164