blob: 392fc5be686653d379c47b6fb21b425fb20305fc [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
10#ifdef __cplusplus
11extern "C" {
12#endif
13
14typedef uint8_t log_level;
Brian Silvermanf665d692013-02-17 22:11:39 -080015
brians343bc112013-02-10 01:53:46 +000016#define DECL_LEVELS \
17DECL_LEVEL(DEBUG, 0); /* stuff that gets printed out every cycle */ \
18DECL_LEVEL(INFO, 1); /* things like PosEdge/NegEdge */ \
Brian Silvermanf665d692013-02-17 22:11:39 -080019/* things that might still work if they happen occasionally */ \
brians343bc112013-02-10 01:53:46 +000020DECL_LEVEL(WARNING, 2); \
21/*-1 so that vxworks macro of same name will have same effect if used*/ \
22DECL_LEVEL(ERROR, -1); /* errors */ \
Brian Silvermanf665d692013-02-17 22:11:39 -080023/* serious errors. the logging code will terminate the process/task */ \
24DECL_LEVEL(FATAL, 4); \
brians343bc112013-02-10 01:53:46 +000025DECL_LEVEL(LOG_UNKNOWN, 5); /* unknown logging level */
Brian Silvermanf665d692013-02-17 22:11:39 -080026#define DECL_LEVEL(name, value) static const log_level name = value;
brians343bc112013-02-10 01:53:46 +000027#undef ERROR
Brian Silvermanf665d692013-02-17 22:11:39 -080028DECL_LEVELS;
brians343bc112013-02-10 01:53:46 +000029#undef DECL_LEVEL
30
31#define STRINGIFY(x) TO_STRING(x)
32#define TO_STRING(x) #x
33
34//not static const size_t for c code
Brian Silvermanf665d692013-02-17 22:11:39 -080035#define LOG_MESSAGE_LEN 500
36
37#ifdef __VXWORKS__
38// We're using ancient glibc, so sticking to just what the syscall can handle is
39// probably safer.
40#define LOG_PRINTF_FORMAT_TYPE printf
41#else
42#define LOG_PRINTF_FORMAT_TYPE gnu_printf
43#endif
44#ifdef __cplusplus
45extern "C" {
46#endif
47// Actually implements the basic logging call.
48// Does not check that level is valid.
49void log_do(log_level level, const char *format, ...)
50 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 2, 3)));
51
52void log_cork(int line, const char *function, const char *format, ...)
53 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 3, 4)));
54// Implements the uncork logging call.
55void log_uncork(int line, const char *function, log_level level,
56 const char *file, const char *format, ...)
57 __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 5, 6)));
58#ifdef __cplusplus
59}
60#endif
61
62// A magical static const char[] or string literal that communicates the name
63// of the enclosing function.
64// It's currently using __PRETTY_FUNCTION__ because both GCC and Clang support
65// that and it gives nicer results in C++ than the standard __func__ (which
66// would also work).
67#define LOG_CURRENT_FUNCTION __PRETTY_FUNCTION__
68
69// The basic logging call.
70#define LOG(level, format, args...) do {\
71 log_do(level, LOG_SOURCENAME ": " STRINGIFY(__LINE__) ": %s: " format, \
72 LOG_CURRENT_FUNCTION, ##args); \
73 /* so that GCC knows that it won't return */ \
74 if (level == FATAL) { \
75 fprintf(stderr, "log_do(FATAL) fell through!!!!!\n"); \
76 printf("see stderr\n"); \
77 abort(); \
78 } \
79} while (0)
brians343bc112013-02-10 01:53:46 +000080
81// Allows format to not be a string constant.
Brian Silvermanf665d692013-02-17 22:11:39 -080082#define LOG_DYNAMIC(level, format, args...) do { \
brians343bc112013-02-10 01:53:46 +000083 static char log_buf[LOG_MESSAGE_LEN]; \
84 int ret = snprintf(log_buf, sizeof(log_buf), format, ##args); \
Brian Silvermanf665d692013-02-17 22:11:39 -080085 if (ret < 0 || (uintmax_t)ret >= LOG_MESSAGE_LEN) { \
86 LOG(ERROR, "next message was too long so not subbing in args\n"); \
brians343bc112013-02-10 01:53:46 +000087 LOG(level, "%s", format); \
88 }else{ \
89 LOG(level, "%s", log_buf); \
90 } \
Brian Silvermanf665d692013-02-17 22:11:39 -080091} while (0)
brians343bc112013-02-10 01:53:46 +000092
Brian Silvermanf665d692013-02-17 22:11:39 -080093// Allows "bottling up" multiple log fragments which can then all be logged in
94// one message with LOG_UNCORK.
95// Calls from a given thread/task will be grouped together.
96#define LOG_CORK(format, args...) do { \
97 log_cork(__LINE__, LOG_CURRENT_FUNCTION, format, ##args); \
98} while (0)
99// Actually logs all of the saved up log fragments (including format and args on
100// the end).
101#define LOG_UNCORK(level, format, args...) do { \
102 log_uncork(__LINE__, LOG_CURRENT_FUNCTION, level, LOG_SOURCENAME, \
103 format, ##args); \
104} while (0)
brians343bc112013-02-10 01:53:46 +0000105
Brian Silvermanf665d692013-02-17 22:11:39 -0800106// TODO(brians) add CHECK macros like glog
107// (<http://google-glog.googlecode.com/svn/trunk/doc/glog.html>)
108// and replace assert with one
brians343bc112013-02-10 01:53:46 +0000109
110#ifdef __cplusplus
111}
112#endif
113
brians343bc112013-02-10 01:53:46 +0000114#endif