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 | |
37 | static char *filename; |
38 | static unsigned int rate; |
39 | static unsigned long long size_limit; |
40 | static unsigned int rotations; |
41 | static char rotate; |
42 | |
43 | static unsigned int count; |
44 | LOGGER_HANDLE *logfile; |
45 | |
46 | static void rotate_log(MYSQL_THD thd, struct st_mysql_sys_var *var, |
47 | void *var_ptr, const void *save); |
48 | |
49 | static 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 | |
53 | static 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 | |
57 | static MYSQL_SYSVAR_UINT(rotations, rotations, |
58 | PLUGIN_VAR_READONLY, "Number of rotations before log is removed." , |
59 | NULL, NULL, 9, 1, 999, 1); |
60 | |
61 | static MYSQL_SYSVAR_BOOL(rotate, rotate, |
62 | PLUGIN_VAR_OPCMDARG, "Force log rotation" , NULL, rotate_log, |
63 | 0); |
64 | |
65 | static 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 | |
70 | static 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 | |
80 | static 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 | |
107 | static 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 | |
122 | static int sql_error_log_deinit(void *p __attribute__((unused))) |
123 | { |
124 | if (logfile) |
125 | logger_close(logfile); |
126 | return 0; |
127 | } |
128 | |
129 | |
130 | static 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 | |
139 | static struct st_mysql_audit descriptor = |
140 | { |
141 | MYSQL_AUDIT_INTERFACE_VERSION, |
142 | NULL, |
143 | log_sql_errors, |
144 | { MYSQL_AUDIT_GENERAL_CLASSMASK } |
145 | }; |
146 | |
147 | maria_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 | } |
163 | maria_declare_plugin_end; |
164 | |