aboutsummaryrefslogtreecommitdiff
path: root/any_log.h
blob: 63461f11771efc0901d78ec28acc73e5adea3572 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#ifndef ANY_LOG_INCLUDE
#define ANY_LOG_INCLUDE

typedef enum {
    LOG_PANIC,
    LOG_ERROR,
    LOG_WARN,
    LOG_INFO,
    LOG_DEBUG,
    LOG_TRACE,
    LOG_ALL,
} log_level_t;

// The value of ANY_LOG_MODULE is used to indicate the current module.
// By default it is defined as __FILE__, so that it will coincide with the
// source file path (relative to the compiler cwd).
//
// You can customize ANY_LOG_MODULE before including the header by simply
// defining it. For example
//
//    #define ANY_LOG_MODULE "my-library"
//    #include "any_log.h"
//
#ifndef ANY_LOG_MODULE
#define ANY_LOG_MODULE __FILE__
#endif

// C99 and later define the __func__ variable
#ifndef ANY_LOG_FUNC
#define ANY_LOG_FUNC __func__
#endif

#define log_panic(...) \
    do { \
        log_generic(LOG_PANIC, ANY_LOG_MODULE, ANY_LOG_FUNC, __VA_ARGS__); \
        log_exit(ANY_LOG_MODULE, ANY_LOG_FUNC); \
    } while (0)

#define log_error(...) \
    log_generic(LOG_ERROR, ANY_LOG_MODULE, ANY_LOG_FUNC, __VA_ARGS__)

#define log_warn(...)  \
    log_generic(LOG_WARN, ANY_LOG_MODULE, ANY_LOG_FUNC, __VA_ARGS__)

#define log_info(...)  \
    log_generic(LOG_INFO, ANY_LOG_MODULE, ANY_LOG_FUNC, __VA_ARGS__)

#define log_debug(...) \
    log_generic(LOG_DEBUG, ANY_LOG_MODULE, ANY_LOG_FUNC, __VA_ARGS__)

#ifdef ANY_LOG_NO_TRACE
#define log_trace(...)
#else
#define log_trace(...) \
    log_generic(LOG_TRACE, ANY_LOG_MODULE, ANY_LOG_FUNC, __VA_ARGS__)
#endif

void log_exit(const char *module, const char *func);

void log_generic(log_level_t level, const char *module,
                 const char *func, const char *format, ...);


#endif

#ifdef ANY_LOG_IMPLEMENT

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

// Using log_panic results in a call to log_exit, which should terminate
// the program. The value of ANY_LOG_PANIC is used to specify what action
// to take in log_exit.
// By default it is abort
//
// NOTE: That log_exit should never return!
//
#ifndef ANY_LOG_PANIC
#define ANY_LOG_PANIC(module, func) abort()
#endif

// NOTE: This function should be called solely by the macro log_panic
void log_exit(const char *module, const char *func)
{
    ANY_LOG_PANIC(module, func);
}

#ifndef ANY_LOG_FORMAT_BEFORE
#define ANY_LOG_FORMAT_BEFORE(level, module, func, levels) \
    "[%s %s] %s: ", module, func, levels[level]
#endif

#ifndef ANY_LOG_FORMAT_AFTER
#define ANY_LOG_FORMAT_AFTER(level, module, func, levels) "\n"
#endif

void log_generic(log_level_t level, const char *module,
		         const char *func, const char *format, ...)
{
	const char *log_levels[] = {
		"panic", "error", "warn",
		"info", "debug", "trace",
	};

	fprintf(stdout, ANY_LOG_FORMAT_BEFORE(level, module, func, log_levels));

    va_list args;
    va_start(args, format);
    vfprintf(stdout, format, args);
    va_end(args);

	fprintf(stdout, ANY_LOG_FORMAT_AFTER(level, module, func, log_levels));
}

#endif

// vim: ts=4 sw=4 et