270#ifndef PICO_LOG_NO_FILE_PATHS
271#define log_trace(...) \
272 log_write(LOG_LEVEL_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__)
274#define log_trace(...) \
275 log_write(LOG_LEVEL_TRACE, "", 0, __func__, __VA_ARGS__)
284#ifndef PICO_LOG_NO_FILE_PATHS
285#define log_debug(...) \
286 log_write(LOG_LEVEL_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
288#define log_debug(...) \
289 log_write(LOG_LEVEL_DEBUG, "", 0, __func__, __VA_ARGS__)
297#ifndef PICO_LOG_NO_FILE_PATHS
298#define log_info(...) \
299 log_write(LOG_LEVEL_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
301#define log_info(...) \
302 log_write(LOG_LEVEL_INFO, "", 0, __func__, __VA_ARGS__)
311#ifndef PICO_LOG_NO_FILE_PATHS
312#define log_warn(...) \
313 log_write(LOG_LEVEL_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
315#define log_warn(...) \
316 log_write(LOG_LEVEL_WARN, "", 0, __func__, __VA_ARGS__)
325#ifndef PICO_LOG_NO_FILE_PATHS
326#define log_error(...) \
327 log_write(LOG_LEVEL_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
329#define log_error(...) \
330 log_write(LOG_LEVEL_ERROR, "", 0, __func__, __VA_ARGS__)
339#ifndef PICO_LOG_NO_FILE_PATHS
340#define log_fatal(...) \
341 log_write(LOG_LEVEL_FATAL, __FILE__, __LINE__, __func__, __VA_ARGS__)
343#define log_fatal(...) \
344 log_write(LOG_LEVEL_FATAL, "", 0, __func__, __VA_ARGS__)
351#if defined(__GNUC__) || defined(__clang__)
352__attribute__((format(printf, 5, 6)))
358 const char* fmt, ...);
367#ifdef PICO_LOG_IMPLEMENTATION
375#ifndef PICO_LOG_MAX_APPENDERS
376#define PICO_LOG_MAX_APPENDERS 16
379#ifndef PICO_LOG_MAX_MSG_LENGTH
380#define PICO_LOG_MAX_MSG_LENGTH 1024
384 #define PICO_LOG_ASSERT(expr) ((void)0)
386 #ifndef PICO_LOG_ASSERT
388 #define PICO_LOG_ASSERT(expr) assert(expr)
396#define LOG_MAX_APPENDERS PICO_LOG_MAX_APPENDERS
397#define LOG_MAX_MSG_LENGTH PICO_LOG_MAX_MSG_LENGTH
398#define LOG_ASSERT PICO_LOG_ASSERT
405#define LOG_TIMESTAMP_LEN 64
406#define LOG_LEVEL_LEN 32
407#define LOG_FILE_LEN 512
408#define LOG_FUNC_LEN 32
409#define LOG_MSG_LEN LOG_MAX_MSG_LENGTH
410#define LOG_BREAK_LEN 1
412#define LOG_ENTRY_LEN (LOG_TIMESTAMP_LEN + \
419#define LOG_TIME_FMT_LEN 32
420#define LOG_TIME_FMT "%d/%m/%Y %H:%M:%S"
422#define LOG_TERM_CODE 0x1B
423#define LOG_TERM_RESET "[0m"
424#define LOG_TERM_GRAY "[90m"
426static bool log_initialized =
false;
427static bool log_enabled =
true;
428static int log_appender_count = 0;
433static const char*
const log_level_str[] =
447static const char*
const log_level_str_formatted[] =
459static const char* log_level_color[] =
461 "[94m",
"[36m",
"[32m",
"[33m",
"[31m",
"[35m", NULL
475 char time_fmt[LOG_TIME_FMT_LEN];
481} log_appender_data_t;
486static log_appender_data_t log_appenders[LOG_MAX_APPENDERS];
499 for (
int i = 0; i < LOG_MAX_APPENDERS; i++)
501 log_appenders[i].appender_fp = NULL;
504 log_initialized =
true;
511 return (
id < LOG_MAX_APPENDERS && NULL != log_appenders[
id].appender_fp);
518 return log_appender_exists(
id) && log_appenders[id].enabled;
526 for (
int i = 0; log_level_str[i]; i++)
528 if (0 == strcmp(str, log_level_str[i]))
557 LOG_ASSERT(log_appender_count < LOG_MAX_APPENDERS);
563 for (
int i = 0; i < LOG_MAX_APPENDERS; i++)
565 if (NULL == log_appenders[i].appender_fp)
567 log_appender_data_t* appender = &log_appenders[i];
570 appender->appender_fp = appender_fp;
571 appender->log_level = level;
572 appender->udata = udata;
574 appender->enabled =
true;
575 appender->colors =
false;
576 appender->level =
true;
577 appender->timestamp =
false;
578 appender->file =
false;
579 appender->func =
false;
580 appender->lock_fp = NULL;
581 appender->lock_udata = NULL;
583 strncpy(appender->time_fmt, LOG_TIME_FMT, LOG_TIME_FMT_LEN);
585 log_appender_count++;
597log_stream_appender (
const char* entry,
void* udata)
599 FILE* stream = (FILE*)udata;
600 fprintf(stream,
"%s", entry);
608 LOG_ASSERT(NULL != stream);
620 LOG_ASSERT(log_appender_exists(
id));
623 log_appenders[id].appender_fp = NULL;
625 log_appender_count--;
635 LOG_ASSERT(log_appender_exists(
id));
638 log_appenders[id].enabled =
true;
648 LOG_ASSERT(log_appender_exists(
id));
651 log_appenders[id].enabled =
false;
658 LOG_ASSERT(NULL != lock_fp);
664 LOG_ASSERT(log_appender_exists(
id));
666 log_appenders[id].lock_fp = lock_fp;
667 log_appenders[id].lock_udata = udata;
677 LOG_ASSERT(log_appender_exists(
id));
683 log_appenders[id].log_level = level;
693 LOG_ASSERT(log_appender_exists(
id));
696 strncpy(log_appenders[
id].time_fmt, fmt, LOG_TIME_FMT_LEN);
706 LOG_ASSERT(log_appender_exists(
id));
709 log_appenders[id].colors = enabled;
719 LOG_ASSERT(log_appender_exists(
id));
722 log_appenders[id].timestamp = enabled;
732 LOG_ASSERT(log_appender_exists(
id));
735 log_appenders[id].level = enabled;
745 LOG_ASSERT(log_appender_exists(
id));
748 log_appenders[id].file = enabled;
758 LOG_ASSERT(log_appender_exists(
id));
761 log_appenders[id].func = enabled;
768log_time_str (
const char* time_fmt,
char* str,
size_t len)
770 time_t now = time(0);
771 size_t ret = strftime(str, len, time_fmt, localtime(&now));
781log_append_timestamp (
char* entry_str,
const char* time_fmt)
783 char time_str[LOG_TIMESTAMP_LEN + 1];
784 char tmp_str[LOG_TIMESTAMP_LEN];
786 snprintf(time_str,
sizeof(time_str),
"%s ",
787 log_time_str(time_fmt, tmp_str,
sizeof(tmp_str)));
789 strncat(entry_str, time_str, LOG_TIMESTAMP_LEN);
793log_append_level (
char* entry_str,
log_level_t level,
bool colors)
795 char level_str[LOG_LEVEL_LEN];
799 snprintf(level_str,
sizeof(level_str),
"%c%s%s %c%s",
800 LOG_TERM_CODE, log_level_color[level],
801 log_level_str_formatted[level],
802 LOG_TERM_CODE, LOG_TERM_RESET);
806 snprintf(level_str,
sizeof(level_str),
"%s ", log_level_str_formatted[level]);
809 strncat(entry_str, level_str, LOG_LEVEL_LEN);
813log_append_file (
char* entry_str,
const char* file,
unsigned line)
815 char file_str[LOG_FILE_LEN];
816 snprintf(file_str,
sizeof(file_str),
"[%s:%u] ", file, line);
817 strncat(entry_str, file_str, LOG_FILE_LEN);
821log_append_func (
char* entry_str,
const char* func,
bool colors)
823 char func_str[LOG_FUNC_LEN];
827 snprintf(func_str,
sizeof(func_str),
"%c%s[%s] %c%s",
828 LOG_TERM_CODE, LOG_TERM_GRAY,
830 LOG_TERM_CODE, LOG_TERM_RESET);
834 snprintf(func_str,
sizeof(func_str),
"[%s] ", func);
837 strncat(entry_str, func_str, LOG_FUNC_LEN);
842 const char* func,
const char* fmt, ...)
849 if (0 == log_appender_count || !log_enabled)
859 log_appender_data_t* appender = &log_appenders[i];
861 if (!log_appender_enabled(i))
864 if (log_appenders[i].log_level <= level)
866 char entry_str[LOG_ENTRY_LEN + 1];
872 if (appender->timestamp)
874 log_append_timestamp(entry_str, appender->time_fmt);
880 log_append_level(entry_str, level, appender->colors);
886 log_append_file(entry_str, file, line);
892 log_append_func(entry_str, func, appender->colors);
896 char msg_str[LOG_MSG_LEN];
900 vsnprintf(msg_str,
sizeof(msg_str), fmt, args);
903 strncat(entry_str, msg_str, LOG_MSG_LEN);
904 strcat(entry_str,
"\n");
907 if (NULL != appender->lock_fp)
909 appender->lock_fp(
true, appender->lock_udata);
912 appender->appender_fp(entry_str, appender->udata);
915 if (NULL != appender->lock_fp)
917 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