mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			810 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			810 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* -*- c-basic-offset: 2 -*- */
 | |
| /*
 | |
|   Copyright(C) 2009-2017 Brazil
 | |
| 
 | |
|   This library is free software; you can redistribute it and/or
 | |
|   modify it under the terms of the GNU Lesser General Public
 | |
|   License version 2.1 as published by the Free Software Foundation.
 | |
| 
 | |
|   This library is distributed in the hope that it will be useful,
 | |
|   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|   Lesser General Public License for more details.
 | |
| 
 | |
|   You should have received a copy of the GNU Lesser General Public
 | |
|   License along with this library; if not, write to the Free Software
 | |
|   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
 | |
| */
 | |
| 
 | |
| #include "grn_logger.h"
 | |
| #include "grn_ctx.h"
 | |
| #include "grn_ctx_impl.h"
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <sys/stat.h>
 | |
| 
 | |
| #ifdef WIN32
 | |
| # include <share.h>
 | |
| #endif /* WIN32 */
 | |
| 
 | |
| static const char *log_level_names[] = {
 | |
|   "none",
 | |
|   "emergency",
 | |
|   "alert",
 | |
|   "critical",
 | |
|   "error",
 | |
|   "warning",
 | |
|   "notice",
 | |
|   "info",
 | |
|   "debug",
 | |
|   "dump"
 | |
| };
 | |
| 
 | |
| #define GRN_LOG_LAST GRN_LOG_DUMP
 | |
| 
 | |
| const char *
 | |
| grn_log_level_to_string(grn_log_level level)
 | |
| {
 | |
|   if (level <= GRN_LOG_LAST) {
 | |
|     return log_level_names[level];
 | |
|   } else {
 | |
|     return "unknown";
 | |
|   }
 | |
| }
 | |
| 
 | |
| grn_bool
 | |
| grn_log_level_parse(const char *string, grn_log_level *level)
 | |
| {
 | |
|   if (strcmp(string, " ") == 0 ||
 | |
|       grn_strcasecmp(string, "none") == 0) {
 | |
|     *level = GRN_LOG_NONE;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "E") == 0 ||
 | |
|              grn_strcasecmp(string, "emerg") == 0 ||
 | |
|              grn_strcasecmp(string, "emergency") == 0) {
 | |
|     *level = GRN_LOG_EMERG;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "A") == 0 ||
 | |
|              grn_strcasecmp(string, "alert") == 0) {
 | |
|     *level = GRN_LOG_ALERT;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "C") == 0 ||
 | |
|              grn_strcasecmp(string, "crit") == 0 ||
 | |
|              grn_strcasecmp(string, "critical") == 0) {
 | |
|     *level = GRN_LOG_CRIT;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "e") == 0 ||
 | |
|              grn_strcasecmp(string, "error") == 0) {
 | |
|     *level = GRN_LOG_ERROR;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "w") == 0 ||
 | |
|              grn_strcasecmp(string, "warn") == 0 ||
 | |
|              grn_strcasecmp(string, "warning") == 0) {
 | |
|     *level = GRN_LOG_WARNING;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "n") == 0 ||
 | |
|              grn_strcasecmp(string, "notice") == 0) {
 | |
|     *level = GRN_LOG_NOTICE;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "i") == 0 ||
 | |
|              grn_strcasecmp(string, "info") == 0) {
 | |
|     *level = GRN_LOG_INFO;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "d") == 0 ||
 | |
|              grn_strcasecmp(string, "debug") == 0) {
 | |
|     *level = GRN_LOG_DEBUG;
 | |
|     return GRN_TRUE;
 | |
|   } else if (strcmp(string, "-") == 0 ||
 | |
|              grn_strcasecmp(string, "dump") == 0) {
 | |
|     *level = GRN_LOG_DUMP;
 | |
|     return GRN_TRUE;
 | |
|   } else {
 | |
|     return GRN_FALSE;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| rotate_log_file(grn_ctx *ctx, const char *current_path)
 | |
| {
 | |
|   char rotated_path[PATH_MAX];
 | |
|   grn_timeval now;
 | |
|   struct tm tm_buffer;
 | |
|   struct tm *tm;
 | |
| 
 | |
|   grn_timeval_now(ctx, &now);
 | |
|   tm = grn_timeval2tm(ctx, &now, &tm_buffer);
 | |
|   grn_snprintf(rotated_path, PATH_MAX, PATH_MAX,
 | |
|                "%s.%04d-%02d-%02d-%02d-%02d-%02d-%06d",
 | |
|                current_path,
 | |
|                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
 | |
|                tm->tm_hour, tm->tm_min, tm->tm_sec,
 | |
|                (int)(GRN_TIME_NSEC_TO_USEC(now.tv_nsec)));
 | |
|   rename(current_path, rotated_path);
 | |
| }
 | |
| 
 | |
| static grn_bool logger_inited = GRN_FALSE;
 | |
| static char *default_logger_path = NULL;
 | |
| static FILE *default_logger_file = NULL;
 | |
| static grn_critical_section default_logger_lock;
 | |
| static off_t default_logger_size = 0;
 | |
| static off_t default_logger_rotate_threshold_size = 0;
 | |
| 
 | |
| #define LOGGER_NEED_ROTATE(size, threshold) \
 | |
|   ((threshold) > 0 && (size) >= (threshold))
 | |
| 
 | |
| static void
 | |
| default_logger_log(grn_ctx *ctx, grn_log_level level,
 | |
|                    const char *timestamp, const char *title,
 | |
|                    const char *message, const char *location, void *user_data)
 | |
| {
 | |
|   const char slev[] = " EACewnid-";
 | |
|   if (default_logger_path) {
 | |
|     CRITICAL_SECTION_ENTER(default_logger_lock);
 | |
|     if (!default_logger_file) {
 | |
|       default_logger_file = grn_fopen(default_logger_path, "a");
 | |
|       default_logger_size = 0;
 | |
|       if (default_logger_file) {
 | |
|         struct stat stat;
 | |
|         if (fstat(grn_fileno(default_logger_file), &stat) != -1) {
 | |
|           default_logger_size = stat.st_size;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (default_logger_file) {
 | |
|       char label = *(slev + level);
 | |
|       int written;
 | |
|       if (location && *location) {
 | |
|         if (title && *title) {
 | |
|           written = fprintf(default_logger_file, "%s|%c|%s: %s %s\n",
 | |
|                             timestamp, label, location, title, message);
 | |
|         } else {
 | |
|           written = fprintf(default_logger_file, "%s|%c|%s: %s\n",
 | |
|                             timestamp, label, location, message);
 | |
|         }
 | |
|       } else {
 | |
|         written = fprintf(default_logger_file, "%s|%c|%s %s\n",
 | |
|                           timestamp, label, title, message);
 | |
|       }
 | |
|       if (written > 0) {
 | |
|         default_logger_size += written;
 | |
|         if (LOGGER_NEED_ROTATE(default_logger_size,
 | |
|                                default_logger_rotate_threshold_size)) {
 | |
|           fclose(default_logger_file);
 | |
|           default_logger_file = NULL;
 | |
|           rotate_log_file(ctx, default_logger_path);
 | |
|         } else {
 | |
|           fflush(default_logger_file);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     CRITICAL_SECTION_LEAVE(default_logger_lock);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| default_logger_reopen(grn_ctx *ctx, void *user_data)
 | |
| {
 | |
|   GRN_LOG(ctx, GRN_LOG_NOTICE, "log will be closed.");
 | |
|   CRITICAL_SECTION_ENTER(default_logger_lock);
 | |
|   if (default_logger_file) {
 | |
|     fclose(default_logger_file);
 | |
|     default_logger_file = NULL;
 | |
|   }
 | |
|   CRITICAL_SECTION_LEAVE(default_logger_lock);
 | |
|   GRN_LOG(ctx, GRN_LOG_NOTICE, "log opened.");
 | |
| }
 | |
| 
 | |
| static void
 | |
| default_logger_fin(grn_ctx *ctx, void *user_data)
 | |
| {
 | |
|   CRITICAL_SECTION_ENTER(default_logger_lock);
 | |
|   if (default_logger_file) {
 | |
|     fclose(default_logger_file);
 | |
|     default_logger_file = NULL;
 | |
|   }
 | |
|   CRITICAL_SECTION_LEAVE(default_logger_lock);
 | |
| }
 | |
| 
 | |
| static grn_logger default_logger = {
 | |
|   GRN_LOG_DEFAULT_LEVEL,
 | |
|   GRN_LOG_TIME|GRN_LOG_MESSAGE,
 | |
|   NULL,
 | |
|   default_logger_log,
 | |
|   default_logger_reopen,
 | |
|   default_logger_fin
 | |
| };
 | |
| 
 | |
| #define INITIAL_LOGGER {                        \
 | |
|   GRN_LOG_DEFAULT_LEVEL,                        \
 | |
|   GRN_LOG_TIME|GRN_LOG_MESSAGE,                 \
 | |
|   NULL,                                         \
 | |
|   NULL,                                         \
 | |
|   NULL,                                         \
 | |
|   NULL                                          \
 | |
| }
 | |
| 
 | |
| static grn_logger current_logger = INITIAL_LOGGER;
 | |
| 
 | |
| void
 | |
| grn_default_logger_set_max_level(grn_log_level max_level)
 | |
| {
 | |
|   default_logger.max_level = max_level;
 | |
|   if (current_logger.log == default_logger_log) {
 | |
|     current_logger.max_level = max_level;
 | |
|   }
 | |
| }
 | |
| 
 | |
| grn_log_level
 | |
| grn_default_logger_get_max_level(void)
 | |
| {
 | |
|   return default_logger.max_level;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_default_logger_set_flags(int flags)
 | |
| {
 | |
|   default_logger.flags = flags;
 | |
|   if (current_logger.log == default_logger_log) {
 | |
|     current_logger.flags = flags;
 | |
|   }
 | |
| }
 | |
| 
 | |
| int
 | |
| grn_default_logger_get_flags(void)
 | |
| {
 | |
|   return default_logger.flags;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_default_logger_set_path(const char *path)
 | |
| {
 | |
|   if (logger_inited) {
 | |
|     CRITICAL_SECTION_ENTER(default_logger_lock);
 | |
|   }
 | |
| 
 | |
|   if (default_logger_path) {
 | |
|     free(default_logger_path);
 | |
|   }
 | |
| 
 | |
|   if (path) {
 | |
|     default_logger_path = grn_strdup_raw(path);
 | |
|   } else {
 | |
|     default_logger_path = NULL;
 | |
|   }
 | |
| 
 | |
|   if (logger_inited) {
 | |
|     CRITICAL_SECTION_LEAVE(default_logger_lock);
 | |
|   }
 | |
| }
 | |
| 
 | |
| const char *
 | |
| grn_default_logger_get_path(void)
 | |
| {
 | |
|   return default_logger_path;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_default_logger_set_rotate_threshold_size(off_t threshold)
 | |
| {
 | |
|   default_logger_rotate_threshold_size = threshold;
 | |
| }
 | |
| 
 | |
| off_t
 | |
| grn_default_logger_get_rotate_threshold_size(void)
 | |
| {
 | |
|   return default_logger_rotate_threshold_size;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_logger_reopen(grn_ctx *ctx)
 | |
| {
 | |
|   if (current_logger.reopen) {
 | |
|     current_logger.reopen(ctx, current_logger.user_data);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| current_logger_fin(grn_ctx *ctx)
 | |
| {
 | |
|   if (current_logger.fin) {
 | |
|     current_logger.fin(ctx, current_logger.user_data);
 | |
|   }
 | |
|   {
 | |
|     grn_logger initial_logger = INITIAL_LOGGER;
 | |
|     current_logger = initial_logger;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| logger_info_func_wrapper(grn_ctx *ctx, grn_log_level level,
 | |
|                          const char *timestamp, const char *title,
 | |
|                          const char *message, const char *location,
 | |
|                          void *user_data)
 | |
| {
 | |
|   grn_logger_info *info = user_data;
 | |
|   info->func(level, timestamp, title, message, location, info->func_arg);
 | |
| }
 | |
| 
 | |
| /* Deprecated since 2.1.2. */
 | |
| grn_rc
 | |
| grn_logger_info_set(grn_ctx *ctx, const grn_logger_info *info)
 | |
| {
 | |
|   if (info) {
 | |
|     grn_logger logger;
 | |
| 
 | |
|     memset(&logger, 0, sizeof(grn_logger));
 | |
|     logger.max_level = info->max_level;
 | |
|     logger.flags = info->flags;
 | |
|     if (info->func) {
 | |
|       logger.log       = logger_info_func_wrapper;
 | |
|       logger.user_data = (grn_logger_info *)info;
 | |
|     } else {
 | |
|       logger.log    = default_logger_log;
 | |
|       logger.reopen = default_logger_reopen;
 | |
|       logger.fin    = default_logger_fin;
 | |
|     }
 | |
|     return grn_logger_set(ctx, &logger);
 | |
|   } else {
 | |
|     return grn_logger_set(ctx, NULL);
 | |
|   }
 | |
| }
 | |
| 
 | |
| grn_rc
 | |
| grn_logger_set(grn_ctx *ctx, const grn_logger *logger)
 | |
| {
 | |
|   current_logger_fin(ctx);
 | |
|   if (logger) {
 | |
|     current_logger = *logger;
 | |
|   } else {
 | |
|     current_logger = default_logger;
 | |
|   }
 | |
|   return GRN_SUCCESS;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_logger_set_max_level(grn_ctx *ctx, grn_log_level max_level)
 | |
| {
 | |
|   current_logger.max_level = max_level;
 | |
| }
 | |
| 
 | |
| grn_log_level
 | |
| grn_logger_get_max_level(grn_ctx *ctx)
 | |
| {
 | |
|   return current_logger.max_level;
 | |
| }
 | |
| 
 | |
| grn_bool
 | |
| grn_logger_pass(grn_ctx *ctx, grn_log_level level)
 | |
| {
 | |
|   return level <= current_logger.max_level;
 | |
| }
 | |
| 
 | |
| #define TBUFSIZE GRN_TIMEVAL_STR_SIZE
 | |
| #define MBUFSIZE 0x1000
 | |
| #define LBUFSIZE 0x400
 | |
| 
 | |
| void
 | |
| grn_logger_put(grn_ctx *ctx,
 | |
|                grn_log_level level,
 | |
|                const char *file,
 | |
|                int line,
 | |
|                const char *func,
 | |
|                const char *fmt,
 | |
|                ...)
 | |
| {
 | |
|   va_list ap;
 | |
|   va_start(ap, fmt);
 | |
|   grn_logger_putv(ctx, level, file, line, func, fmt, ap);
 | |
|   va_end(ap);
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_logger_putv(grn_ctx *ctx,
 | |
|                 grn_log_level level,
 | |
|                 const char *file,
 | |
|                 int line,
 | |
|                 const char *func,
 | |
|                 const char *fmt,
 | |
|                 va_list ap)
 | |
| {
 | |
|   if (level <= current_logger.max_level && current_logger.log) {
 | |
|     char tbuf[TBUFSIZE];
 | |
|     char mbuf[MBUFSIZE];
 | |
|     char lbuf[LBUFSIZE];
 | |
|     tbuf[0] = '\0';
 | |
|     if (current_logger.flags & GRN_LOG_TIME) {
 | |
|       grn_timeval tv;
 | |
|       grn_timeval_now(ctx, &tv);
 | |
|       grn_timeval2str(ctx, &tv, tbuf, TBUFSIZE);
 | |
|     }
 | |
|     if (current_logger.flags & GRN_LOG_MESSAGE) {
 | |
|       grn_vsnprintf(mbuf, MBUFSIZE, fmt, ap);
 | |
|     } else {
 | |
|       mbuf[0] = '\0';
 | |
|     }
 | |
|     if (current_logger.flags & GRN_LOG_LOCATION) {
 | |
|       grn_snprintf(lbuf, LBUFSIZE, LBUFSIZE,
 | |
|                    "%d %s:%d %s()", grn_getpid(), file, line, func);
 | |
|     } else if (current_logger.flags & GRN_LOG_PID) {
 | |
|       grn_snprintf(lbuf, LBUFSIZE, LBUFSIZE,
 | |
|                    "%d", grn_getpid());
 | |
|     } else {
 | |
|       lbuf[0] = '\0';
 | |
|     }
 | |
|     current_logger.log(ctx, level, tbuf, "", mbuf, lbuf,
 | |
|                        current_logger.user_data);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_logger_init(void)
 | |
| {
 | |
|   CRITICAL_SECTION_INIT(default_logger_lock);
 | |
|   if (!current_logger.log) {
 | |
|     current_logger = default_logger;
 | |
|   }
 | |
| 
 | |
|   logger_inited = GRN_TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_logger_fin(grn_ctx *ctx)
 | |
| {
 | |
|   current_logger_fin(ctx);
 | |
|   if (default_logger_path) {
 | |
|     free(default_logger_path);
 | |
|     default_logger_path = NULL;
 | |
|   }
 | |
|   CRITICAL_SECTION_FIN(default_logger_lock);
 | |
| 
 | |
|   logger_inited = GRN_FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| static grn_bool query_logger_inited = GRN_FALSE;
 | |
| static char *default_query_logger_path = NULL;
 | |
| static FILE *default_query_logger_file = NULL;
 | |
| static grn_critical_section default_query_logger_lock;
 | |
| static off_t default_query_logger_size = 0;
 | |
| static off_t default_query_logger_rotate_threshold_size = 0;
 | |
| 
 | |
| grn_bool
 | |
| grn_query_log_flags_parse(const char *string,
 | |
|                           int string_size,
 | |
|                           unsigned int *flags)
 | |
| {
 | |
|   const char *string_end;
 | |
| 
 | |
|   *flags = GRN_QUERY_LOG_NONE;
 | |
| 
 | |
|   if (!string) {
 | |
|     return GRN_TRUE;
 | |
|   }
 | |
| 
 | |
|   if (string_size < 0) {
 | |
|     string_size = strlen(string);
 | |
|   }
 | |
| 
 | |
|   string_end = string + string_size;
 | |
| 
 | |
|   while (string < string_end) {
 | |
|     if (*string == '|' || *string == ' ') {
 | |
|       string += 1;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
| #define CHECK_FLAG(name)                                        \
 | |
|     if (((size_t) (string_end - string) >= (sizeof(#name) - 1)) &&       \
 | |
|         (memcmp(string, #name, sizeof(#name) - 1) == 0) &&      \
 | |
|         (((size_t)(string_end - string) == (sizeof(#name) - 1)) ||      \
 | |
|          (string[sizeof(#name) - 1] == '|') ||                  \
 | |
|          (string[sizeof(#name) - 1] == ' '))) {                 \
 | |
|       *flags |= GRN_QUERY_LOG_ ## name;                         \
 | |
|       string += sizeof(#name) - 1;                              \
 | |
|       continue;                                                 \
 | |
|     }
 | |
| 
 | |
|     CHECK_FLAG(NONE);
 | |
|     CHECK_FLAG(COMMAND);
 | |
|     CHECK_FLAG(RESULT_CODE);
 | |
|     CHECK_FLAG(DESTINATION);
 | |
|     CHECK_FLAG(CACHE);
 | |
|     CHECK_FLAG(SIZE);
 | |
|     CHECK_FLAG(SCORE);
 | |
|     CHECK_FLAG(ALL);
 | |
|     CHECK_FLAG(DEFAULT);
 | |
| 
 | |
| #undef CHECK_FLAG
 | |
| 
 | |
|     return GRN_FALSE;
 | |
|   }
 | |
| 
 | |
|   return GRN_TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| default_query_logger_log(grn_ctx *ctx, unsigned int flag,
 | |
|                          const char *timestamp, const char *info,
 | |
|                          const char *message, void *user_data)
 | |
| {
 | |
|   if (default_query_logger_path) {
 | |
|     CRITICAL_SECTION_ENTER(default_query_logger_lock);
 | |
|     if (!default_query_logger_file) {
 | |
|       default_query_logger_file = grn_fopen(default_query_logger_path, "a");
 | |
|       default_query_logger_size = 0;
 | |
|       if (default_query_logger_file) {
 | |
|         struct stat stat;
 | |
|         if (fstat(grn_fileno(default_query_logger_file), &stat) != -1) {
 | |
|           default_query_logger_size = stat.st_size;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (default_query_logger_file) {
 | |
|       int written;
 | |
|       written = fprintf(default_query_logger_file, "%s|%s%s\n",
 | |
|                         timestamp, info, message);
 | |
|       if (written > 0) {
 | |
|         default_query_logger_size += written;
 | |
|         if (LOGGER_NEED_ROTATE(default_query_logger_size,
 | |
|                                default_query_logger_rotate_threshold_size)) {
 | |
|           fclose(default_query_logger_file);
 | |
|           default_query_logger_file = NULL;
 | |
|           rotate_log_file(ctx, default_query_logger_path);
 | |
|         } else {
 | |
|           fflush(default_query_logger_file);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     CRITICAL_SECTION_LEAVE(default_query_logger_lock);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| default_query_logger_close(grn_ctx *ctx, void *user_data)
 | |
| {
 | |
|   GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_DESTINATION, " ",
 | |
|                 "query log will be closed: <%s>", default_query_logger_path);
 | |
|   CRITICAL_SECTION_ENTER(default_query_logger_lock);
 | |
|   if (default_query_logger_file) {
 | |
|     fclose(default_query_logger_file);
 | |
|     default_query_logger_file = NULL;
 | |
|   }
 | |
|   CRITICAL_SECTION_LEAVE(default_query_logger_lock);
 | |
| }
 | |
| 
 | |
| static void
 | |
| default_query_logger_reopen(grn_ctx *ctx, void *user_data)
 | |
| {
 | |
|   default_query_logger_close(ctx, user_data);
 | |
|   if (default_query_logger_path) {
 | |
|     GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_DESTINATION, " ",
 | |
|                   "query log is opened: <%s>", default_query_logger_path);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| default_query_logger_fin(grn_ctx *ctx, void *user_data)
 | |
| {
 | |
|   if (default_query_logger_file) {
 | |
|     default_query_logger_close(ctx, user_data);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static grn_query_logger default_query_logger = {
 | |
|   GRN_QUERY_LOG_DEFAULT,
 | |
|   NULL,
 | |
|   default_query_logger_log,
 | |
|   default_query_logger_reopen,
 | |
|   default_query_logger_fin
 | |
| };
 | |
| 
 | |
| #define INITIAL_QUERY_LOGGER {                  \
 | |
|   GRN_QUERY_LOG_DEFAULT,                        \
 | |
|   NULL,                                         \
 | |
|   NULL,                                         \
 | |
|   NULL,                                         \
 | |
|   NULL                                          \
 | |
| }
 | |
| 
 | |
| static grn_query_logger current_query_logger = INITIAL_QUERY_LOGGER;
 | |
| 
 | |
| void
 | |
| grn_default_query_logger_set_flags(unsigned int flags)
 | |
| {
 | |
|   default_query_logger.flags = flags;
 | |
|   if (current_query_logger.log == default_query_logger_log) {
 | |
|     current_query_logger.flags = flags;
 | |
|   }
 | |
| }
 | |
| 
 | |
| unsigned int
 | |
| grn_default_query_logger_get_flags(void)
 | |
| {
 | |
|   return default_query_logger.flags;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_default_query_logger_set_path(const char *path)
 | |
| {
 | |
|   if (query_logger_inited) {
 | |
|     CRITICAL_SECTION_ENTER(default_query_logger_lock);
 | |
|   }
 | |
| 
 | |
|   if (default_query_logger_path) {
 | |
|     free(default_query_logger_path);
 | |
|   }
 | |
| 
 | |
|   if (path) {
 | |
|     default_query_logger_path = grn_strdup_raw(path);
 | |
|   } else {
 | |
|     default_query_logger_path = NULL;
 | |
|   }
 | |
| 
 | |
|   if (query_logger_inited) {
 | |
|     CRITICAL_SECTION_LEAVE(default_query_logger_lock);
 | |
|   }
 | |
| }
 | |
| 
 | |
| const char *
 | |
| grn_default_query_logger_get_path(void)
 | |
| {
 | |
|   return default_query_logger_path;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_default_query_logger_set_rotate_threshold_size(off_t threshold)
 | |
| {
 | |
|   default_query_logger_rotate_threshold_size = threshold;
 | |
| }
 | |
| 
 | |
| off_t
 | |
| grn_default_query_logger_get_rotate_threshold_size(void)
 | |
| {
 | |
|   return default_query_logger_rotate_threshold_size;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_query_logger_reopen(grn_ctx *ctx)
 | |
| {
 | |
|   if (current_query_logger.reopen) {
 | |
|     current_query_logger.reopen(ctx, current_query_logger.user_data);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| current_query_logger_fin(grn_ctx *ctx)
 | |
| {
 | |
|   if (current_query_logger.fin) {
 | |
|     current_query_logger.fin(ctx, current_query_logger.user_data);
 | |
|   }
 | |
|   {
 | |
|     grn_query_logger initial_query_logger = INITIAL_QUERY_LOGGER;
 | |
|     current_query_logger = initial_query_logger;
 | |
|   }
 | |
| }
 | |
| 
 | |
| grn_rc
 | |
| grn_query_logger_set(grn_ctx *ctx, const grn_query_logger *logger)
 | |
| {
 | |
|   current_query_logger_fin(ctx);
 | |
|   if (logger) {
 | |
|     current_query_logger = *logger;
 | |
|   } else {
 | |
|     current_query_logger = default_query_logger;
 | |
|   }
 | |
|   return GRN_SUCCESS;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_query_logger_set_flags(grn_ctx *ctx, unsigned int flags)
 | |
| {
 | |
|   current_query_logger.flags = flags;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_query_logger_add_flags(grn_ctx *ctx, unsigned int flags)
 | |
| {
 | |
|   current_query_logger.flags |= flags;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_query_logger_remove_flags(grn_ctx *ctx, unsigned int flags)
 | |
| {
 | |
|   current_query_logger.flags &= ~flags;
 | |
| }
 | |
| 
 | |
| unsigned int
 | |
| grn_query_logger_get_flags(grn_ctx *ctx)
 | |
| {
 | |
|   return current_query_logger.flags;
 | |
| }
 | |
| 
 | |
| grn_bool
 | |
| grn_query_logger_pass(grn_ctx *ctx, unsigned int flag)
 | |
| {
 | |
|   return current_query_logger.flags & flag;
 | |
| }
 | |
| 
 | |
| #define TIMESTAMP_BUFFER_SIZE    TBUFSIZE
 | |
| /* 8+a(%p) + 1(|) + 1(mark) + 15(elapsed time) = 25+a */
 | |
| #define INFO_BUFFER_SIZE         40
 | |
| 
 | |
| void
 | |
| grn_query_logger_put(grn_ctx *ctx, unsigned int flag, const char *mark,
 | |
|                      const char *format, ...)
 | |
| {
 | |
|   char timestamp[TIMESTAMP_BUFFER_SIZE];
 | |
|   char info[INFO_BUFFER_SIZE];
 | |
|   grn_obj *message = &ctx->impl->query_log_buf;
 | |
| 
 | |
|   if (!current_query_logger.log) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     grn_timeval tv;
 | |
|     timestamp[0] = '\0';
 | |
|     grn_timeval_now(ctx, &tv);
 | |
|     grn_timeval2str(ctx, &tv, timestamp, TIMESTAMP_BUFFER_SIZE);
 | |
|   }
 | |
| 
 | |
|   if (flag & (GRN_QUERY_LOG_COMMAND | GRN_QUERY_LOG_DESTINATION)) {
 | |
|     grn_snprintf(info, INFO_BUFFER_SIZE, INFO_BUFFER_SIZE,
 | |
|                  "%p|%s", ctx, mark);
 | |
|     info[INFO_BUFFER_SIZE - 1] = '\0';
 | |
|   } else {
 | |
|     grn_timeval tv;
 | |
|     uint64_t elapsed_time;
 | |
|     grn_timeval_now(ctx, &tv);
 | |
|     elapsed_time =
 | |
|       (uint64_t)(tv.tv_sec - ctx->impl->tv.tv_sec) * GRN_TIME_NSEC_PER_SEC +
 | |
|       (tv.tv_nsec - ctx->impl->tv.tv_nsec);
 | |
| 
 | |
|     grn_snprintf(info, INFO_BUFFER_SIZE, INFO_BUFFER_SIZE,
 | |
|                  "%p|%s%015" GRN_FMT_INT64U " ", ctx, mark, elapsed_time);
 | |
|     info[INFO_BUFFER_SIZE - 1] = '\0';
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     va_list args;
 | |
| 
 | |
|     va_start(args, format);
 | |
|     GRN_BULK_REWIND(message);
 | |
|     grn_text_vprintf(ctx, message, format, args);
 | |
|     va_end(args);
 | |
|     GRN_TEXT_PUTC(ctx, message, '\0');
 | |
|   }
 | |
| 
 | |
|   current_query_logger.log(ctx, flag, timestamp, info, GRN_TEXT_VALUE(message),
 | |
|                            current_query_logger.user_data);
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_query_logger_init(void)
 | |
| {
 | |
|   current_query_logger = default_query_logger;
 | |
|   CRITICAL_SECTION_INIT(default_query_logger_lock);
 | |
| 
 | |
|   query_logger_inited = GRN_TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_query_logger_fin(grn_ctx *ctx)
 | |
| {
 | |
|   current_query_logger_fin(ctx);
 | |
|   if (default_query_logger_path) {
 | |
|     free(default_query_logger_path);
 | |
|     default_query_logger_path = NULL;
 | |
|   }
 | |
|   CRITICAL_SECTION_FIN(default_query_logger_lock);
 | |
| 
 | |
|   query_logger_inited = GRN_FALSE;
 | |
| }
 | |
| 
 | |
| void
 | |
| grn_log_reopen(grn_ctx *ctx)
 | |
| {
 | |
|   grn_logger_reopen(ctx);
 | |
|   grn_query_logger_reopen(ctx);
 | |
| }
 | 
