blob: 9087a325e78f43db872de0ffed2bfca85635271b [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#ifndef AOS_COMMON_LOGGING_LOGGING_H_
brians343bc112013-02-10 01:53:46 +00002#define AOS_COMMON_LOGGING_LOGGING_H_
3
Brian Silvermanf665d692013-02-17 22:11:39 -08004// This file contains the logging client interface. It works with both C and C++
5// code.
6
7#include <stdio.h>
brians343bc112013-02-10 01:53:46 +00008#include <stdint.h>
brians343bc112013-02-10 01:53:46 +00009
Brian Silvermanc2f62fa2013-03-08 15:55:43 -080010#ifdef __VXWORKS__
11// Because the vxworks system headers miss the noreturn...
12void abort(void) __attribute__((noreturn));
13#endif
14
brians343bc112013-02-10 01:53:46 +000015#ifdef __cplusplus
16extern "C" {
17#endif
18
19typedef uint8_t log_level;
Brian Silvermanf665d692013-02-17 22:11:39 -080020
brians343bc112013-02-10 01:53:46 +000021#define DECL_LEVELS \
22DECL_LEVEL(DEBUG, 0); /* stuff that gets printed out every cycle */ \
23DECL_LEVEL(INFO, 1); /* things like PosEdge/NegEdge */ \
Brian Silvermanf665d692013-02-17 22:11:39 -080024/* things that might still work if they happen occasionally */ \
brians343bc112013-02-10 01:53:46 +000025DECL_LEVEL(WARNING, 2); \
26/*-1 so that vxworks macro of same name will have same effect if used*/ \
27DECL_LEVEL(ERROR, -1); /* errors */ \
Brian Silvermanf665d692013-02-17 22:11:39 -080028/* serious errors. the logging code will terminate the process/task */ \
29DECL_LEVEL(FATAL, 4); \
brians343bc112013-02-10 01:53:46 +000030DECL_LEVEL(LOG_UNKNOWN, 5); /* unknown logging level */
Brian Silvermanf665d692013-02-17 22:11:39 -080031#define DECL_LEVEL(name, value) static const log_level name = value;
brians343bc112013-02-10 01:53:46 +000032#undef ERROR
Brian Silvermanf665d692013-02-17 22:11:39 -080033DECL_LEVELS;
brians343bc112013-02-10 01:53:46 +000034#undef DECL_LEVEL
35
36#define STRINGIFY(x) TO_STRING(x)
37#define TO_STRING(x) #x
38
39//not static const size_t for c code
Brian Silvermanf665d692013-02-17 22:11:39 -080040#define LOG_MESSAGE_LEN 500
41
42#ifdef __VXWORKS__
43// We're using ancient glibc, so sticking to just what the syscall can handle is
44// probably safer.
45#define LOG_PRINTF_FORMAT_TYPE printf
46#else
47#define LOG_PRINTF_FORMAT_TYPE gnu_printf
48#endif
49#ifdef __cplusplus
50extern "C" {
51#endif
52// Actually implements the basic logging call.
53// Does not check that level is valid.
54void log_do(log_level level, const char *format, ...)
55 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 2, 3)));
56
57void log_cork(int line, const char *function, const char *format, ...)
58 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 3, 4)));
59// Implements the uncork logging call.
60void log_uncork(int line, const char *function, log_level level,
61 const char *file, const char *format, ...)
62 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 5, 6)));
63#ifdef __cplusplus
64}
65#endif
66
67// A magical static const char[] or string literal that communicates the name
68// of the enclosing function.
69// It's currently using __PRETTY_FUNCTION__ because both GCC and Clang support
70// that and it gives nicer results in C++ than the standard __func__ (which
71// would also work).
72#define LOG_CURRENT_FUNCTION __PRETTY_FUNCTION__
73
74// The basic logging call.
75#define LOG(level, format, args...) do {\
76 log_do(level, LOG_SOURCENAME ": " STRINGIFY(__LINE__) ": %s: " format, \
77 LOG_CURRENT_FUNCTION, ##args); \
78 /* so that GCC knows that it won't return */ \
79 if (level == FATAL) { \
80 fprintf(stderr, "log_do(FATAL) fell through!!!!!\n"); \
81 printf("see stderr\n"); \
82 abort(); \
83 } \
84} while (0)
brians343bc112013-02-10 01:53:46 +000085
86// Allows format to not be a string constant.
Brian Silvermanf665d692013-02-17 22:11:39 -080087#define LOG_DYNAMIC(level, format, args...) do { \
brians343bc112013-02-10 01:53:46 +000088 static char log_buf[LOG_MESSAGE_LEN]; \
89 int ret = snprintf(log_buf, sizeof(log_buf), format, ##args); \
Brian Silvermanf665d692013-02-17 22:11:39 -080090 if (ret < 0 || (uintmax_t)ret >= LOG_MESSAGE_LEN) { \
91 LOG(ERROR, "next message was too long so not subbing in args\n"); \
brians343bc112013-02-10 01:53:46 +000092 LOG(level, "%s", format); \
93 }else{ \
94 LOG(level, "%s", log_buf); \
95 } \
Brian Silvermanf665d692013-02-17 22:11:39 -080096} while (0)
brians343bc112013-02-10 01:53:46 +000097
Brian Silvermanf665d692013-02-17 22:11:39 -080098// Allows "bottling up" multiple log fragments which can then all be logged in
99// one message with LOG_UNCORK.
100// Calls from a given thread/task will be grouped together.
101#define LOG_CORK(format, args...) do { \
102 log_cork(__LINE__, LOG_CURRENT_FUNCTION, format, ##args); \
103} while (0)
104// Actually logs all of the saved up log fragments (including format and args on
105// the end).
106#define LOG_UNCORK(level, format, args...) do { \
107 log_uncork(__LINE__, LOG_CURRENT_FUNCTION, level, LOG_SOURCENAME, \
108 format, ##args); \
109} while (0)
brians343bc112013-02-10 01:53:46 +0000110
Brian Silvermanf665d692013-02-17 22:11:39 -0800111// TODO(brians) add CHECK macros like glog
112// (<http://google-glog.googlecode.com/svn/trunk/doc/glog.html>)
113// and replace assert with one
brians343bc112013-02-10 01:53:46 +0000114
115#ifdef __cplusplus
116}
117#endif
118
brians343bc112013-02-10 01:53:46 +0000119#endif