1 /*
2   +----------------------------------------------------------------------+
3   | Swoole                                                               |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 2.0 of the Apache license,    |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | http://www.apache.org/licenses/LICENSE-2.0.html                      |
9   | If you did not receive a copy of the Apache2.0 license and are unable|
10   | to obtain it through the world-wide-web, please send a note to       |
11   | license@swoole.com so we can mail you a copy immediately.            |
12   +----------------------------------------------------------------------+
13   | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
14   +----------------------------------------------------------------------+
15 */
16 
17 #pragma once
18 
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <string>
22 #include <unistd.h>
23 
24 #define SW_LOG_BUFFER_SIZE (SW_ERROR_MSG_SIZE + 256)
25 #define SW_LOG_DATE_STRLEN 128
26 #define SW_LOG_DEFAULT_DATE_FORMAT "%F %T"
27 
28 enum swLogLevel {
29     SW_LOG_DEBUG = 0,
30     SW_LOG_TRACE,
31     SW_LOG_INFO,
32     SW_LOG_NOTICE,
33     SW_LOG_WARNING,
34     SW_LOG_ERROR,
35     SW_LOG_NONE,
36 };
37 
38 enum swLogRotationType {
39     SW_LOG_ROTATION_SINGLE = 0,
40     SW_LOG_ROTATION_MONTHLY,
41     SW_LOG_ROTATION_DAILY,
42     SW_LOG_ROTATION_HOURLY,
43     SW_LOG_ROTATION_EVERY_MINUTE,
44 };
45 
46 namespace swoole {
47 class Logger {
48   private:
49     bool opened = false;
50     // Redirect stdin and stdout to log_fd
51     bool redirected = false;
52     bool display_backtrace_ = false;
53     int stdout_fd = -1;
54     int stderr_fd = -1;
55     int log_fd = STDOUT_FILENO;
56     int log_level = SW_LOG_INFO;
57     bool date_with_microseconds = false;
58     std::string date_format = SW_LOG_DEFAULT_DATE_FORMAT;
59     std::string log_file = "";
60     std::string log_real_file;
61     int log_rotation = SW_LOG_ROTATION_SINGLE;
62 
63   public:
64     bool open(const char *logfile);
65     void put(int level, const char *content, size_t length);
66     void reopen();
67     void close(void);
68     void reset();
69     void set_level(int lv);
70     int get_level();
71     bool set_date_format(const char *format);
72     void set_rotation(int rotation);
73     const char *get_real_file();
74     const char *get_file();
75     bool is_opened();
76     bool redirect_stdout_and_stderr(int enable);
77     void set_date_with_microseconds(bool enable);
78     std::string gen_real_file(const std::string &file);
79     static std::string get_pretty_name(const std::string &prettyFunction, bool strip = true);
80 
display_backtrace()81     void display_backtrace() {
82         display_backtrace_ = true;
83     }
84 };
85 }  // namespace swoole
86 
87 swoole::Logger *sw_logger();
88 #define __SW_FUNC__ (swoole::Logger::get_pretty_name(__PRETTY_FUNCTION__).c_str())
89 
90 #define swoole_info(str, ...)                                                                                          \
91     if (SW_LOG_INFO >= sw_logger()->get_level()) {                                                                     \
92         size_t _sw_error_len = sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, str, ##__VA_ARGS__);                           \
93         sw_logger()->put(SW_LOG_INFO, sw_error, _sw_error_len);                                                        \
94     }
95 
96 #define swoole_notice(str, ...)                                                                                        \
97     if (SW_LOG_NOTICE >= sw_logger()->get_level()) {                                                                   \
98         size_t _sw_error_len = sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, str, ##__VA_ARGS__);                           \
99         sw_logger()->put(SW_LOG_NOTICE, sw_error, _sw_error_len);                                                      \
100     }
101 
102 #define swoole_sys_notice(str, ...)                                                                                    \
103     do {                                                                                                               \
104         swoole_set_last_error(errno);                                                                                  \
105         if (SW_LOG_ERROR >= sw_logger()->get_level()) {                                                                \
106             size_t _sw_error_len = sw_snprintf(sw_error,                                                               \
107                                                SW_ERROR_MSG_SIZE,                                                      \
108                                                "%s(:%d): " str ", Error: %s[%d]",                                      \
109                                                __SW_FUNC__,                                                            \
110                                                __LINE__,                                                               \
111                                                ##__VA_ARGS__,                                                          \
112                                                swoole_strerror(errno),                                                 \
113                                                errno);                                                                 \
114             sw_logger()->put(SW_LOG_NOTICE, sw_error, _sw_error_len);                                                  \
115         }                                                                                                              \
116     } while (0)
117 
118 #define swoole_warning(str, ...)                                                                                       \
119     do {                                                                                                               \
120         if (SW_LOG_WARNING >= sw_logger()->get_level()) {                                                              \
121             size_t _sw_error_len = sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s(): " str, __SW_FUNC__, ##__VA_ARGS__); \
122             sw_logger()->put(SW_LOG_WARNING, sw_error, _sw_error_len);                                                 \
123         }                                                                                                              \
124     } while (0)
125 
126 #define swoole_sys_warning(str, ...)                                                                                   \
127     do {                                                                                                               \
128         swoole_set_last_error(errno);                                                                                  \
129         if (SW_LOG_ERROR >= sw_logger()->get_level()) {                                                                \
130             size_t _sw_error_len = sw_snprintf(sw_error,                                                               \
131                                                SW_ERROR_MSG_SIZE,                                                      \
132                                                "%s(): " str ", Error: %s[%d]",                                         \
133                                                __SW_FUNC__,                                                            \
134                                                ##__VA_ARGS__,                                                          \
135                                                swoole_strerror(errno),                                                 \
136                                                errno);                                                                 \
137             sw_logger()->put(SW_LOG_WARNING, sw_error, _sw_error_len);                                                 \
138         }                                                                                                              \
139     } while (0)
140 
141 #define swoole_error(str, ...)                                                                                         \
142     do {                                                                                                               \
143         size_t _sw_error_len = sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, str, ##__VA_ARGS__);                           \
144         sw_logger()->put(SW_LOG_ERROR, sw_error, _sw_error_len);                                                       \
145         exit(1);                                                                                                       \
146     } while (0)
147 
148 #define swoole_sys_error(str, ...)                                                                                     \
149     do {                                                                                                               \
150         size_t _sw_error_len = sw_snprintf(sw_error,                                                                   \
151                                            SW_ERROR_MSG_SIZE,                                                          \
152                                            "%s(): " str ", Error: %s[%d]",                                             \
153                                            __SW_FUNC__,                                                                \
154                                            ##__VA_ARGS__,                                                              \
155                                            swoole_strerror(errno),                                                     \
156                                            errno);                                                                     \
157         sw_logger()->put(SW_LOG_ERROR, sw_error, _sw_error_len);                                                       \
158         exit(1);                                                                                                       \
159     } while (0)
160 
161 #define swoole_fatal_error(code, str, ...)                                                                             \
162     do {                                                                                                               \
163         SwooleG.fatal_error(code, str, ##__VA_ARGS__);                                                                 \
164         exit(255);                                                                                                     \
165     } while (0)
166 
167 #define swoole_error_log(level, error, str, ...)                                                                       \
168     do {                                                                                                               \
169         swoole_set_last_error(error);                                                                                  \
170         if (level >= sw_logger()->get_level() && !swoole_is_ignored_error(error)) {                                    \
171             size_t _sw_error_len =                                                                                     \
172                 sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s() (ERRNO %d): " str, __SW_FUNC__, error, ##__VA_ARGS__);  \
173             sw_logger()->put(level, sw_error, _sw_error_len);                                                          \
174         }                                                                                                              \
175     } while (0)
176 
177 #ifdef SW_DEBUG
178 #define swoole_debug(str, ...)                                                                                         \
179     if (SW_LOG_DEBUG >= sw_logger()->get_level()) {                                                                    \
180         size_t _sw_error_len =                                                                                         \
181             sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s(:%d): " str, __SW_FUNC__, __LINE__, ##__VA_ARGS__);           \
182         sw_logger()->put(SW_LOG_DEBUG, sw_error, _sw_error_len);                                                       \
183     }
184 
185 #define swoole_hex_dump(data, length)                                                                                  \
186     do {                                                                                                               \
187         const char *__data = (data);                                                                                   \
188         size_t __length = (length);                                                                                    \
189         swoole_debug("+----------+------------+-----------+-----------+------------+------------------+");             \
190         for (size_t of = 0; of < __length; of += 16) {                                                                 \
191             char hex[16 * 3 + 1];                                                                                      \
192             char str[16 + 1];                                                                                          \
193             size_t i, hof = 0, sof = 0;                                                                                \
194             for (i = of; i < of + 16 && i < __length; i++) {                                                           \
195                 hof += sprintf(hex + hof, "%02x ", (__data)[i] & 0xff);                                                \
196                 sof += sprintf(str + sof, "%c", isprint((int) (__data)[i]) ? (__data)[i] : '.');                       \
197             }                                                                                                          \
198             swoole_debug("| %08x | %-48s| %-16s |", of, hex, str);                                                     \
199         }                                                                                                              \
200         swoole_debug("+----------+------------+-----------+-----------+------------+------------------+");             \
201     } while (0)
202 #else
203 #define swoole_debug(str, ...)
204 #define swoole_hex_dump(data, length)
205 #endif
206 
207 enum swTrace_type {
208     /**
209      * Server
210      */
211     SW_TRACE_SERVER = 1u << 1,
212     SW_TRACE_CLIENT = 1u << 2,
213     SW_TRACE_BUFFER = 1u << 3,
214     SW_TRACE_CONN = 1u << 4,
215     SW_TRACE_EVENT = 1u << 5,
216     SW_TRACE_WORKER = 1u << 6,
217     SW_TRACE_MEMORY = 1u << 7,
218     SW_TRACE_REACTOR = 1u << 8,
219     SW_TRACE_PHP = 1u << 9,
220     SW_TRACE_HTTP = 1u << 10,
221     SW_TRACE_HTTP2 = 1u << 11,
222     SW_TRACE_EOF_PROTOCOL = 1u << 12,
223     SW_TRACE_LENGTH_PROTOCOL = 1u << 13,
224     SW_TRACE_CLOSE = 1u << 14,
225     SW_TRACE_WEBSOCKET = 1u << 15,
226     /**
227      * Client
228      */
229     SW_TRACE_REDIS_CLIENT = 1u << 16,
230     SW_TRACE_MYSQL_CLIENT = 1u << 17,
231     SW_TRACE_HTTP_CLIENT = 1u << 18,
232     SW_TRACE_AIO = 1u << 19,
233     SW_TRACE_SSL = 1u << 20,
234     SW_TRACE_NORMAL = 1u << 21,
235     /**
236      * Coroutine
237      */
238     SW_TRACE_CHANNEL = 1u << 22,
239     SW_TRACE_TIMER = 1u << 23,
240     SW_TRACE_SOCKET = 1u << 24,
241     SW_TRACE_COROUTINE = 1u << 25,
242     SW_TRACE_CONTEXT = 1u << 26,
243     SW_TRACE_CO_HTTP_SERVER = 1u << 27,
244     SW_TRACE_TABLE = 1u << 28,
245     SW_TRACE_CO_CURL = 1u << 29,
246     SW_TRACE_CARES = 1u << 30,
247 
248     SW_TRACE_ALL = 0x7fffffffffffffff
249 };
250 
251 #ifdef SW_LOG_TRACE_OPEN
252 #define swoole_trace_log(what, str, ...)                                                                               \
253     if (SW_LOG_TRACE >= sw_logger()->get_level() && (what & SwooleG.trace_flags)) {                                    \
254         size_t _sw_error_len =                                                                                         \
255             sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s(:%d): " str, __SW_FUNC__, __LINE__, ##__VA_ARGS__);           \
256         sw_logger()->put(SW_LOG_TRACE, sw_error, _sw_error_len);                                                       \
257     }
258 #else
259 #define swoole_trace_log(what, str, ...)
260 #endif
261 
262 #define swoole_trace(str, ...) swoole_trace_log(SW_TRACE_NORMAL, str, ##__VA_ARGS__)
263