brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 1 | #ifndef AOS_COMMON_LOGGING_LOGGING_H_ |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 2 | #define AOS_COMMON_LOGGING_LOGGING_H_ |
| 3 | |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 4 | // This file contains the logging client interface. It works with both C and C++ |
| 5 | // code. |
| 6 | |
| 7 | #include <stdio.h> |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 8 | #include <stdint.h> |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 9 | |
| 10 | #ifdef __cplusplus |
| 11 | extern "C" { |
| 12 | #endif |
| 13 | |
| 14 | typedef uint8_t log_level; |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 15 | |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 16 | #define DECL_LEVELS \ |
| 17 | DECL_LEVEL(DEBUG, 0); /* stuff that gets printed out every cycle */ \ |
| 18 | DECL_LEVEL(INFO, 1); /* things like PosEdge/NegEdge */ \ |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 19 | /* things that might still work if they happen occasionally */ \ |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 20 | DECL_LEVEL(WARNING, 2); \ |
| 21 | /*-1 so that vxworks macro of same name will have same effect if used*/ \ |
| 22 | DECL_LEVEL(ERROR, -1); /* errors */ \ |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 23 | /* serious errors. the logging code will terminate the process/task */ \ |
| 24 | DECL_LEVEL(FATAL, 4); \ |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 25 | DECL_LEVEL(LOG_UNKNOWN, 5); /* unknown logging level */ |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 26 | #define DECL_LEVEL(name, value) static const log_level name = value; |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 27 | #undef ERROR |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 28 | DECL_LEVELS; |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 29 | #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 Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 35 | #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 |
| 45 | extern "C" { |
| 46 | #endif |
| 47 | // Actually implements the basic logging call. |
| 48 | // Does not check that level is valid. |
| 49 | void log_do(log_level level, const char *format, ...) |
| 50 | __attribute__((format(LOG_PRINTF_FORMAT_TYPE, 2, 3))); |
| 51 | |
| 52 | void 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. |
| 55 | void 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) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 80 | |
| 81 | // Allows format to not be a string constant. |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 82 | #define LOG_DYNAMIC(level, format, args...) do { \ |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 83 | static char log_buf[LOG_MESSAGE_LEN]; \ |
| 84 | int ret = snprintf(log_buf, sizeof(log_buf), format, ##args); \ |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 85 | if (ret < 0 || (uintmax_t)ret >= LOG_MESSAGE_LEN) { \ |
| 86 | LOG(ERROR, "next message was too long so not subbing in args\n"); \ |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 87 | LOG(level, "%s", format); \ |
| 88 | }else{ \ |
| 89 | LOG(level, "%s", log_buf); \ |
| 90 | } \ |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 91 | } while (0) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 92 | |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 93 | // 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) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 105 | |
Brian Silverman | f665d69 | 2013-02-17 22:11:39 -0800 | [diff] [blame^] | 106 | // TODO(brians) add CHECK macros like glog |
| 107 | // (<http://google-glog.googlecode.com/svn/trunk/doc/glog.html>) |
| 108 | // and replace assert with one |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 109 | |
| 110 | #ifdef __cplusplus |
| 111 | } |
| 112 | #endif |
| 113 | |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 114 | #endif |