MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EventLogHandler.cpp
1 /*
2  Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #ifdef _WIN32
19 
20 #include "EventLogHandler.hpp"
21 #include "message.h"
22 
23 EventLogHandler::EventLogHandler(const char* source_name)
24  : LogHandler(),
25  m_source_name(source_name),
26  m_event_source(NULL),
27  m_level(Logger::LL_ERROR)
28 {
29 }
30 
31 
32 EventLogHandler::~EventLogHandler()
33 {
34  close();
35 }
36 
37 
38 static bool
39 check_message_resource(void)
40 {
41  // Only do check once per binary
42  static bool check_message_resource_done = false;
43  if (check_message_resource_done)
44  return true;
45  check_message_resource_done = true;
46 
47  // Each program that want to log to Windows event log need to
48  // have a message resource compiled in. Check that it's there
49  // by resolving the message from current module(.exe)
50  char* message_text;
51  if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
52  FORMAT_MESSAGE_FROM_HMODULE |
53  FORMAT_MESSAGE_IGNORE_INSERTS,
54  NULL, MSG_EVENTLOG, NULL,
55  (LPTSTR)&message_text, 0, NULL) != 0)
56  {
57  LocalFree(message_text);
58  return true;
59  }
60 
61  // Could not get message from own module, extract error
62  // message from system and print it to help debugging
63  DWORD last_err = GetLastError();
64  fprintf(stderr,
65  "This program does not seem to have the message resource "
66  "required for logging to Windows event log, error: %u ", last_err);
67  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
68  FORMAT_MESSAGE_ALLOCATE_BUFFER |
69  FORMAT_MESSAGE_IGNORE_INSERTS,
70  NULL, last_err, 0,
71  (LPSTR)&message_text, 0, NULL))
72  {
73  fprintf(stderr, "message: '%s'\n", message_text);
74  LocalFree(message_text);
75  }
76  else
77  {
78  fprintf(stderr, "message: <unknown>\n");
79  }
80  fflush(stderr);
81 
82  // The program have not been properly compiled, crash in debug mode
83  assert(false);
84  return false;
85 }
86 
87 
88 static bool
89 setup_eventlogging(const char* source_name)
90 {
91  // Check that this binary have mesage resource compiled in
92  if (!check_message_resource())
93  return false;
94 
95  char sub_key[MAX_PATH];
96  BaseString::snprintf(sub_key, sizeof(sub_key),
97  "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s",
98  source_name);
99 
100  // Create the event source registry key
101  HKEY key_handle;
102  LONG error = RegCreateKey(HKEY_LOCAL_MACHINE, sub_key, &key_handle);
103  if (error != ERROR_SUCCESS)
104  {
105  // Could neither create or open key
106  fprintf(stderr, "Could neither create or open key '%s', error: %u\n",
107  sub_key, error);
108  return false;
109  }
110 
111  /* Get path of current module and use it as message resource */
112  char module_path[MAX_PATH];
113  DWORD len = GetModuleFileName(NULL, module_path, sizeof(module_path));
114  if (len == 0 || len == sizeof(module_path))
115  {
116  fprintf(stderr,
117  "Could not extract path of module, module_len: %u, error: %u\n",
118  len, GetLastError());
119  RegCloseKey(key_handle);
120  return false;
121  }
122 
123  (void)RegSetValueEx(key_handle, "EventMessageFile", 0, REG_EXPAND_SZ,
124  (PBYTE)module_path, len + 1 );
125 
126  /* Register supported event types */
127  const DWORD event_types= (EVENTLOG_ERROR_TYPE |
128  EVENTLOG_WARNING_TYPE |
129  EVENTLOG_INFORMATION_TYPE);
130  (void)RegSetValueEx(key_handle, "TypesSupported", 0, REG_DWORD,
131  (PBYTE)&event_types, sizeof(event_types));
132 
133  RegCloseKey(key_handle);
134  return true;
135 }
136 
137 
138 bool
140 {
141  if (!setup_eventlogging(m_source_name))
142  {
143  fprintf(stderr, "Failed to setup event logging\n");
144  return false;
145  }
146 
147  m_event_source = RegisterEventSource(NULL, m_source_name);
148  if (!m_event_source)
149  {
150  fprintf(stderr, "Failed to register event source, error: %u\n",
151  GetLastError());
152  return false;
153  }
154  return true;
155 }
156 
157 
158 bool
160 {
161  if (!is_open())
162  return true;
163 
164  (void)DeregisterEventSource(m_event_source);
165 
166  return true;
167 }
168 
169 
170 bool
172 {
173  return (m_event_source != NULL);
174 }
175 
176 void
177 EventLogHandler::writeHeader(const char* pCategory, Logger::LoggerLevel level)
178 {
179  m_level = level;
180 }
181 
182 
183 static bool
184 write_event_log(HANDLE eventlog_handle, Logger::LoggerLevel level,
185  const char* msg)
186 {
187  WORD type;
188  switch(level)
189  {
190  case Logger::LL_DEBUG:
191  case Logger::LL_INFO:
192  type = EVENTLOG_INFORMATION_TYPE;
193  break;
194 
195  case Logger::LL_WARNING:
196  type = EVENTLOG_WARNING_TYPE;
197  break;
198 
199  case Logger::LL_ERROR:
200  case Logger::LL_ALERT:
201  case Logger::LL_CRITICAL:
202  type = EVENTLOG_ERROR_TYPE;
203  break;
204  }
205 
206  if (!ReportEvent(eventlog_handle, type, 0, MSG_EVENTLOG,
207  NULL, 1, 0, &msg, NULL))
208  {
209  return false;
210  }
211 
212  return true;
213 }
214 
215 
216 void
217 EventLogHandler::writeMessage(const char* msg)
218 {
219  if (!is_open())
220  return;
221 
222  if (!write_event_log(m_event_source, m_level, msg))
223  {
224  fprintf(stderr, "Failed to report event to event log, error: %u\n",
225  GetLastError());
226  }
227 }
228 
229 
230 void
231 EventLogHandler::writeFooter()
232 {
233 }
234 
235 
236 bool
237 EventLogHandler::setParam(const BaseString &param, const BaseString &value) {
238  return false;
239 }
240 
241 
242 int
243 EventLogHandler::printf(Logger::LoggerLevel level, const char* source_name,
244  const char* msg, ...)
245 {
246  if (setup_eventlogging(source_name))
247  {
248  // Failed to setup event logging
249  return -3;
250  }
251 
252  char buf[MAX_LOG_MESSAGE_SIZE];
253  va_list ap;
254  va_start(ap, msg);
255  int ret = vsnprintf_s(buf, sizeof(buf), _TRUNCATE, msg, ap);
256  va_end(ap);
257 
258  HANDLE eventlog_handle = RegisterEventSource(NULL, source_name);
259  if (!eventlog_handle)
260  {
261  // Failed to open event log
262  return -2;
263  }
264 
265  if (!write_event_log(eventlog_handle, level, buf))
266  {
267  // Failed to log, return error
268  (void)DeregisterEventSource(eventlog_handle);
269  return -1;
270  }
271 
272  (void)DeregisterEventSource(eventlog_handle);
273 
274  // Ok, return length of the logged message
275  return ret;
276 }
277 
278 #endif