log.cc (fstransform-0.9.3-src) | : | log.cc (fstransform-0.9.4) | ||
---|---|---|---|---|
/* | /* | |||
* logging utilities for fsattr, fsmove, fsremap | ||||
* | ||||
* Copyright (C) 2011-2012 Massimiliano Ghilardi | ||||
* | ||||
* This program is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | ||||
* | ||||
* This program 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 General Public License for more details. | ||||
* | ||||
* You should have received a copy of the GNU General Public License | ||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
* | ||||
* log.cc | * log.cc | |||
* | * | |||
* Created on: Mar 8, 2011 | * Created on: Mar 8, 2011 | |||
* Author: max | * Author: max | |||
*/ | */ | |||
#include "first.hh" | #include "first.hh" | |||
#if defined(FT_HAVE_STRING_H) | #if defined(FT_HAVE_STRING_H) | |||
# include <string.h> // for strerror(), strncmp() | # include <string.h> // for strerror(), strncmp() | |||
#elif defined(FT_HAVE_CSTRING) | #elif defined(FT_HAVE_CSTRING) | |||
# include <cstring> // for strerror(), strncmp() | # include <cstring> // for strerror(), strncmp() | |||
#endif | #endif | |||
#if defined(FT_HAVE_TIME_H) | #if defined(FT_HAVE_TIME_H) | |||
# include <time.h> // for time(), localtime_r(), localtime(), strftime() | # include <time.h> // for time(), localtime_r(), localtime(), strftime() | |||
#elif defined(FT_HAVE_CTIME) | #elif defined(FT_HAVE_CTIME) | |||
# include <ctime> // for time(), localtime_r(), localtime(), strftime() | # include <ctime> // for time(), localtime_r(), localtime(), strftime() | |||
#endif | #endif | |||
#if defined(FT_HAVE_UNISTD_H) | ||||
# include <unistd.h> /* for isatty() */ | ||||
#endif | ||||
#include <utility> // for std::make_pair() | #include <utility> // for std::make_pair() | |||
#include "types.hh" // for ft_size | #include "types.hh" // for ft_size | |||
#include "log.hh" // for ff_log(), ff_vlog() ... | #include "log.hh" // for ff_log(), ff_vlog() ... | |||
#if defined(FT_HAVE_VA_COPY) || defined(va_copy) | #if defined(FT_HAVE_VA_COPY) || defined(va_copy) | |||
# define ff_va_copy va_copy | # define ff_va_copy va_copy | |||
#elif defined(__va_copy) | #elif defined(FT_HAVE___VA_COPY) || defined(__va_copy) | |||
# define ff_va_copy __va_copy | # define ff_va_copy __va_copy | |||
#else | #else | |||
# error both va_copy() and __va_copy() are missing, cannot compile log.cc | # error both va_copy() and __va_copy() are missing, cannot compile log.cc | |||
#endif | #endif | |||
FT_NAMESPACE_BEGIN | FT_NAMESPACE_BEGIN | |||
static char const* const this_log_label[FC_FATAL+1] = | static char const* const this_log_label[FC_FATAL+1] = | |||
{ | { | |||
"", "DUMP ", "TRACE ", "DEBUG ", "INFO ", "NOTICE", "WARN ", "ERROR ", " FATAL ", | "", "DUMP ", "TRACE ", "DEBUG ", "INFO ", "NOTICE", "WARN ", "ERROR ", " FATAL ", | |||
}; | }; | |||
static char const* const this_log_label_always[FC_FATAL+1] = | static char const* const this_log_label_always[FC_FATAL+1] = | |||
{ | { | |||
"", "", "", "", "", "", "WARN: ", "ERROR: ", "FATAL: ", | "", "", "", "", "", "", "WARN: ", "ERROR: ", "FATAL: ", | |||
}; | }; | |||
static std::list<ft_log_appender *> * fc_log_all_appenders = NULL; | static char const* const this_log_color_ansi[FC_FATAL+1] = | |||
static std::map<ft_string, ft_log *> * fc_log_all_loggers = NULL; | { | |||
"", "\033[1;30m", "\033[1;30m", "\033[1;30m", "", "\033[1m", "\033[1;33m", | ||||
"\033[1;31m", "\033[1;35m", | ||||
}; | ||||
static char const* const this_log_color_ansi_off_nl = "\033[0m\n"; | ||||
const char * ff_log_level_to_string(ft_log_level level) | ||||
{ | ||||
if (level >= FC_LEVEL_NOT_SET && level <= FC_FATAL) | ||||
return this_log_label[level]; | ||||
if (level == FC_LEVEL_NOT_SET) | ||||
return "NOT_SET"; | ||||
return "UNKNOWN"; | ||||
} | ||||
static ft_log_appenders * fc_log_all_appenders = NULL; | ||||
static all_loggers_type * fc_log_all_loggers = NULL; | ||||
static ft_log * fc_log_root_logger = NULL; | static ft_log * fc_log_root_logger = NULL; | |||
static bool fc_log_initialized = false; | static bool fc_log_initialized = false; | |||
/** list of all appenders */ | /** list of all appenders */ | |||
std::list<ft_log_appender *> & ft_log_appender::get_all_appenders() | ft_log_appenders & ft_log_appender::get_all_appenders() | |||
{ | { | |||
if (!fc_log_initialized) | if (!fc_log_initialized) | |||
ft_log::initialize(); | ft_log::initialize(); | |||
return * fc_log_all_appenders; | return * fc_log_all_appenders; | |||
} | } | |||
/** constructor. */ | /** constructor. */ | |||
ft_log_appender::ft_log_appender(FILE * my_stream, ft_log_fmt my_format, ft_log_ | ft_log_appender::ft_log_appender(FILE * my_stream, ft_log_fmt my_format, | |||
level my_min_level, ft_log_level my_max_level) | ft_log_level my_min_level, ft_log_level my_max_level, ft_log_color my_co | |||
: stream(my_stream), format(my_format), min_level(my_min_level), max_level(m | lor) | |||
y_max_level) | : | |||
stream(my_stream), format(my_format), | ||||
min_level(my_min_level), max_level(my_max_level), color(my_color) | ||||
{ | { | |||
get_all_appenders().push_back(this); | get_all_appenders().insert(this); | |||
} | } | |||
/** destructor. */ | /** destructor. */ | |||
ft_log_appender::~ft_log_appender() | ft_log_appender::~ft_log_appender() | |||
{ | { | |||
get_all_appenders().remove(this); | flush(); | |||
get_all_appenders().erase(this); | ||||
} | } | |||
/** | /** | |||
* write a log message to stream. | * write a log message to stream. | |||
* | * | |||
* print fmt and subsequent printf-style args to log stream. | * print fmt and subsequent printf-style args to log stream. | |||
* if err != 0, append ": ", strerror(errno) and "\n" | * if err != 0, append ": ", strerror(errno) and "\n" | |||
* else append "\n" | * else append "\n" | |||
*/ | */ | |||
void ft_log_appender::append(ft_log_event & event) | void ft_log_appender::append(ft_log_event & event) | |||
{ | { | |||
const ft_log_level level = event.level; | const ft_log_level level = event.level; | |||
if (level < min_level || level > max_level) | if (level < min_level || level > max_level) | |||
return; | return; | |||
const char * color_on = "", * color_off_nl = "\n"; | ||||
#if defined(FT_HAVE_ISATTY) && defined(FT_HAVE_FILENO) | ||||
if (color == FC_COL_AUTO) | ||||
color = (isatty(fileno(stream)) == 1) ? FC_COL_ANSI : FC_COL_NONE; | ||||
#endif | ||||
if (color == FC_COL_ANSI) | ||||
{ | ||||
color_on = this_log_color_ansi[level]; | ||||
color_off_nl = this_log_color_ansi_off_nl; | ||||
} | ||||
switch (format) { | switch (format) { | |||
case FC_FMT_DATETIME_LEVEL_CALLER_MSG: | case FC_FMT_DATETIME_LEVEL_CALLER_MSG: | |||
fprintf(stream, "%s %s [%.*s%s.%s(%d)] ", event.str_now, this_log_la bel[level], | fprintf(stream, "%s%s %s [%.*s%s.%s(%d)]\t", color_on, event.str_now , this_log_label[level], | |||
event.file_len, event.file, event.file_suffix, event.functio n, event.line); | event.file_len, event.file, event.file_suffix, event.functio n, event.line); | |||
break; | break; | |||
case FC_FMT_DATETIME_LEVEL_MSG: | case FC_FMT_DATETIME_LEVEL_MSG: | |||
fprintf(stream, "%s %s ", event.str_now, this_log_label[level]); | fprintf(stream, "%s%s %s ", color_on, event.str_now, this_log_label[ level]); | |||
break; | break; | |||
case FC_FMT_LEVEL_MSG: | case FC_FMT_LEVEL_MSG: | |||
fprintf(stream, "%s ", this_log_label[level]); | fprintf(stream, "%s%s ", color_on, this_log_label[level]); | |||
break; | break; | |||
case FC_FMT_MSG: | case FC_FMT_MSG: | |||
default: | default: | |||
/* always mark warnings, errors and fatal errors as such */ | /* always mark warnings, errors and fatal errors as such */ | |||
fprintf(stream, "%s", this_log_label_always[level]); | fprintf(stream, "%s%s", color_on, this_log_label_always[level]); | |||
break; | break; | |||
} | } | |||
va_list vargs; | va_list vargs; | |||
ff_va_copy(vargs, event.vargs); | ff_va_copy(vargs, event.vargs); | |||
vfprintf(stream, event.fmt, vargs); | vfprintf(stream, event.fmt, vargs); | |||
va_end(vargs); | va_end(vargs); | |||
if (event.err != 0) { | if (event.err != 0) { | |||
bool is_reported = ff_log_is_reported(event.err); | bool is_reported = ff_log_is_reported(event.err); | |||
fprintf(stream, is_reported ? " (caused by previous error: %s)\n" : ": % | fprintf(stream, is_reported ? " (caused by previous error: %s)%s" : ": % | |||
s\n", strerror(is_reported ? -event.err : event.err)); | s%s", | |||
strerror(is_reported ? -event.err : event.err), color_off_nl); | ||||
} else | } else | |||
fputc('\n', stream); | fputs(color_off_nl, stream); | |||
} | } | |||
/** flush this appender */ | /** flush this appender */ | |||
void ft_log_appender::flush() | void ft_log_appender::flush() | |||
{ | { | |||
fflush(stream); | fflush(stream); | |||
} | } | |||
/** flush all buffered streams used to log messages for specified level */ | /** flush all buffered streams used to log messages for specified level */ | |||
void ft_log_appender::flush_all(ft_log_level level) | void ft_log_appender::flush_all(ft_log_level level) | |||
{ | { | |||
std::list<ft_log_appender *> & all_appenders = get_all_appenders(); | ft_log_appenders & all_appenders = get_all_appenders(); | |||
std::list<ft_log_appender *>::const_iterator iter = all_appenders.begin(), e | ft_log_appenders_citerator iter = all_appenders.begin(), end = all_appenders | |||
nd = all_appenders.end(); | .end(); | |||
/* iterate on streams configured for 'level' */ | /* iterate on streams configured for 'level' */ | |||
for (; iter != end; ++iter) { | for (; iter != end; ++iter) { | |||
ft_log_appender * appender = *iter; | ft_log_appender * appender = *iter; | |||
if (appender->min_level <= level && appender->max_level >= level) | if (appender->min_level <= level && appender->max_level >= level) | |||
appender->flush(); | appender->flush(); | |||
} | } | |||
} | } | |||
/** set format and min/max levels of this appender */ | /** set format, min level and color of this appender */ | |||
void ft_log_appender::redefine(ft_log_fmt format, ft_log_level min_level, ft_log | void ft_log_appender::reconfigure(ft_log_fmt format_except_fatal, ft_log_level s | |||
_level max_level) | tdout_min_level, ft_log_color color) | |||
{ | { | |||
this->format = format; | if (this->max_level != FC_FATAL) | |||
this->min_level = min_level; | this->format = format_except_fatal; | |||
this->max_level = max_level; | if (stdout_min_level != FC_LEVEL_NOT_SET && this->stream == stdout) | |||
this->min_level = stdout_min_level; | ||||
this->color = color; | ||||
} | } | |||
/** set format and min/max levels of all appenders attached to stream */ | /** set format, min level and color of all appenders */ | |||
void ft_log_appender::redefine(FILE * stream, ft_log_fmt format, ft_log_level mi | void ft_log_appender::reconfigure_all(ft_log_fmt format_except_fatal, ft_log_lev | |||
n_level, ft_log_level max_level) | el stdout_min_level, ft_log_color color) | |||
{ | { | |||
if (!fc_log_initialized) | ft_log_appenders & all_appenders = get_all_appenders(); | |||
ft_log::initialize(); | ft_log_appenders_citerator iter = all_appenders.begin(), end = all_appenders | |||
.end(); | ||||
std::list<ft_log_appender *> & all_appenders = get_all_appenders(); | ||||
std::list<ft_log_appender *>::const_iterator iter = all_appenders.begin(), e | ||||
nd = all_appenders.end(); | ||||
for (; iter != end; ++iter) { | for (; iter != end; ++iter) | |||
ft_log_appender * appender = *iter; | (*iter)->reconfigure(format_except_fatal, stdout_min_level, color); | |||
if (appender->stream == stream) | ||||
appender->redefine(format, min_level, max_level); | ||||
} | ||||
} | } | |||
/** return map of all existing loggers. */ | /** return map of all existing loggers. */ | |||
std::map<ft_string, ft_log *> & ft_log::get_all_loggers() | all_loggers_type & ft_log::get_all_loggers() | |||
{ | { | |||
if (!fc_log_initialized) | if (!fc_log_initialized) | |||
ft_log::initialize(); | ft_log::initialize(); | |||
return * fc_log_all_loggers; | return * fc_log_all_loggers; | |||
} | } | |||
/** return root logger. by default, all messages less serious than 'FC_INFO' are suppressed on all streams */ | /** return root logger. by default, all messages less serious than 'FC_INFO' are suppressed on all streams */ | |||
ft_log & ft_log::get_root_logger() | ft_log & ft_log::get_root_logger() | |||
{ | { | |||
if (!fc_log_initialized) | if (!fc_log_initialized) | |||
ft_log::initialize(); | ft_log::initialize(); | |||
return * fc_log_root_logger; | return * fc_log_root_logger; | |||
} | } | |||
/** | /** | |||
* initialize log subsystem. automatic configuration is: | * initialize log subsystem. automatic configuration is: | |||
* | * | |||
* print to stderr all INFO and NOTICE messages, with format FC_FMT_MSG | * print to stderr all INFO and NOTICE messages, with format FC_FMT_MSG | |||
* print to stdout all WARN, ERROR and FATAL messages, with format FC_FMT_MSG | * print to stdout all WARN, ERROR and FATAL messages, with format FC_FMT_MSG | |||
*/ | */ | |||
void ft_log::initialize() | void ft_log::initialize() | |||
{ | { | |||
if (fc_log_initialized) | if (fc_log_initialized) | |||
return; | return; | |||
fc_log_initialized = true; | fc_log_initialized = true; | |||
if (fc_log_all_appenders == NULL) | ||||
fc_log_all_appenders = new std::list<ft_log_appender *>(); | ||||
if (fc_log_all_loggers == NULL) | ||||
fc_log_all_loggers = new std::map<ft_string, ft_log *>(); | ||||
if (fc_log_root_logger == NULL) | ||||
fc_log_root_logger = new ft_log("", NULL, FC_INFO); | ||||
ft_log & root_logger = ft_log::get_root_logger(); | ||||
#ifdef FT_HAVE_TZSET | #ifdef FT_HAVE_TZSET | |||
tzset(); | tzset(); | |||
#endif | #endif | |||
(void) setvbuf(stdout, NULL, _IOLBF, 0); | (void) setvbuf(stdout, NULL, _IOLBF, 0); | |||
(void) setvbuf(stderr, NULL, _IOLBF, 0); | (void) setvbuf(stderr, NULL, _IOLBF, 0); | |||
root_logger.add_appender(* new ft_log_appender(stdout, FC_FMT_MSG, FC_INFO, | if (fc_log_all_appenders == NULL) | |||
FC_NOTICE)); | fc_log_all_appenders = new ft_log_appenders(); | |||
root_logger.add_appender(* new ft_log_appender(stderr, FC_FMT_MSG, FC_WARN)) | if (fc_log_all_loggers == NULL) | |||
; | fc_log_all_loggers = new all_loggers_type(); | |||
if (fc_log_root_logger == NULL) | ||||
fc_log_root_logger = new ft_log("", NULL, FC_INFO); | ||||
ft_log & root_logger = get_root_logger(); | ||||
root_logger.add_appender(* new ft_log_appender(stdout, FC_FMT_MSG, FC_DUMP, | ||||
FC_NOTICE)); | ||||
root_logger.add_appender(* new ft_log_appender(stderr, FC_FMT_MSG, FC_WARN, | ||||
FC_ERROR)); | ||||
root_logger.add_appender(* new ft_log_appender(stderr, FC_FMT_DATETIME_LEVEL | ||||
_CALLER_MSG, FC_FATAL)); | ||||
} | } | |||
/** constructor. */ | /** constructor. */ | |||
ft_log::ft_log(const ft_string & my_name, ft_log * my_parent, ft_log_level my_le | ft_log::ft_log(const ft_mstring & my_name, ft_log * my_parent, ft_log_level my_l | |||
vel) | evel) | |||
: parent(my_parent), appenders(), level(my_level) | : parent(my_parent), appenders(), level(my_level), | |||
effective_level(FC_LEVEL_NOT_SET), threshold_level(FC_LEVEL_NOT_SET) | ||||
{ | { | |||
std::pair<all_loggers_iterator, bool> iter_pair = get_all_loggers().insert(s td::make_pair(my_name, this)); | std::pair<all_loggers_iterator, bool> iter_pair = get_all_loggers().insert(s td::make_pair(my_name, this)); | |||
name = & iter_pair.first->first; | name = & iter_pair.first->first; | |||
} | } | |||
/** destructor. */ | /** destructor. */ | |||
ft_log::~ft_log() | ft_log::~ft_log() | |||
{ | { | |||
get_all_loggers().erase(* name); | get_all_loggers().erase(* name); | |||
if (parent == NULL) | if (parent == NULL) | |||
ft_log_appender::flush_all(FC_DUMP); | ft_log_appender::flush_all(FC_DUMP); | |||
} | } | |||
/** find or create parent logger given child name. */ | /** find or create parent logger given child name. */ | |||
ft_log & ft_log::get_parent(const ft_string & child_logger_name) | ft_log & ft_log::get_parent(const ft_mstring & child_logger_name) | |||
{ | { | |||
ft_size slash = child_logger_name.rfind('/'); | ft_size slash = child_logger_name.rfind('/'); | |||
if (slash == ft_string::npos) | if (slash == ft_mstring::npos) | |||
return get_root_logger(); | return get_root_logger(); | |||
ft_string parent_name(child_logger_name, 0, slash); | ft_mstring parent_name(child_logger_name, 0, slash); | |||
return get_logger(parent_name); | return get_logger(parent_name); | |||
} | } | |||
/** find or create a logger by name */ | /** find or create a logger by name */ | |||
ft_log & ft_log::get_logger(const ft_string & logger_name) | ft_log & ft_log::get_logger(const ft_mstring & logger_name) | |||
{ | { | |||
std::map<ft_string, ft_log *> & all_loggers = get_all_loggers(); | all_loggers_type & all_loggers = get_all_loggers(); | |||
all_loggers_iterator iter = all_loggers.find(logger_name); | all_loggers_iterator iter = all_loggers.find(logger_name); | |||
if (iter != all_loggers.end()) | if (iter != all_loggers.end()) | |||
return * iter->second; | return * iter->second; | |||
ft_log & parent = get_parent(logger_name); | ft_log & parent = get_parent(logger_name); | |||
return * new ft_log(logger_name, & parent); | return * new ft_log(logger_name, & parent); | |||
} | } | |||
/** log a message (skip level check) */ | /** log a message (skip threshold_level check) */ | |||
void ft_log::append(ft_log_event & event) | void ft_log::append(ft_log_event & event) | |||
{ | { | |||
ft_log * logger = this; | ft_log * logger = this; | |||
do { | do { | |||
std::list<ft_log_appender *>::const_iterator iter = logger->appenders.be | if (event.level >= logger->get_effective_level()) | |||
gin(), end = logger->appenders.end(); | { | |||
for (; iter != end; ++iter) | ft_log_appenders_citerator iter = logger->appenders.begin(), end = l | |||
(* iter)->append(event); | ogger->appenders.end(); | |||
for (; iter != end; ++iter) | ||||
(* iter)->append(event); | ||||
} | ||||
logger = logger->parent; | logger = logger->parent; | |||
} while (logger != NULL); | } while (logger != NULL); | |||
} | } | |||
/** log a message (unless it's suppressed) */ | /** log a message (unless it's suppressed) */ | |||
void ft_log::log(ft_log_event & event) | void ft_log::log(ft_log_event & event) | |||
{ | { | |||
ft_log_level level = get_effective_level(); | if (event.level >= get_threshold_level()) | |||
if (event.level >= level) | ||||
append(event); | append(event); | |||
} | } | |||
/** return the effective level: if level is set return it, otherwise return pare nt effective level. */ | /** return the effective level: if level is set return it, otherwise return pare nt effective level. */ | |||
ft_log_level ft_log::get_effective_level() const | ft_log_level ft_log::get_effective_level() const | |||
{ | { | |||
const ft_log * logger = this; | if (effective_level == FC_LEVEL_NOT_SET) | |||
ft_log_level level; | { | |||
do { | if (level == FC_LEVEL_NOT_SET) | |||
level = logger->level; | effective_level = (parent != NULL) ? parent->get_effective_level() : | |||
logger = logger->parent; | FC_INFO; | |||
} while (level == FC_LEVEL_NOT_SET && logger != NULL); | else | |||
effective_level = level; | ||||
} | ||||
return effective_level; | ||||
} | ||||
/** return the threshold level: the minimum of this and all ancestor's levels. * | ||||
/ | ||||
ft_log_level ft_log::get_threshold_level() const | ||||
{ | ||||
if (threshold_level == FC_LEVEL_NOT_SET) | ||||
{ | ||||
ft_log_level effective_level = get_effective_level(); | ||||
ft_log_level parent_threshold_level = (parent != NULL) ? parent->get_thr | ||||
eshold_level() : effective_level; | ||||
threshold_level = effective_level < parent_threshold_level ? effective_l | ||||
evel : parent_threshold_level; | ||||
} | ||||
return threshold_level; | ||||
} | ||||
return level; | void ft_log::invalidate_all_cached_levels() | |||
{ | ||||
all_loggers_type & all_loggers = get_all_loggers(); | ||||
all_loggers_iterator iter = all_loggers.begin(), end = all_loggers.end(); | ||||
for (; iter != end; ++iter) | ||||
{ | ||||
ft_log * logger = iter->second; | ||||
logger->effective_level = logger->threshold_level = FC_LEVEL_NOT_SET; | ||||
} | ||||
} | } | |||
/** add an appender */ | /** add an appender */ | |||
void ft_log::add_appender(ft_log_appender & appender) | void ft_log::add_appender(ft_log_appender & appender) | |||
{ | { | |||
appenders.push_back(& appender); | appenders.insert(& appender); | |||
} | } | |||
/** remove an appender */ | /** remove an appender */ | |||
void ft_log::remove_appender(ft_log_appender & appender) | void ft_log::remove_appender(ft_log_appender & appender) | |||
{ | { | |||
// remove last occurrence of appender | appender.flush(); | |||
std::list<ft_log_appender *>::iterator begin = appenders.begin(), iter = app | appenders.erase(& appender); | |||
enders.end(); | ||||
while (iter != begin) { | ||||
if (*--iter == & appender) { | ||||
appender.flush(); | ||||
appenders.erase(iter); | ||||
return; | ||||
} | ||||
} | ||||
} | } | |||
static const char * ff_strftime(); | static const char * ff_strftime(); | |||
static void ff_pretty_file(ft_log_event & event); | static void ff_pretty_file(ft_log_event & event); | |||
bool ff_logl_is_enabled(const char * caller_file, ft_log_level level) | bool ff_logl_is_enabled(const char * file, int file_len, ft_log_level level) | |||
{ | { | |||
ft_log_event event = { | ft_log_event event = { | |||
"", caller_file, "", "", "", | "", file, "", "", "", | |||
0, 0, 0, | file_len, 0, 0, | |||
level, | level, | |||
/* va_list vargs */ | /* va_list vargs field follows - but no portable way to value-initialize it */ | |||
}; | }; | |||
ff_pretty_file(event); | ff_pretty_file(event); | |||
ft_string logger_name(event.file, event.file_len); | ft_mstring logger_name(event.file, event.file_len); | |||
ft_log & logger = ft_log::get_logger(logger_name); | ft_log & logger = ft_log::get_logger(logger_name); | |||
return logger.is_enabled(level); | return logger.is_enabled(level); | |||
} | } | |||
/** | /** | |||
* print fmt and subsequent printf-style args to log stream(s). | * print fmt and subsequent printf-style args to log stream(s). | |||
* if err != 0, append ": ", strerror(errno) and "\n" | * if err != 0, append ": ", strerror(errno) and "\n" | |||
* else append "\n" | * else append "\n" | |||
* finally return err | * finally return err | |||
*/ | */ | |||
int ff_logl(const char * file, const char * func, int line, ft_log_level level, int err, const char * fmt, ...) | int ff_logl(const char * file, int file_len, const char * func, int line, ft_log _level level, int err, const char * fmt, ...) | |||
{ | { | |||
/* | /* | |||
* note 1.1) | * note 1.1) | |||
* log subsystem is automatically initialized upon first call to | * log subsystem is automatically initialized upon first call to | |||
* ff_log(), ff_vlog(), ff_log_register() or ff_log_set_threshold(). | * ff_log(), ff_vlog(), ff_log_register() or ff_log_set_threshold(). | |||
*/ | */ | |||
ft_log_event event = { | ft_log_event event = { | |||
ff_strftime(), file, "", func, fmt, | ff_strftime(), file, "", func, fmt, | |||
0, line, err, | file_len, line, err, | |||
level, | level, | |||
/* va_list vargs */ | /* va_list vargs field follows - but no portable way to value-initialize it */ | |||
}; | }; | |||
ff_pretty_file(event); | ff_pretty_file(event); | |||
ft_string logger_name(event.file, event.file_len); | ft_mstring logger_name(event.file, event.file_len); | |||
ft_log & logger = ft_log::get_logger(logger_name); | ft_log & logger = ft_log::get_logger(logger_name); | |||
va_start(event.vargs, fmt); | va_start(event.vargs, fmt); | |||
logger.log(event); | logger.log(event); | |||
va_end(event.vargs); | va_end(event.vargs); | |||
/* note 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EIN VAL, -ENOMEM...) */ | /* note 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EIN VAL, -ENOMEM...) */ | |||
return ff_log_is_reported(err) ? err : -err; | return ff_log_is_reported(err) ? err : -err; | |||
} | } | |||
/** | /** | |||
* print to log fmt and subsequent printf-style args log stream(s). | * print to log fmt and subsequent printf-style args log stream(s). | |||
* if err != 0, append ": ", strerror(errno) and "\n" | * if err != 0, append ": ", strerror(errno) and "\n" | |||
* else append "\n" | * else append "\n" | |||
* finally return err as reported (flip sign if it was unreported) | * finally return err as reported (flip sign if it was unreported) | |||
*/ | */ | |||
int ff_logv(const char * file, const char * func, int line, ft_log_level level, int err, const char * fmt, va_list vargs) | int ff_logv(const char * file, int file_len, const char * func, int line, ft_log _level level, int err, const char * fmt, va_list vargs) | |||
{ | { | |||
/* | /* | |||
* note 1.1) | * note 1.1) | |||
* log subsystem is automatically initialized upon first call to | * log subsystem is automatically initialized upon first call to | |||
* ff_log(), ff_vlog(), ff_log_register() or ff_log_set_threshold(). | * ff_log(), ff_vlog(), ff_log_register() or ff_log_set_threshold(). | |||
*/ | */ | |||
ft_log_event event = { | ft_log_event event = { | |||
ff_strftime(), file, "", func, fmt, | ff_strftime(), file, "", func, fmt, | |||
0, line, err, | file_len, line, err, | |||
level, | level, | |||
/* va_list vargs */ | /* va_list vargs field follows - but no portable way to value-initialize it */ | |||
}; | }; | |||
ff_pretty_file(event); | ff_pretty_file(event); | |||
ft_string logger_name(event.file, event.file_len); | ft_mstring logger_name(event.file, event.file_len); | |||
ft_log & logger = ft_log::get_logger(logger_name); | ft_log & logger = ft_log::get_logger(logger_name); | |||
ff_va_copy(event.vargs, vargs); | ff_va_copy(event.vargs, vargs); | |||
logger.log(event); | logger.log(event); | |||
va_end(event.vargs); | va_end(event.vargs); | |||
/* note 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EIN VAL, -ENOMEM...) */ | /* note 1.2.1) ff_log() and ff_vlog() always return errors as reported (-EIN VAL, -ENOMEM...) */ | |||
return ff_log_is_reported(err) ? err : -err; | return ff_log_is_reported(err) ? err : -err; | |||
} | } | |||
skipping to change at line 421 | skipping to change at line 491 | |||
/** | /** | |||
* compute pretty-print version of args.file (i.e. __FILE__): | * compute pretty-print version of args.file (i.e. __FILE__): | |||
* skip any '../' or 'src/' prefix, | * skip any '../' or 'src/' prefix, | |||
* skip filename extension (for example .cc or .hh) | * skip filename extension (for example .cc or .hh) | |||
* and replace final '.t' with '<T>' | * and replace final '.t' with '<T>' | |||
*/ | */ | |||
static void ff_pretty_file(ft_log_event & event) | static void ff_pretty_file(ft_log_event & event) | |||
{ | { | |||
const char * file = event.file; | const char * file = event.file; | |||
if (!strncmp(file, "../", 3)) | int file_len = event.file_len; | |||
file += 3; | ||||
if (!strncmp(file, "src/", 3)) | while (file_len >= 3 && !memcmp(file, "../", 3)) | |||
file += 4; | file += 3, file_len -= 3; | |||
ft_size file_len = strlen(file); | if (file_len >= 8 && !memcmp(file, "fsremap/", 8)) | |||
file += 8, file_len -= 8; | ||||
else if (file_len >= 7 && !memcmp(file, "fsmove/", 7)) | ||||
file += 7, file_len -= 7; | ||||
if (file_len >= 4 && !memcmp(file, "src/", 4)) | ||||
file += 4, file_len -= 4; | ||||
/** skip file extension, usually .cc or .hh */ | /** skip file extension, usually .cc or .hh */ | |||
const char * dot = (const char *) memrchr(file, '.', file_len); | const char * dot = (const char *) memrchr(file, '.', file_len); | |||
if (dot != NULL) | if (dot != NULL) | |||
file_len = dot - file; | file_len = dot - file; | |||
/** if file name ends with .t then replace with <T> */ | /** if file name ends with .t then replace with <T> */ | |||
if (file_len >= 2 && !strncmp(file + file_len - 2, ".t", 2)) { | if (file_len >= 2 && file[file_len - 2] == '.' && file[file_len - 1] == 't') { | |||
file_len -= 2; | file_len -= 2; | |||
event.file_suffix = "<T>"; | event.file_suffix = "<T>"; | |||
} | } | |||
event.file = file; | event.file = file; | |||
/* conversion ft_size -> int: check for overflow, even it may seem silly for a file name */ | ||||
event.file_len = file_len; | event.file_len = file_len; | |||
if (event.file_len < 0 || file_len != (ft_size) event.file_len) | ||||
event.file_len = 255; | ||||
} | } | |||
FT_NAMESPACE_END | FT_NAMESPACE_END | |||
End of changes. 56 change blocks. | ||||
113 lines changed or deleted | 189 lines changed or added |