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