1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2009-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_ctx_impl.h" |
22 | |
23 | #include <stdio.h> |
24 | #include <string.h> |
25 | #include <sys/stat.h> |
26 | |
27 | #ifdef WIN32 |
28 | # include <share.h> |
29 | #endif /* WIN32 */ |
30 | |
31 | static const char *log_level_names[] = { |
32 | "none" , |
33 | "emergency" , |
34 | "alert" , |
35 | "critical" , |
36 | "error" , |
37 | "warning" , |
38 | "notice" , |
39 | "info" , |
40 | "debug" , |
41 | "dump" |
42 | }; |
43 | |
44 | #define GRN_LOG_LAST GRN_LOG_DUMP |
45 | |
46 | const char * |
47 | grn_log_level_to_string(grn_log_level level) |
48 | { |
49 | if (level <= GRN_LOG_LAST) { |
50 | return log_level_names[level]; |
51 | } else { |
52 | return "unknown" ; |
53 | } |
54 | } |
55 | |
56 | grn_bool |
57 | grn_log_level_parse(const char *string, grn_log_level *level) |
58 | { |
59 | if (strcmp(string, " " ) == 0 || |
60 | grn_strcasecmp(string, "none" ) == 0) { |
61 | *level = GRN_LOG_NONE; |
62 | return GRN_TRUE; |
63 | } else if (strcmp(string, "E" ) == 0 || |
64 | grn_strcasecmp(string, "emerg" ) == 0 || |
65 | grn_strcasecmp(string, "emergency" ) == 0) { |
66 | *level = GRN_LOG_EMERG; |
67 | return GRN_TRUE; |
68 | } else if (strcmp(string, "A" ) == 0 || |
69 | grn_strcasecmp(string, "alert" ) == 0) { |
70 | *level = GRN_LOG_ALERT; |
71 | return GRN_TRUE; |
72 | } else if (strcmp(string, "C" ) == 0 || |
73 | grn_strcasecmp(string, "crit" ) == 0 || |
74 | grn_strcasecmp(string, "critical" ) == 0) { |
75 | *level = GRN_LOG_CRIT; |
76 | return GRN_TRUE; |
77 | } else if (strcmp(string, "e" ) == 0 || |
78 | grn_strcasecmp(string, "error" ) == 0) { |
79 | *level = GRN_LOG_ERROR; |
80 | return GRN_TRUE; |
81 | } else if (strcmp(string, "w" ) == 0 || |
82 | grn_strcasecmp(string, "warn" ) == 0 || |
83 | grn_strcasecmp(string, "warning" ) == 0) { |
84 | *level = GRN_LOG_WARNING; |
85 | return GRN_TRUE; |
86 | } else if (strcmp(string, "n" ) == 0 || |
87 | grn_strcasecmp(string, "notice" ) == 0) { |
88 | *level = GRN_LOG_NOTICE; |
89 | return GRN_TRUE; |
90 | } else if (strcmp(string, "i" ) == 0 || |
91 | grn_strcasecmp(string, "info" ) == 0) { |
92 | *level = GRN_LOG_INFO; |
93 | return GRN_TRUE; |
94 | } else if (strcmp(string, "d" ) == 0 || |
95 | grn_strcasecmp(string, "debug" ) == 0) { |
96 | *level = GRN_LOG_DEBUG; |
97 | return GRN_TRUE; |
98 | } else if (strcmp(string, "-" ) == 0 || |
99 | grn_strcasecmp(string, "dump" ) == 0) { |
100 | *level = GRN_LOG_DUMP; |
101 | return GRN_TRUE; |
102 | } else { |
103 | return GRN_FALSE; |
104 | } |
105 | } |
106 | |
107 | static void |
108 | rotate_log_file(grn_ctx *ctx, const char *current_path) |
109 | { |
110 | char rotated_path[PATH_MAX]; |
111 | grn_timeval now; |
112 | struct tm tm_buffer; |
113 | struct tm *tm; |
114 | |
115 | grn_timeval_now(ctx, &now); |
116 | tm = grn_timeval2tm(ctx, &now, &tm_buffer); |
117 | grn_snprintf(rotated_path, PATH_MAX, PATH_MAX, |
118 | "%s.%04d-%02d-%02d-%02d-%02d-%02d-%06d" , |
119 | current_path, |
120 | tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
121 | tm->tm_hour, tm->tm_min, tm->tm_sec, |
122 | (int)(GRN_TIME_NSEC_TO_USEC(now.tv_nsec))); |
123 | rename(current_path, rotated_path); |
124 | } |
125 | |
126 | static grn_bool logger_inited = GRN_FALSE; |
127 | static char *default_logger_path = NULL; |
128 | static FILE *default_logger_file = NULL; |
129 | static grn_critical_section default_logger_lock; |
130 | static off_t default_logger_size = 0; |
131 | static off_t default_logger_rotate_threshold_size = 0; |
132 | |
133 | #define LOGGER_NEED_ROTATE(size, threshold) \ |
134 | ((threshold) > 0 && (size) >= (threshold)) |
135 | |
136 | static void |
137 | default_logger_log(grn_ctx *ctx, grn_log_level level, |
138 | const char *timestamp, const char *title, |
139 | const char *message, const char *location, void *user_data) |
140 | { |
141 | const char slev[] = " EACewnid-" ; |
142 | if (default_logger_path) { |
143 | CRITICAL_SECTION_ENTER(default_logger_lock); |
144 | if (!default_logger_file) { |
145 | default_logger_file = grn_fopen(default_logger_path, "a" ); |
146 | default_logger_size = 0; |
147 | if (default_logger_file) { |
148 | struct stat stat; |
149 | if (fstat(grn_fileno(default_logger_file), &stat) != -1) { |
150 | default_logger_size = stat.st_size; |
151 | } |
152 | } |
153 | } |
154 | if (default_logger_file) { |
155 | char label = *(slev + level); |
156 | int written; |
157 | if (location && *location) { |
158 | if (title && *title) { |
159 | written = fprintf(default_logger_file, "%s|%c|%s: %s %s\n" , |
160 | timestamp, label, location, title, message); |
161 | } else { |
162 | written = fprintf(default_logger_file, "%s|%c|%s: %s\n" , |
163 | timestamp, label, location, message); |
164 | } |
165 | } else { |
166 | written = fprintf(default_logger_file, "%s|%c|%s %s\n" , |
167 | timestamp, label, title, message); |
168 | } |
169 | if (written > 0) { |
170 | default_logger_size += written; |
171 | if (LOGGER_NEED_ROTATE(default_logger_size, |
172 | default_logger_rotate_threshold_size)) { |
173 | fclose(default_logger_file); |
174 | default_logger_file = NULL; |
175 | rotate_log_file(ctx, default_logger_path); |
176 | } else { |
177 | fflush(default_logger_file); |
178 | } |
179 | } |
180 | } |
181 | CRITICAL_SECTION_LEAVE(default_logger_lock); |
182 | } |
183 | } |
184 | |
185 | static void |
186 | default_logger_reopen(grn_ctx *ctx, void *user_data) |
187 | { |
188 | GRN_LOG(ctx, GRN_LOG_NOTICE, "log will be closed." ); |
189 | CRITICAL_SECTION_ENTER(default_logger_lock); |
190 | if (default_logger_file) { |
191 | fclose(default_logger_file); |
192 | default_logger_file = NULL; |
193 | } |
194 | CRITICAL_SECTION_LEAVE(default_logger_lock); |
195 | GRN_LOG(ctx, GRN_LOG_NOTICE, "log opened." ); |
196 | } |
197 | |
198 | static void |
199 | default_logger_fin(grn_ctx *ctx, void *user_data) |
200 | { |
201 | CRITICAL_SECTION_ENTER(default_logger_lock); |
202 | if (default_logger_file) { |
203 | fclose(default_logger_file); |
204 | default_logger_file = NULL; |
205 | } |
206 | CRITICAL_SECTION_LEAVE(default_logger_lock); |
207 | } |
208 | |
209 | static grn_logger default_logger = { |
210 | GRN_LOG_DEFAULT_LEVEL, |
211 | GRN_LOG_TIME|GRN_LOG_MESSAGE, |
212 | NULL, |
213 | default_logger_log, |
214 | default_logger_reopen, |
215 | default_logger_fin |
216 | }; |
217 | |
218 | #define INITIAL_LOGGER { \ |
219 | GRN_LOG_DEFAULT_LEVEL, \ |
220 | GRN_LOG_TIME|GRN_LOG_MESSAGE, \ |
221 | NULL, \ |
222 | NULL, \ |
223 | NULL, \ |
224 | NULL \ |
225 | } |
226 | |
227 | static grn_logger current_logger = INITIAL_LOGGER; |
228 | |
229 | void |
230 | grn_default_logger_set_max_level(grn_log_level max_level) |
231 | { |
232 | default_logger.max_level = max_level; |
233 | if (current_logger.log == default_logger_log) { |
234 | current_logger.max_level = max_level; |
235 | } |
236 | } |
237 | |
238 | grn_log_level |
239 | grn_default_logger_get_max_level(void) |
240 | { |
241 | return default_logger.max_level; |
242 | } |
243 | |
244 | void |
245 | grn_default_logger_set_flags(int flags) |
246 | { |
247 | default_logger.flags = flags; |
248 | if (current_logger.log == default_logger_log) { |
249 | current_logger.flags = flags; |
250 | } |
251 | } |
252 | |
253 | int |
254 | grn_default_logger_get_flags(void) |
255 | { |
256 | return default_logger.flags; |
257 | } |
258 | |
259 | void |
260 | grn_default_logger_set_path(const char *path) |
261 | { |
262 | if (logger_inited) { |
263 | CRITICAL_SECTION_ENTER(default_logger_lock); |
264 | } |
265 | |
266 | if (default_logger_path) { |
267 | free(default_logger_path); |
268 | } |
269 | |
270 | if (path) { |
271 | default_logger_path = grn_strdup_raw(path); |
272 | } else { |
273 | default_logger_path = NULL; |
274 | } |
275 | |
276 | if (logger_inited) { |
277 | CRITICAL_SECTION_LEAVE(default_logger_lock); |
278 | } |
279 | } |
280 | |
281 | const char * |
282 | grn_default_logger_get_path(void) |
283 | { |
284 | return default_logger_path; |
285 | } |
286 | |
287 | void |
288 | grn_default_logger_set_rotate_threshold_size(off_t threshold) |
289 | { |
290 | default_logger_rotate_threshold_size = threshold; |
291 | } |
292 | |
293 | off_t |
294 | grn_default_logger_get_rotate_threshold_size(void) |
295 | { |
296 | return default_logger_rotate_threshold_size; |
297 | } |
298 | |
299 | void |
300 | grn_logger_reopen(grn_ctx *ctx) |
301 | { |
302 | if (current_logger.reopen) { |
303 | current_logger.reopen(ctx, current_logger.user_data); |
304 | } |
305 | } |
306 | |
307 | static void |
308 | current_logger_fin(grn_ctx *ctx) |
309 | { |
310 | if (current_logger.fin) { |
311 | current_logger.fin(ctx, current_logger.user_data); |
312 | } |
313 | { |
314 | grn_logger initial_logger = INITIAL_LOGGER; |
315 | current_logger = initial_logger; |
316 | } |
317 | } |
318 | |
319 | static void |
320 | logger_info_func_wrapper(grn_ctx *ctx, grn_log_level level, |
321 | const char *timestamp, const char *title, |
322 | const char *message, const char *location, |
323 | void *user_data) |
324 | { |
325 | grn_logger_info *info = user_data; |
326 | info->func(level, timestamp, title, message, location, info->func_arg); |
327 | } |
328 | |
329 | /* Deprecated since 2.1.2. */ |
330 | grn_rc |
331 | grn_logger_info_set(grn_ctx *ctx, const grn_logger_info *info) |
332 | { |
333 | if (info) { |
334 | grn_logger logger; |
335 | |
336 | memset(&logger, 0, sizeof(grn_logger)); |
337 | logger.max_level = info->max_level; |
338 | logger.flags = info->flags; |
339 | if (info->func) { |
340 | logger.log = logger_info_func_wrapper; |
341 | logger.user_data = (grn_logger_info *)info; |
342 | } else { |
343 | logger.log = default_logger_log; |
344 | logger.reopen = default_logger_reopen; |
345 | logger.fin = default_logger_fin; |
346 | } |
347 | return grn_logger_set(ctx, &logger); |
348 | } else { |
349 | return grn_logger_set(ctx, NULL); |
350 | } |
351 | } |
352 | |
353 | grn_rc |
354 | grn_logger_set(grn_ctx *ctx, const grn_logger *logger) |
355 | { |
356 | current_logger_fin(ctx); |
357 | if (logger) { |
358 | current_logger = *logger; |
359 | } else { |
360 | current_logger = default_logger; |
361 | } |
362 | return GRN_SUCCESS; |
363 | } |
364 | |
365 | void |
366 | grn_logger_set_max_level(grn_ctx *ctx, grn_log_level max_level) |
367 | { |
368 | current_logger.max_level = max_level; |
369 | } |
370 | |
371 | grn_log_level |
372 | grn_logger_get_max_level(grn_ctx *ctx) |
373 | { |
374 | return current_logger.max_level; |
375 | } |
376 | |
377 | grn_bool |
378 | grn_logger_pass(grn_ctx *ctx, grn_log_level level) |
379 | { |
380 | return level <= current_logger.max_level; |
381 | } |
382 | |
383 | #define TBUFSIZE GRN_TIMEVAL_STR_SIZE |
384 | #define MBUFSIZE 0x1000 |
385 | #define LBUFSIZE 0x400 |
386 | |
387 | void |
388 | grn_logger_put(grn_ctx *ctx, |
389 | grn_log_level level, |
390 | const char *file, |
391 | int line, |
392 | const char *func, |
393 | const char *fmt, |
394 | ...) |
395 | { |
396 | va_list ap; |
397 | va_start(ap, fmt); |
398 | grn_logger_putv(ctx, level, file, line, func, fmt, ap); |
399 | va_end(ap); |
400 | } |
401 | |
402 | void |
403 | grn_logger_putv(grn_ctx *ctx, |
404 | grn_log_level level, |
405 | const char *file, |
406 | int line, |
407 | const char *func, |
408 | const char *fmt, |
409 | va_list ap) |
410 | { |
411 | if (level <= current_logger.max_level && current_logger.log) { |
412 | char tbuf[TBUFSIZE]; |
413 | char mbuf[MBUFSIZE]; |
414 | char lbuf[LBUFSIZE]; |
415 | tbuf[0] = '\0'; |
416 | if (current_logger.flags & GRN_LOG_TIME) { |
417 | grn_timeval tv; |
418 | grn_timeval_now(ctx, &tv); |
419 | grn_timeval2str(ctx, &tv, tbuf, TBUFSIZE); |
420 | } |
421 | if (current_logger.flags & GRN_LOG_MESSAGE) { |
422 | grn_vsnprintf(mbuf, MBUFSIZE, fmt, ap); |
423 | } else { |
424 | mbuf[0] = '\0'; |
425 | } |
426 | if (current_logger.flags & GRN_LOG_LOCATION) { |
427 | grn_snprintf(lbuf, LBUFSIZE, LBUFSIZE, |
428 | "%d %s:%d %s()" , grn_getpid(), file, line, func); |
429 | } else if (current_logger.flags & GRN_LOG_PID) { |
430 | grn_snprintf(lbuf, LBUFSIZE, LBUFSIZE, |
431 | "%d" , grn_getpid()); |
432 | } else { |
433 | lbuf[0] = '\0'; |
434 | } |
435 | current_logger.log(ctx, level, tbuf, "" , mbuf, lbuf, |
436 | current_logger.user_data); |
437 | } |
438 | } |
439 | |
440 | void |
441 | grn_logger_init(void) |
442 | { |
443 | CRITICAL_SECTION_INIT(default_logger_lock); |
444 | if (!current_logger.log) { |
445 | current_logger = default_logger; |
446 | } |
447 | |
448 | logger_inited = GRN_TRUE; |
449 | } |
450 | |
451 | void |
452 | grn_logger_fin(grn_ctx *ctx) |
453 | { |
454 | current_logger_fin(ctx); |
455 | if (default_logger_path) { |
456 | free(default_logger_path); |
457 | default_logger_path = NULL; |
458 | } |
459 | CRITICAL_SECTION_FIN(default_logger_lock); |
460 | |
461 | logger_inited = GRN_FALSE; |
462 | } |
463 | |
464 | |
465 | static grn_bool query_logger_inited = GRN_FALSE; |
466 | static char *default_query_logger_path = NULL; |
467 | static FILE *default_query_logger_file = NULL; |
468 | static grn_critical_section default_query_logger_lock; |
469 | static off_t default_query_logger_size = 0; |
470 | static off_t default_query_logger_rotate_threshold_size = 0; |
471 | |
472 | grn_bool |
473 | grn_query_log_flags_parse(const char *string, |
474 | int string_size, |
475 | unsigned int *flags) |
476 | { |
477 | const char *string_end; |
478 | |
479 | *flags = GRN_QUERY_LOG_NONE; |
480 | |
481 | if (!string) { |
482 | return GRN_TRUE; |
483 | } |
484 | |
485 | if (string_size < 0) { |
486 | string_size = strlen(string); |
487 | } |
488 | |
489 | string_end = string + string_size; |
490 | |
491 | while (string < string_end) { |
492 | if (*string == '|' || *string == ' ') { |
493 | string += 1; |
494 | continue; |
495 | } |
496 | |
497 | #define CHECK_FLAG(name) \ |
498 | if (((string_end - string) >= (sizeof(#name) - 1)) && \ |
499 | (memcmp(string, #name, sizeof(#name) - 1) == 0) && \ |
500 | (((string_end - string) == (sizeof(#name) - 1)) || \ |
501 | (string[sizeof(#name) - 1] == '|') || \ |
502 | (string[sizeof(#name) - 1] == ' '))) { \ |
503 | *flags |= GRN_QUERY_LOG_ ## name; \ |
504 | string += sizeof(#name) - 1; \ |
505 | continue; \ |
506 | } |
507 | |
508 | CHECK_FLAG(NONE); |
509 | CHECK_FLAG(COMMAND); |
510 | CHECK_FLAG(RESULT_CODE); |
511 | CHECK_FLAG(DESTINATION); |
512 | CHECK_FLAG(CACHE); |
513 | CHECK_FLAG(SIZE); |
514 | CHECK_FLAG(SCORE); |
515 | CHECK_FLAG(ALL); |
516 | CHECK_FLAG(DEFAULT); |
517 | |
518 | #undef CHECK_FLAG |
519 | |
520 | return GRN_FALSE; |
521 | } |
522 | |
523 | return GRN_TRUE; |
524 | } |
525 | |
526 | static void |
527 | default_query_logger_log(grn_ctx *ctx, unsigned int flag, |
528 | const char *timestamp, const char *info, |
529 | const char *message, void *user_data) |
530 | { |
531 | if (default_query_logger_path) { |
532 | CRITICAL_SECTION_ENTER(default_query_logger_lock); |
533 | if (!default_query_logger_file) { |
534 | default_query_logger_file = grn_fopen(default_query_logger_path, "a" ); |
535 | default_query_logger_size = 0; |
536 | if (default_query_logger_file) { |
537 | struct stat stat; |
538 | if (fstat(grn_fileno(default_query_logger_file), &stat) != -1) { |
539 | default_query_logger_size = stat.st_size; |
540 | } |
541 | } |
542 | } |
543 | if (default_query_logger_file) { |
544 | int written; |
545 | written = fprintf(default_query_logger_file, "%s|%s%s\n" , |
546 | timestamp, info, message); |
547 | if (written > 0) { |
548 | default_query_logger_size += written; |
549 | if (LOGGER_NEED_ROTATE(default_query_logger_size, |
550 | default_query_logger_rotate_threshold_size)) { |
551 | fclose(default_query_logger_file); |
552 | default_query_logger_file = NULL; |
553 | rotate_log_file(ctx, default_query_logger_path); |
554 | } else { |
555 | fflush(default_query_logger_file); |
556 | } |
557 | } |
558 | } |
559 | CRITICAL_SECTION_LEAVE(default_query_logger_lock); |
560 | } |
561 | } |
562 | |
563 | static void |
564 | default_query_logger_close(grn_ctx *ctx, void *user_data) |
565 | { |
566 | GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_DESTINATION, " " , |
567 | "query log will be closed: <%s>" , default_query_logger_path); |
568 | CRITICAL_SECTION_ENTER(default_query_logger_lock); |
569 | if (default_query_logger_file) { |
570 | fclose(default_query_logger_file); |
571 | default_query_logger_file = NULL; |
572 | } |
573 | CRITICAL_SECTION_LEAVE(default_query_logger_lock); |
574 | } |
575 | |
576 | static void |
577 | default_query_logger_reopen(grn_ctx *ctx, void *user_data) |
578 | { |
579 | default_query_logger_close(ctx, user_data); |
580 | if (default_query_logger_path) { |
581 | GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_DESTINATION, " " , |
582 | "query log is opened: <%s>" , default_query_logger_path); |
583 | } |
584 | } |
585 | |
586 | static void |
587 | default_query_logger_fin(grn_ctx *ctx, void *user_data) |
588 | { |
589 | if (default_query_logger_file) { |
590 | default_query_logger_close(ctx, user_data); |
591 | } |
592 | } |
593 | |
594 | static grn_query_logger default_query_logger = { |
595 | GRN_QUERY_LOG_DEFAULT, |
596 | NULL, |
597 | default_query_logger_log, |
598 | default_query_logger_reopen, |
599 | default_query_logger_fin |
600 | }; |
601 | |
602 | #define INITIAL_QUERY_LOGGER { \ |
603 | GRN_QUERY_LOG_DEFAULT, \ |
604 | NULL, \ |
605 | NULL, \ |
606 | NULL, \ |
607 | NULL \ |
608 | } |
609 | |
610 | static grn_query_logger current_query_logger = INITIAL_QUERY_LOGGER; |
611 | |
612 | void |
613 | grn_default_query_logger_set_flags(unsigned int flags) |
614 | { |
615 | default_query_logger.flags = flags; |
616 | if (current_query_logger.log == default_query_logger_log) { |
617 | current_query_logger.flags = flags; |
618 | } |
619 | } |
620 | |
621 | unsigned int |
622 | grn_default_query_logger_get_flags(void) |
623 | { |
624 | return default_query_logger.flags; |
625 | } |
626 | |
627 | void |
628 | grn_default_query_logger_set_path(const char *path) |
629 | { |
630 | if (query_logger_inited) { |
631 | CRITICAL_SECTION_ENTER(default_query_logger_lock); |
632 | } |
633 | |
634 | if (default_query_logger_path) { |
635 | free(default_query_logger_path); |
636 | } |
637 | |
638 | if (path) { |
639 | default_query_logger_path = grn_strdup_raw(path); |
640 | } else { |
641 | default_query_logger_path = NULL; |
642 | } |
643 | |
644 | if (query_logger_inited) { |
645 | CRITICAL_SECTION_LEAVE(default_query_logger_lock); |
646 | } |
647 | } |
648 | |
649 | const char * |
650 | grn_default_query_logger_get_path(void) |
651 | { |
652 | return default_query_logger_path; |
653 | } |
654 | |
655 | void |
656 | grn_default_query_logger_set_rotate_threshold_size(off_t threshold) |
657 | { |
658 | default_query_logger_rotate_threshold_size = threshold; |
659 | } |
660 | |
661 | off_t |
662 | grn_default_query_logger_get_rotate_threshold_size(void) |
663 | { |
664 | return default_query_logger_rotate_threshold_size; |
665 | } |
666 | |
667 | void |
668 | grn_query_logger_reopen(grn_ctx *ctx) |
669 | { |
670 | if (current_query_logger.reopen) { |
671 | current_query_logger.reopen(ctx, current_query_logger.user_data); |
672 | } |
673 | } |
674 | |
675 | static void |
676 | current_query_logger_fin(grn_ctx *ctx) |
677 | { |
678 | if (current_query_logger.fin) { |
679 | current_query_logger.fin(ctx, current_query_logger.user_data); |
680 | } |
681 | { |
682 | grn_query_logger initial_query_logger = INITIAL_QUERY_LOGGER; |
683 | current_query_logger = initial_query_logger; |
684 | } |
685 | } |
686 | |
687 | grn_rc |
688 | grn_query_logger_set(grn_ctx *ctx, const grn_query_logger *logger) |
689 | { |
690 | current_query_logger_fin(ctx); |
691 | if (logger) { |
692 | current_query_logger = *logger; |
693 | } else { |
694 | current_query_logger = default_query_logger; |
695 | } |
696 | return GRN_SUCCESS; |
697 | } |
698 | |
699 | void |
700 | grn_query_logger_set_flags(grn_ctx *ctx, unsigned int flags) |
701 | { |
702 | current_query_logger.flags = flags; |
703 | } |
704 | |
705 | void |
706 | grn_query_logger_add_flags(grn_ctx *ctx, unsigned int flags) |
707 | { |
708 | current_query_logger.flags |= flags; |
709 | } |
710 | |
711 | void |
712 | grn_query_logger_remove_flags(grn_ctx *ctx, unsigned int flags) |
713 | { |
714 | current_query_logger.flags &= ~flags; |
715 | } |
716 | |
717 | unsigned int |
718 | grn_query_logger_get_flags(grn_ctx *ctx) |
719 | { |
720 | return current_query_logger.flags; |
721 | } |
722 | |
723 | grn_bool |
724 | grn_query_logger_pass(grn_ctx *ctx, unsigned int flag) |
725 | { |
726 | return current_query_logger.flags & flag; |
727 | } |
728 | |
729 | #define TIMESTAMP_BUFFER_SIZE TBUFSIZE |
730 | /* 8+a(%p) + 1(|) + 1(mark) + 15(elapsed time) = 25+a */ |
731 | #define INFO_BUFFER_SIZE 40 |
732 | |
733 | void |
734 | grn_query_logger_put(grn_ctx *ctx, unsigned int flag, const char *mark, |
735 | const char *format, ...) |
736 | { |
737 | char timestamp[TIMESTAMP_BUFFER_SIZE]; |
738 | char info[INFO_BUFFER_SIZE]; |
739 | grn_obj *message = &ctx->impl->query_log_buf; |
740 | |
741 | if (!current_query_logger.log) { |
742 | return; |
743 | } |
744 | |
745 | { |
746 | grn_timeval tv; |
747 | timestamp[0] = '\0'; |
748 | grn_timeval_now(ctx, &tv); |
749 | grn_timeval2str(ctx, &tv, timestamp, TIMESTAMP_BUFFER_SIZE); |
750 | } |
751 | |
752 | if (flag & (GRN_QUERY_LOG_COMMAND | GRN_QUERY_LOG_DESTINATION)) { |
753 | grn_snprintf(info, INFO_BUFFER_SIZE, INFO_BUFFER_SIZE, |
754 | "%p|%s" , ctx, mark); |
755 | info[INFO_BUFFER_SIZE - 1] = '\0'; |
756 | } else { |
757 | grn_timeval tv; |
758 | uint64_t elapsed_time; |
759 | grn_timeval_now(ctx, &tv); |
760 | elapsed_time = |
761 | (uint64_t)(tv.tv_sec - ctx->impl->tv.tv_sec) * GRN_TIME_NSEC_PER_SEC + |
762 | (tv.tv_nsec - ctx->impl->tv.tv_nsec); |
763 | |
764 | grn_snprintf(info, INFO_BUFFER_SIZE, INFO_BUFFER_SIZE, |
765 | "%p|%s%015" GRN_FMT_INT64U " " , ctx, mark, elapsed_time); |
766 | info[INFO_BUFFER_SIZE - 1] = '\0'; |
767 | } |
768 | |
769 | { |
770 | va_list args; |
771 | |
772 | va_start(args, format); |
773 | GRN_BULK_REWIND(message); |
774 | grn_text_vprintf(ctx, message, format, args); |
775 | va_end(args); |
776 | GRN_TEXT_PUTC(ctx, message, '\0'); |
777 | } |
778 | |
779 | current_query_logger.log(ctx, flag, timestamp, info, GRN_TEXT_VALUE(message), |
780 | current_query_logger.user_data); |
781 | } |
782 | |
783 | void |
784 | grn_query_logger_init(void) |
785 | { |
786 | current_query_logger = default_query_logger; |
787 | CRITICAL_SECTION_INIT(default_query_logger_lock); |
788 | |
789 | query_logger_inited = GRN_TRUE; |
790 | } |
791 | |
792 | void |
793 | grn_query_logger_fin(grn_ctx *ctx) |
794 | { |
795 | current_query_logger_fin(ctx); |
796 | if (default_query_logger_path) { |
797 | free(default_query_logger_path); |
798 | default_query_logger_path = NULL; |
799 | } |
800 | CRITICAL_SECTION_FIN(default_query_logger_lock); |
801 | |
802 | query_logger_inited = GRN_FALSE; |
803 | } |
804 | |
805 | void |
806 | grn_log_reopen(grn_ctx *ctx) |
807 | { |
808 | grn_logger_reopen(ctx); |
809 | grn_query_logger_reopen(ctx); |
810 | } |
811 | |