1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2015-2017 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "grn_logger.h"
20#include "grn_ctx.h"
21#include "grn_windows.h"
22
23#include <string.h>
24
25#ifdef WIN32
26
27typedef struct _grn_windows_event_logger_data {
28 char *event_source_name;
29 HANDLE event_source;
30} grn_windows_event_logger_data;
31
32static void
33windows_event_logger_log(grn_ctx *ctx, grn_log_level level,
34 const char *timestamp, const char *title,
35 const char *message, const char *location,
36 void *user_data)
37{
38 grn_windows_event_logger_data *data = user_data;
39 WORD type;
40 WORD category = 0;
41 DWORD event_id = 0;
42 PSID user_sid = NULL;
43 WORD n_strings = 1;
44 DWORD event_data_size = 0;
45 const WCHAR *strings[1];
46 LPVOID event_data = NULL;
47 const char level_marks[] = " EACewnid-";
48 grn_obj formatted_buffer;
49 UINT code_page;
50 DWORD convert_flags = 0;
51 int n_converted_chars;
52
53 switch (level) {
54 case GRN_LOG_NONE :
55 return;
56 break;
57 case GRN_LOG_EMERG :
58 case GRN_LOG_ALERT :
59 case GRN_LOG_CRIT :
60 case GRN_LOG_ERROR :
61 type = EVENTLOG_ERROR_TYPE;
62 break;
63 case GRN_LOG_WARNING :
64 type = EVENTLOG_WARNING_TYPE;
65 break;
66 case GRN_LOG_NOTICE :
67 case GRN_LOG_INFO :
68 case GRN_LOG_DEBUG :
69 case GRN_LOG_DUMP :
70 type = EVENTLOG_INFORMATION_TYPE;
71 break;
72 default :
73 type = EVENTLOG_ERROR_TYPE;
74 break;
75 }
76
77 if (data->event_source == INVALID_HANDLE_VALUE) {
78 data->event_source = RegisterEventSourceA(NULL, data->event_source_name);
79 if (data->event_source == INVALID_HANDLE_VALUE) {
80 return;
81 }
82 }
83
84 GRN_TEXT_INIT(&formatted_buffer, 0);
85 if (location && location[0]) {
86 grn_text_printf(ctx, &formatted_buffer, "%s|%c|%s %s %s",
87 timestamp, level_marks[level], title, message, location);
88 } else {
89 grn_text_printf(ctx, &formatted_buffer, "%s|%c|%s %s",
90 timestamp, level_marks[level], title, message);
91 }
92
93 code_page = grn_windows_encoding_to_code_page(ctx->encoding);
94
95 n_converted_chars = MultiByteToWideChar(code_page,
96 convert_flags,
97 GRN_TEXT_VALUE(&formatted_buffer),
98 GRN_TEXT_LEN(&formatted_buffer),
99 NULL,
100 0);
101#define CONVERTED_BUFFER_SIZE 512
102 if (n_converted_chars < CONVERTED_BUFFER_SIZE) {
103 WCHAR converted_buffer[CONVERTED_BUFFER_SIZE];
104 n_converted_chars = MultiByteToWideChar(code_page,
105 convert_flags,
106 GRN_TEXT_VALUE(&formatted_buffer),
107 GRN_TEXT_LEN(&formatted_buffer),
108 converted_buffer,
109 CONVERTED_BUFFER_SIZE);
110 converted_buffer[n_converted_chars] = L'\0';
111 strings[0] = converted_buffer;
112 ReportEventW(data->event_source, type, category, event_id, user_sid,
113 n_strings, event_data_size,
114 strings, event_data);
115#undef CONVERTED_BUFFER_SIZE
116 } else {
117 WCHAR *converted;
118 converted = GRN_MALLOCN(WCHAR, n_converted_chars);
119 n_converted_chars = MultiByteToWideChar(code_page,
120 convert_flags,
121 GRN_TEXT_VALUE(&formatted_buffer),
122 GRN_TEXT_LEN(&formatted_buffer),
123 converted,
124 n_converted_chars);
125 converted[n_converted_chars] = L'\0';
126 strings[0] = converted;
127 ReportEventW(data->event_source, type, category, event_id, user_sid,
128 n_strings, event_data_size,
129 strings, event_data);
130 GRN_FREE(converted);
131 }
132 GRN_OBJ_FIN(ctx, &formatted_buffer);
133}
134
135static void
136windows_event_logger_reopen(grn_ctx *ctx, void *user_data)
137{
138}
139
140static void
141windows_event_logger_fin(grn_ctx *ctx, void *user_data)
142{
143 grn_windows_event_logger_data *data = user_data;
144
145 free(data->event_source_name);
146 if (data->event_source != INVALID_HANDLE_VALUE) {
147 DeregisterEventSource(data->event_source);
148 }
149 free(data);
150}
151#endif /* WIN32 */
152
153grn_rc
154grn_windows_event_logger_set(grn_ctx *ctx, const char *event_source_name)
155{
156#ifdef WIN32
157 grn_rc rc;
158 grn_logger windows_event_logger;
159 grn_windows_event_logger_data *data;
160
161 if (ctx) {
162 GRN_API_ENTER;
163 }
164
165 data = malloc(sizeof(grn_windows_event_logger_data));
166 if (!data) {
167 if (ctx) {
168 ERR(GRN_NO_MEMORY_AVAILABLE,
169 "failed to allocate user data for Windows event logger");
170 GRN_API_RETURN(ctx->rc);
171 } else {
172 return GRN_NO_MEMORY_AVAILABLE;
173 }
174 }
175
176 if (event_source_name) {
177 data->event_source_name = grn_strdup_raw(event_source_name);
178 } else {
179 data->event_source_name = grn_strdup_raw("libgroonga");
180 }
181 data->event_source = INVALID_HANDLE_VALUE;
182
183 windows_event_logger.max_level = GRN_LOG_DEFAULT_LEVEL;
184 windows_event_logger.flags = GRN_LOG_TIME | GRN_LOG_MESSAGE;
185 windows_event_logger.user_data = data;
186 windows_event_logger.log = windows_event_logger_log;
187 windows_event_logger.reopen = windows_event_logger_reopen;
188 windows_event_logger.fin = windows_event_logger_fin;
189
190 rc = grn_logger_set(ctx, &windows_event_logger);
191 if (rc != GRN_SUCCESS) {
192 windows_event_logger.fin(ctx, windows_event_logger.user_data);
193 }
194
195 if (ctx) {
196 GRN_API_RETURN(rc);
197 } else {
198 return rc;
199 }
200#else /* WIN32 */
201 return GRN_FUNCTION_NOT_IMPLEMENTED;
202#endif /* WIN32 */
203}
204