269#define log_trace(...) \
270 log_write(LOG_LEVEL_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__)
278#define log_debug(...) \
279 log_write(LOG_LEVEL_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
287#define log_info(...) \
288 log_write(LOG_LEVEL_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
296#define log_warn(...) \
297 log_write(LOG_LEVEL_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
305#define log_error(...) \
306 log_write(LOG_LEVEL_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
314#define log_fatal(...) \
315 log_write(LOG_LEVEL_FATAL, __FILE__, __LINE__, __func__, __VA_ARGS__)
322#if defined(__GNUC__) || defined(__clang__)
323__attribute__((format(printf, 5, 6)))
329 const char* fmt, ...);
338#ifdef PICO_LOG_IMPLEMENTATION
346#ifndef PICO_LOG_MAX_APPENDERS
347#define PICO_LOG_MAX_APPENDERS 16
350#ifndef PICO_LOG_MAX_MSG_LENGTH
351#define PICO_LOG_MAX_MSG_LENGTH 1024
355 #define PICO_LOG_ASSERT(expr) ((void)0)
357 #ifndef PICO_LOG_ASSERT
359 #define PICO_LOG_ASSERT(expr) assert(expr)
367#define LOG_MAX_APPENDERS PICO_LOG_MAX_APPENDERS
368#define LOG_MAX_MSG_LENGTH PICO_LOG_MAX_MSG_LENGTH
369#define LOG_ASSERT PICO_LOG_ASSERT
376#define LOG_TIMESTAMP_LEN 64
377#define LOG_LEVEL_LEN 32
378#define LOG_FILE_LEN 512
379#define LOG_FUNC_LEN 32
380#define LOG_MSG_LEN LOG_MAX_MSG_LENGTH
381#define LOG_BREAK_LEN 1
383#define LOG_ENTRY_LEN (LOG_TIMESTAMP_LEN + \
390#define LOG_TIME_FMT_LEN 32
391#define LOG_TIME_FMT "%d/%m/%Y %H:%M:%S"
393#define LOG_TERM_CODE 0x1B
394#define LOG_TERM_RESET "[0m"
395#define LOG_TERM_GRAY "[90m"
397static bool log_initialized =
false;
398static bool log_enabled =
true;
399static int log_appender_count = 0;
404static const char*
const log_level_str[] =
418static const char*
const log_level_str_formatted[] =
430static const char* log_level_color[] =
432 "[94m",
"[36m",
"[32m",
"[33m",
"[31m",
"[35m", NULL
446 char time_fmt[LOG_TIME_FMT_LEN];
452} log_appender_data_t;
457static log_appender_data_t log_appenders[LOG_MAX_APPENDERS];
470 for (
int i = 0; i < LOG_MAX_APPENDERS; i++)
472 log_appenders[i].appender_fp = NULL;
475 log_initialized =
true;
482 return (
id < LOG_MAX_APPENDERS && NULL != log_appenders[
id].appender_fp);
489 return log_appender_exists(
id) && log_appenders[id].enabled;
497 for (
int i = 0; log_level_str[i]; i++)
499 if (0 == strcmp(str, log_level_str[i]))
528 LOG_ASSERT(log_appender_count < LOG_MAX_APPENDERS);
534 for (
int i = 0; i < LOG_MAX_APPENDERS; i++)
536 if (NULL == log_appenders[i].appender_fp)
538 log_appender_data_t* appender = &log_appenders[i];
541 appender->appender_fp = appender_fp;
542 appender->log_level = level;
543 appender->udata = udata;
545 appender->enabled =
true;
546 appender->colors =
false;
547 appender->level =
true;
548 appender->timestamp =
false;
549 appender->file =
false;
550 appender->func =
false;
551 appender->lock_fp = NULL;
552 appender->lock_udata = NULL;
554 strncpy(appender->time_fmt, LOG_TIME_FMT, LOG_TIME_FMT_LEN);
556 log_appender_count++;
568log_stream_appender (
const char* entry,
void* udata)
570 FILE* stream = (FILE*)udata;
571 fprintf(stream,
"%s", entry);
579 LOG_ASSERT(NULL != stream);
591 LOG_ASSERT(log_appender_exists(
id));
594 log_appenders[id].appender_fp = NULL;
596 log_appender_count--;
606 LOG_ASSERT(log_appender_exists(
id));
609 log_appenders[id].enabled =
true;
619 LOG_ASSERT(log_appender_exists(
id));
622 log_appenders[id].enabled =
false;
629 LOG_ASSERT(NULL != lock_fp);
635 LOG_ASSERT(log_appender_exists(
id));
637 log_appenders[id].lock_fp = lock_fp;
638 log_appenders[id].lock_udata = udata;
648 LOG_ASSERT(log_appender_exists(
id));
654 log_appenders[id].log_level = level;
664 LOG_ASSERT(log_appender_exists(
id));
667 strncpy(log_appenders[
id].time_fmt, fmt, LOG_TIME_FMT_LEN);
677 LOG_ASSERT(log_appender_exists(
id));
680 log_appenders[id].colors = enabled;
690 LOG_ASSERT(log_appender_exists(
id));
693 log_appenders[id].timestamp = enabled;
703 LOG_ASSERT(log_appender_exists(
id));
706 log_appenders[id].level = enabled;
716 LOG_ASSERT(log_appender_exists(
id));
719 log_appenders[id].file = enabled;
729 LOG_ASSERT(log_appender_exists(
id));
732 log_appenders[id].func = enabled;
739log_time_str (
const char* time_fmt,
char* str,
size_t len)
741 time_t now = time(0);
742 size_t ret = strftime(str, len, time_fmt, localtime(&now));
750log_append_timestamp (
char* entry_str,
const char* time_fmt)
752 char time_str[LOG_TIMESTAMP_LEN + 1];
753 char tmp_str[LOG_TIMESTAMP_LEN];
755 snprintf(time_str,
sizeof(time_str),
"%s ",
756 log_time_str(time_fmt, tmp_str,
sizeof(tmp_str)));
758 strncat(entry_str, time_str, LOG_TIMESTAMP_LEN);
762log_append_level (
char* entry_str,
log_level_t level,
bool colors)
764 char level_str[LOG_LEVEL_LEN];
768 snprintf(level_str,
sizeof(level_str),
"%c%s%s %c%s",
769 LOG_TERM_CODE, log_level_color[level],
770 log_level_str_formatted[level],
771 LOG_TERM_CODE, LOG_TERM_RESET);
775 snprintf(level_str,
sizeof(level_str),
"%s ", log_level_str_formatted[level]);
778 strncat(entry_str, level_str, LOG_LEVEL_LEN);
782log_append_file (
char* entry_str,
const char* file,
unsigned line)
784 char file_str[LOG_FILE_LEN];
785 snprintf(file_str,
sizeof(file_str),
"[%s:%u] ", file, line);
786 strncat(entry_str, file_str, LOG_FILE_LEN);
790log_append_func (
char* entry_str,
const char* func,
bool colors)
792 char func_str[LOG_FUNC_LEN];
796 snprintf(func_str,
sizeof(func_str),
"%c%s[%s] %c%s",
797 LOG_TERM_CODE, LOG_TERM_GRAY,
799 LOG_TERM_CODE, LOG_TERM_RESET);
803 snprintf(func_str,
sizeof(func_str),
"[%s] ", func);
806 strncat(entry_str, func_str, LOG_FUNC_LEN);
811 const char* func,
const char* fmt, ...)
818 if (0 == log_appender_count || !log_enabled)
828 log_appender_data_t* appender = &log_appenders[i];
830 if (!log_appender_enabled(i))
833 if (log_appenders[i].log_level <= level)
835 char entry_str[LOG_ENTRY_LEN + 1];
841 if (appender->timestamp)
843 log_append_timestamp(entry_str, appender->time_fmt);
849 log_append_level(entry_str, level, appender->colors);
855 log_append_file(entry_str, file, line);
861 log_append_func(entry_str, func, appender->colors);
865 char msg_str[LOG_MSG_LEN];
869 vsnprintf(msg_str,
sizeof(msg_str), fmt, args);
872 strncat(entry_str, msg_str, LOG_MSG_LEN);
873 strcat(entry_str,
"\n");
876 if (NULL != appender->lock_fp)
878 appender->lock_fp(
true, appender->lock_udata);
881 appender->appender_fp(entry_str, appender->udata);
884 if (NULL != appender->lock_fp)
886 appender->lock_fp(
false, appender->lock_udata);
void log_display_timestamp(log_appender_t id, bool enabled)
Turns timestamp reporting on/off for the specified appender. NOTE: Off by default.
void log_write(log_level_t level, const char *file, unsigned line, const char *func, const char *fmt,...)
void log_disable(void)
Disables logging.
void log_display_file(log_appender_t id, bool enabled)
Turns filename and line number reporting on/off for the specified appender. NOTE: Off by default.
void log_enable(void)
Enables logging. NOTE: Logging is enabled by default.
void(* log_appender_fn)(const char *entry, void *udata)
Appender function definition. An appender writes a log entry to an output stream. This could be the c...
Definition pico_log.h:100
bool log_str_to_level(const char *str, log_level_t *level)
Converts a string to the corresponding log level.
void log_display_colors(log_appender_t id, bool enabled)
Turns colors ouput on or off for the specified appender. NOTE: Off by default.
void log_display_level(log_appender_t id, bool enabled)
Turns log level reporting on/off for the specified appender. NOTE: On by default.
log_appender_t log_add_stream(FILE *stream, log_level_t level)
Registers an output stream appender.
log_level_t
These codes allow different layers of granularity when logging. See the documentation of the log_set_...
Definition pico_log.h:86
@ LOG_LEVEL_DEBUG
Definition pico_log.h:88
@ LOG_LEVEL_ERROR
Definition pico_log.h:91
@ LOG_LEVEL_FATAL
Definition pico_log.h:92
@ LOG_LEVEL_TRACE
Definition pico_log.h:87
@ LOG_LEVEL_WARN
Definition pico_log.h:90
@ LOG_LEVEL_COUNT
Definition pico_log.h:93
@ LOG_LEVEL_INFO
Definition pico_log.h:89
void log_set_level(log_appender_t id, log_level_t level)
Sets the logging level.
void log_set_lock(log_appender_t id, log_appender_lock_fn lock_fp, void *udata)
Sets the lock function for a given appender.
void log_remove_appender(log_appender_t id)
Unregisters appender (removes the appender from the logger).
void log_display_function(log_appender_t id, bool enabled)
Turns function reporting on/off for the specified appender. NOTE: Off by default.
void log_enable_appender(log_appender_t id)
Enables the specified appender. NOTE: Appenders are enabled by default after registration.
log_appender_t log_add_appender(log_appender_fn appender_fp, log_level_t level, void *udata)
Registers an appender.
void log_set_time_fmt(log_appender_t id, const char *fmt)
Set the appender timestamp.
int log_appender_t
Identifies a registered appender.
Definition pico_log.h:113
void log_disable_appender(log_appender_t id)
Disables the specified appender.
void(* log_appender_lock_fn)(bool lock, void *udata)
Lock function definition. This is called during log_write.
Definition pico_log.h:108