/* -*- 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 0 x1000
#define LBUFSIZE 0 x400
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);
}
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland