1 /*
2 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3 */
4
5 #include <stdarg.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #include "ulog/ulog.h"
10 #include "aos/kernel.h"
11 #include "ulog_api.h"
12 #include "ulog_ring_fifo.h"
13 #include "aos/errno.h"
14 static char serverity_name[LOG_NONE] = { 'V', 'A', 'F', 'E', 'W', 'T', 'I', 'D' };
15
16 #define UNKNOWN_BUF ""
17
18 void (*aos_cust_output_func)(const char *fmt, ...) = NULL;
19
ulog_vprintf(const char * vformat,va_list varg)20 int ulog_vprintf(const char *vformat, va_list varg)
21 {
22 int i=0;
23 int out_int;
24 int *out_n;
25 unsigned int out_hex_int;
26 unsigned int out_unsigned_int;
27 char out_char=NULL;
28 char *out_string=NULL;
29 char int_to_string[20];
30 double out_f;
31 double out_e;
32 double out_a;
33 unsigned int out_o;
34 unsigned int out_p;
35 int k=0;
36 char number_array[6];
37 int count=0;
38
39 for (i = 0; vformat[i] != '\0';) {
40 if (vformat[i] == '%') {
41 i = i + 1;
42 while (vformat[i] == '0'|| vformat[i] == '1'|| vformat[i] == '2'|| vformat[i] == '3'
43 || vformat[i] == '4' || vformat[i] == '5' || vformat[i] == '6' ||vformat[i] == '7'
44 || vformat[i] == '8' || vformat[i] == '9' || vformat[i] == '$' ||vformat[i] == '*'
45 || vformat[i] == '.') {
46 if (vformat[i] == '%') {
47 break;
48 } else {
49 number_array[k++] = vformat[i];
50 i = i + 1;
51 }
52 }
53 //number=findNumber(number_array);
54 //
55 if (vformat[i] == 'd') {
56 out_int = va_arg(varg, int);
57 sprintf(int_to_string, "%d", out_int);
58 count = count + strlen(int_to_string);
59 aos_cust_output_func("%d",out_int);
60 i = i + 1;
61 } else if (vformat[i] == 'i') {
62 out_int = va_arg(varg, int);
63 sprintf(int_to_string, "%i", out_int);
64 count = count + strlen(int_to_string);
65 aos_cust_output_func("%i", out_int);
66 i = i + 1;
67 } else if (vformat[i] == 's') {
68 out_string = va_arg(varg, char*);
69 count = count+strlen(out_string);
70 aos_cust_output_func("%s", out_string);
71 i = i + 1;
72 } else if (vformat[i] == 'c') {
73 out_char = va_arg(varg, int);
74 count++;
75 aos_cust_output_func("%c", out_char);
76 i = i + 1;
77 } else if (vformat[i] == 'x') {
78 out_hex_int = va_arg(varg, int);
79 sprintf(int_to_string, "%x", out_hex_int);
80 count = count + strlen(int_to_string);
81 aos_cust_output_func("%x", out_hex_int);
82 i = i + 1;
83 } else if (vformat[i] == 'X') {
84 out_hex_int = va_arg(varg, int);
85 sprintf(int_to_string, "%X", out_hex_int);
86 count= count + strlen(int_to_string);
87 aos_cust_output_func("%X", out_hex_int);
88 i = i + 1;
89 } else if (vformat[i]=='f') {
90 out_f = va_arg(varg, double);
91 sprintf(int_to_string, "%f", out_f);
92 count = count + strlen(int_to_string);
93 aos_cust_output_func("%f", out_f);
94 i = i + 1;
95 } else if (vformat[i] == 'u') {
96 out_unsigned_int = va_arg(varg, int);
97 sprintf(int_to_string, "%u", out_unsigned_int);
98 count = count + strlen(int_to_string);
99 aos_cust_output_func("%u", out_unsigned_int);
100 i=i+1;
101 } else if (vformat[i]=='h') {
102 if (vformat[i+1] == 'n') {
103 out_n = (int *)va_arg(varg, int*);
104 //*out_n=count;
105 i = i + 2;
106 } else {
107 count++;
108 aos_cust_output_func("%c", vformat[i]);
109 i = i + 1;
110 }
111 } else if (vformat[i]=='e') {
112 out_e = va_arg(varg, double);
113 sprintf(int_to_string, "%e", out_e);
114 count = count + strlen(int_to_string);
115 aos_cust_output_func("%e", out_e);
116 i = i + 1;
117 } else if (vformat[i] == 'o') {
118 out_o = va_arg(varg, unsigned int);
119 sprintf(int_to_string, "%o", out_o);
120 count = count + strlen(int_to_string);
121 aos_cust_output_func("%o", out_o);
122 i = i + 1;
123 } else if (vformat[i]=='p') {
124 out_p = va_arg(varg, unsigned int);
125 sprintf(int_to_string, "%p", (void *)out_p);
126 count = count + strlen(int_to_string);
127 aos_cust_output_func("%p", (void *)out_p);
128 i = i + 1;
129 } else if (vformat[i] == 'a') {
130 out_a = va_arg(varg,double);
131 sprintf(int_to_string, "%a", out_a);
132 count = count + strlen(int_to_string);
133 aos_cust_output_func("%a", out_a);
134 i = i + 1;
135 } else if (vformat[i] == 'n') {
136 out_n=(int *)va_arg(varg,int*);
137 //*out_n=count; //uncomment this for test1 and test2
138 i=i+1;
139 } else if (vformat[i] == '%') {
140 count++;
141 aos_cust_output_func("%c", vformat[i]);
142 i = i + 1;
143 } else {
144 count++;
145 i++;
146 }
147 } else {
148 count++;
149 aos_cust_output_func("%c", vformat[i]);
150 i++;
151 }
152 }
153
154 return 0;
155
156 }
157
158 /* stop filter, any level <= stop_filter_level(value >= this value) will be abonded */
159 static uint8_t stop_filter_level[ulog_session_size] = {
160 STOP_FILTER_DEFAULT,
161
162 #if ULOG_POP_CLOUD_ENABLE
163 STOP_FILTER_CLOUD,
164 #endif
165
166 #if ULOG_POP_FS_ENABLE
167 STOP_FILTER_FS,
168 #endif
169
170 #if ULOG_POP_UDP_ENABLE
171 STOP_FILTER_UDP,
172 #endif
173
174 };
175
176 static uint8_t push_stop_filter_level = LOG_EMERG;
177
178
179 /* Prefix <248>~<255> */
180 /* using type char instead of int8_t which align with the prototype of string operation function */
181
182
183 static char ulog_buf[ULOG_SIZE + 1];
184
185 /*check whether session can pop log*/
check_pass_pop_out(const ulog_session_type_t session,const uint8_t level)186 bool check_pass_pop_out(const ulog_session_type_t session, const uint8_t level)
187 {
188 return (stop_filter_level[session]>level);
189 }
190
191 /*获取日志停止输出的level*/
ulog_stop_filter_level(const ulog_session_type_t session)192 uint8_t ulog_stop_filter_level(const ulog_session_type_t session)
193 {
194 return stop_filter_level[session];
195 }
196
197 /*设置本地终端日志输出level*/
aos_set_log_level(aos_log_level_t log_level)198 int aos_set_log_level(aos_log_level_t log_level)
199 {
200 int rc = -EINVAL;
201
202 if(aos_ulog_init) {
203 if (log_level <= AOS_LL_DEBUG) {
204 on_filter_level_changes(ulog_session_std, log_level + 1);
205 rc = 0;
206 }
207 }
208 return rc;
209 }
210
211 /*设置输出到云端日志level*/
212 #if ULOG_POP_CLOUD_ENABLE
aos_set_popcloud_log_level(aos_log_level_t log_level)213 int aos_set_popcloud_log_level(aos_log_level_t log_level)
214 {
215 int rc = -EINVAL;
216
217 if (aos_ulog_init) {
218 if (log_level <= AOS_LL_DEBUG) {
219 on_filter_level_changes(ulog_session_cloud, log_level + 1);
220 rc = 0;
221 }
222 }
223 return rc;
224 }
225 #endif
226
227 /*设置输出到本地文件系统日志level*/
228 #if ULOG_POP_FS_ENABLE
aos_set_popfs_log_level(aos_log_level_t log_level)229 int aos_set_popfs_log_level(aos_log_level_t log_level)
230 {
231 int rc = -EINVAL;
232
233 if (aos_ulog_init) {
234 if (log_level <= AOS_LL_DEBUG) {
235 on_filter_level_changes(ulog_session_file, log_level + 1);
236 rc = 0;
237 }
238 }
239 return rc;
240 }
241 #endif
242
243 /*设置输出到syslog 服务器到日志等级*/
244 #if ULOG_POP_UDP_ENABLE
aos_set_popudp_log_level(aos_log_level_t log_level)245 int aos_set_popudp_log_level(aos_log_level_t log_level)
246 {
247 int rc = -EINVAL;
248
249 if (aos_ulog_init) {
250 if (log_level <= AOS_LL_DEBUG) {
251 on_filter_level_changes(ulog_session_udp, log_level + 1);
252 rc = 0;
253 }
254 }
255 return rc;
256 }
257 #endif
258
aos_log_hexdump(const char * tag,char * buffer,int len)259 int aos_log_hexdump(const char *tag, char *buffer, int len)
260 {
261 int i;
262
263 if (aos_ulog_init == false) {
264 return -1;
265 }
266
267 aos_cust_output_func("[%s]\n", tag);
268 aos_cust_output_func("0x0000: ");
269 for (i = 0; i < len; i++) {
270 aos_cust_output_func("0x%02x ", buffer[i]);
271
272 if (i % 8 == 7) {
273 aos_cust_output_func("\n");
274 aos_cust_output_func("0x%04x: ", i + 1);
275 }
276 }
277
278 aos_cust_output_func("\n");
279 return 0;
280 }
281
aos_set_log_output(void (* output_func)(const char * fmt,...))282 int aos_set_log_output(void (*output_func)(const char* fmt, ...))
283 {
284 if (NULL == output_func) {
285 return -1;
286 }
287
288 aos_cust_output_func = output_func;
289 return 0;
290 }
291
get_sync_stop_level()292 char* get_sync_stop_level()
293 {
294 static char buf[32];
295 #ifdef CONFIG_LOGMACRO_SILENT
296 return "NDEBUG mode active";
297 #else
298 if (stop_filter_level[ulog_session_std] == LOG_NONE) {
299 return "all log recorded";
300 } else if (stop_filter_level[ulog_session_std] == LOG_EMERG) {
301 return "all log stop";
302 } else {
303 snprintf(buf, 24, "current log level %c",serverity_name[stop_filter_level[ulog_session_std]-1]);
304 return buf;
305 }
306 #endif
307 }
308
309 #if SYNC_DETAIL_COLOR
310 /*
311 * color def.
312 * see http://stackoverflow.com/questions/3585846/color-text-in-terminal-applications-in-unix
313 */
314 #define COL_DEF "\x1B[0m" /* white */
315 #define COL_RED "\x1B[31m" /* red */
316 #define COL_GRE "\x1B[32m" /* green */
317 #define COL_BLU "\x1B[34m" /* blue */
318 #define COL_YEL "\x1B[33m" /* yellow */
319 #define COL_WHE "\x1B[37m" /* white */
320 #define COL_CYN "\x1B[36m"
321 #define COL_MAG "\x1B[35m"
322
323 static char log_col_list[LOG_NONE][12] = {
324 COL_DEF, COL_RED, COL_RED, COL_RED, COL_BLU, COL_GRE, COL_GRE, COL_WHE
325 };
log_col_def(const unsigned char level)326 static char* log_col_def(const unsigned char level)
327 {
328 if(level<LOG_NONE) {
329 return log_col_list[level];
330 } else {
331 return log_col_list[0];
332 }
333 }
334 #else
335 #define log_col_def(x) ""
336 #endif
337
338 #ifdef ULOG_CONFIG_ASYNC
339 static uint8_t get_lowest_level(const ulog_session_type_t start);
340 #endif
341
ulog(const unsigned char s,const char * mod,const char * f,const unsigned long l,const char * fmt,...)342 int ulog(const unsigned char s, const char *mod, const char *f, const unsigned long l, const char *fmt, ...)
343 {
344 int rc = -1;
345 if (aos_ulog_init &&
346 (s < push_stop_filter_level) ) {
347 char log_time[24];
348 if (log_get_mutex()) {
349 const char* rpt_mod = NULL;
350 if ((mod == NULL) || (0 == strlen(mod))) {
351 rpt_mod = UNKNOWN_BUF;
352 } else {
353 rpt_mod = mod;
354 }
355 #if ULOG_CONFIG_ASYNC
356 uint8_t facility = FACILITY_NORMAL_LOG;
357 if (strlen(rpt_mod) == 0 || 0 == strncmp("MQTT", rpt_mod, strlen("MQTT"))) {
358 facility = FACILITY_NORMAL_LOG_NO_POP_CLOUD;
359 }
360
361 snprintf(ulog_buf,ULOG_HEADER_TYPE_LEN+1,"<%03d>",s+(facility&0xF8));
362
363 #if SYNC_LOG_DETAILS
364 snprintf(&ulog_buf[ULOG_HEADER_TYPE_LEN], ULOG_SIZE-ULOG_HEADER_TYPE_LEN, "%s[%s]<%c>%s %s[%d]: ",
365 log_col_def(s),
366 ulog_format_time(log_time, 24), serverity_name[s], rpt_mod,
367 trim_file_path(f),
368 (int)l);
369 #else /* !SYNC_LOG_DETAILS */
370 snprintf(&ulog_buf[ULOG_HEADER_TYPE_LEN], ULOG_SIZE-ULOG_HEADER_TYPE_LEN, "[%s]<%c>%s ",
371 ulog_format_time(log_time, 24), serverity_name[s], rpt_mod);
372 #endif
373
374 va_list args;
375 va_start(args, fmt);
376 rc = vsnprintf(&ulog_buf[strlen(ulog_buf)], ULOG_SIZE-strlen(ulog_buf), fmt, args);
377 va_end(args);
378 rc = rc<ULOG_SIZE-1?rc:ULOG_SIZE-1;
379
380 bool skip_session_std = false;
381 #if !LOG_DIR_ASYNC
382 if(s < stop_filter_level[ulog_session_std]) {
383 skip_session_std = true;
384 puts(&ulog_buf[LOG_PREFIX_LEN]);
385 }
386 #endif
387 if(!skip_session_std || (s<get_lowest_level(ulog_session_std))) {
388 uring_fifo_push_s(ulog_buf, strlen(ulog_buf)+1);
389 }
390
391 #else /* !ULOG_CONFIG_ASYNC */
392
393 #if SYNC_LOG_DETAILS
394 aos_cust_output_func("%s[%s]<%c>%s %s[%d]: ",
395 log_col_def(s),
396 ulog_format_time(log_time, 24), serverity_name[s], rpt_mod,
397 trim_file_path(f),
398 (int)l);
399 #else /* !SYNC_LOG_DETAILS */
400 rc = snprintf(ulog_buf, ULOG_SIZE,
401 "[%s]<%c>%s ", ulog_format_time(log_time, 24), serverity_name[s], rpt_mod);
402
403 #endif /* SYNC_LOG_DETAILS */
404
405 va_list args;
406 va_start(args, fmt);
407 rc = vsnprintf(&ulog_buf[strlen(ulog_buf)], ULOG_SIZE-strlen(ulog_buf), fmt, args);
408 va_end(args);
409 fflush(stdout);
410 aos_cust_output_func(ulog_buf);
411
412 #endif /* if def ULOG_CONFIG_ASYNC */
413 log_release_mutex();
414 }
415 }
416 return rc;
417 }
418
419 /*用于loglevel 命令行处理*/
on_sync_filter_level_change(const ulog_session_type_t session,const char level)420 void on_sync_filter_level_change(const ulog_session_type_t session, const char level)
421 {
422 if ('N' == level) {
423 on_filter_level_changes(session, LOG_EMERG);
424 } else {
425 int8_t i = 0;
426 for (; i < LOG_NONE; i++) {
427 if (serverity_name[i] == level) {
428 on_filter_level_changes(session, i+1);
429 break;
430 }
431 }
432 }
433 }
434
on_filter_level_changes(const ulog_session_type_t session,const uint8_t level)435 void on_filter_level_changes(const ulog_session_type_t session, const uint8_t level)
436 {
437 bool next_handle = true;
438 uint8_t i = 0;
439
440 if (session == ulog_session_size) {/* only happen on init, get the initial push level */
441 push_stop_filter_level = LOG_EMERG;
442 } else if (session < ulog_session_size && level <= LOG_NONE) {
443 stop_filter_level[session] = level;
444
445 /* suppose we use update session sf(stop filter) as push filter, this value will be updated below */
446 push_stop_filter_level = stop_filter_level[session];
447 } else {
448 next_handle = false;
449 }
450 if (next_handle) {
451 /*遍历所有终端的 filter level , push pop filter 选择最低的一个,保证每一条日志都能吐出来*/
452 for (; i < ulog_session_size; i++) {
453 if (push_stop_filter_level < stop_filter_level[i]) {
454 push_stop_filter_level = stop_filter_level[i];
455 }
456 }
457 }
458 }
459
460 #ifdef ULOG_CONFIG_ASYNC
get_lowest_level(const ulog_session_type_t start)461 static uint8_t get_lowest_level(const ulog_session_type_t start)
462 {
463 uint8_t i = start+1;
464 uint8_t lowest_level = LOG_EMERG;
465 for(; i<ulog_session_size; i++) {
466 if(lowest_level<stop_filter_level[i]) {
467 lowest_level = stop_filter_level[i];
468 }
469 }
470 return lowest_level;
471 }
472 #endif
473
on_filter_change(const ulog_session_type_t session,const char level)474 void on_filter_change(const ulog_session_type_t session, const char level)
475 {
476 if(session<ulog_session_size && level<=LOG_NONE) {
477 on_filter_level_changes(session, level);
478 }
479 }
480
481