xref: /nrf52832-nimble/rt-thread/components/utilities/ulog/ulog.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2018-08-25     armink       the first version
9*10465441SEvalZero  */
10*10465441SEvalZero 
11*10465441SEvalZero #include <stdarg.h>
12*10465441SEvalZero #include "ulog.h"
13*10465441SEvalZero #include "rthw.h"
14*10465441SEvalZero 
15*10465441SEvalZero #ifdef ULOG_USING_SYSLOG
16*10465441SEvalZero #include <syslog.h>
17*10465441SEvalZero #endif
18*10465441SEvalZero 
19*10465441SEvalZero #ifdef ULOG_OUTPUT_FLOAT
20*10465441SEvalZero #include <stdio.h>
21*10465441SEvalZero #endif
22*10465441SEvalZero 
23*10465441SEvalZero #ifdef ULOG_TIME_USING_TIMESTAMP
24*10465441SEvalZero #include <sys/time.h>
25*10465441SEvalZero #endif
26*10465441SEvalZero 
27*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
28*10465441SEvalZero #include <rtdevice.h>
29*10465441SEvalZero #endif
30*10465441SEvalZero 
31*10465441SEvalZero #ifdef RT_USING_ULOG
32*10465441SEvalZero 
33*10465441SEvalZero /* the number which is max stored line logs */
34*10465441SEvalZero #ifndef ULOG_ASYNC_OUTPUT_STORE_LINES
35*10465441SEvalZero #define ULOG_ASYNC_OUTPUT_STORE_LINES  (ULOG_ASYNC_OUTPUT_BUF_SIZE * 3 / 2 / ULOG_LINE_BUF_SIZE)
36*10465441SEvalZero #endif
37*10465441SEvalZero 
38*10465441SEvalZero #ifdef ULOG_USING_COLOR
39*10465441SEvalZero /**
40*10465441SEvalZero  * CSI(Control Sequence Introducer/Initiator) sign
41*10465441SEvalZero  * more information on https://en.wikipedia.org/wiki/ANSI_escape_code
42*10465441SEvalZero  */
43*10465441SEvalZero #define CSI_START                      "\033["
44*10465441SEvalZero #define CSI_END                        "\033[0m"
45*10465441SEvalZero /* output log front color */
46*10465441SEvalZero #define F_BLACK                        "30m"
47*10465441SEvalZero #define F_RED                          "31m"
48*10465441SEvalZero #define F_GREEN                        "32m"
49*10465441SEvalZero #define F_YELLOW                       "33m"
50*10465441SEvalZero #define F_BLUE                         "34m"
51*10465441SEvalZero #define F_MAGENTA                      "35m"
52*10465441SEvalZero #define F_CYAN                         "36m"
53*10465441SEvalZero #define F_WHITE                        "37m"
54*10465441SEvalZero 
55*10465441SEvalZero /* output log default color definition */
56*10465441SEvalZero #ifndef ULOG_COLOR_DEBUG
57*10465441SEvalZero #define ULOG_COLOR_DEBUG               NULL
58*10465441SEvalZero #endif
59*10465441SEvalZero #ifndef ULOG_COLOR_INFO
60*10465441SEvalZero #define ULOG_COLOR_INFO                (F_GREEN)
61*10465441SEvalZero #endif
62*10465441SEvalZero #ifndef ULOG_COLOR_WARN
63*10465441SEvalZero #define ULOG_COLOR_WARN                (F_YELLOW)
64*10465441SEvalZero #endif
65*10465441SEvalZero #ifndef ULOG_COLOR_ERROR
66*10465441SEvalZero #define ULOG_COLOR_ERROR               (F_RED)
67*10465441SEvalZero #endif
68*10465441SEvalZero #ifndef ULOG_COLOR_ASSERT
69*10465441SEvalZero #define ULOG_COLOR_ASSERT              (F_MAGENTA)
70*10465441SEvalZero #endif
71*10465441SEvalZero #endif /* ULOG_USING_COLOR */
72*10465441SEvalZero 
73*10465441SEvalZero #if ULOG_LINE_BUF_SIZE < 80
74*10465441SEvalZero #error "the log line buffer size must more than 80"
75*10465441SEvalZero #endif
76*10465441SEvalZero 
77*10465441SEvalZero struct rt_ulog
78*10465441SEvalZero {
79*10465441SEvalZero     rt_bool_t init_ok;
80*10465441SEvalZero     struct rt_mutex output_locker;
81*10465441SEvalZero     /* all backends */
82*10465441SEvalZero     rt_slist_t backend_list;
83*10465441SEvalZero     /* the thread log's line buffer */
84*10465441SEvalZero     char log_buf_th[ULOG_LINE_BUF_SIZE];
85*10465441SEvalZero 
86*10465441SEvalZero #ifdef ULOG_USING_ISR_LOG
87*10465441SEvalZero     /* the ISR log's line buffer */
88*10465441SEvalZero     rt_base_t output_locker_isr_lvl;
89*10465441SEvalZero     char log_buf_isr[ULOG_LINE_BUF_SIZE];
90*10465441SEvalZero #endif /* ULOG_USING_ISR_LOG */
91*10465441SEvalZero 
92*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
93*10465441SEvalZero     rt_rbb_t async_rbb;
94*10465441SEvalZero     rt_thread_t async_th;
95*10465441SEvalZero     struct rt_semaphore async_notice;
96*10465441SEvalZero #endif
97*10465441SEvalZero 
98*10465441SEvalZero #ifdef ULOG_USING_FILTER
99*10465441SEvalZero     struct
100*10465441SEvalZero     {
101*10465441SEvalZero         /* all tag's level filter */
102*10465441SEvalZero         rt_slist_t tag_lvl_list;
103*10465441SEvalZero         /* global filter level, tag and keyword */
104*10465441SEvalZero         rt_uint32_t level;
105*10465441SEvalZero         char tag[ULOG_FILTER_TAG_MAX_LEN + 1];
106*10465441SEvalZero         char keyword[ULOG_FILTER_KW_MAX_LEN + 1];
107*10465441SEvalZero     } filter;
108*10465441SEvalZero #endif /* ULOG_USING_FILTER */
109*10465441SEvalZero };
110*10465441SEvalZero 
111*10465441SEvalZero /* level output info */
112*10465441SEvalZero static const char * const level_output_info[] =
113*10465441SEvalZero {
114*10465441SEvalZero         "A/",
115*10465441SEvalZero         NULL,
116*10465441SEvalZero         NULL,
117*10465441SEvalZero         "E/",
118*10465441SEvalZero         "W/",
119*10465441SEvalZero         NULL,
120*10465441SEvalZero         "I/",
121*10465441SEvalZero         "D/",
122*10465441SEvalZero };
123*10465441SEvalZero 
124*10465441SEvalZero #ifdef ULOG_USING_COLOR
125*10465441SEvalZero /* color output info */
126*10465441SEvalZero static const char * const color_output_info[] =
127*10465441SEvalZero {
128*10465441SEvalZero         ULOG_COLOR_ASSERT,
129*10465441SEvalZero         NULL,
130*10465441SEvalZero         NULL,
131*10465441SEvalZero         ULOG_COLOR_ERROR,
132*10465441SEvalZero         ULOG_COLOR_WARN,
133*10465441SEvalZero         NULL,
134*10465441SEvalZero         ULOG_COLOR_INFO,
135*10465441SEvalZero         ULOG_COLOR_DEBUG,
136*10465441SEvalZero };
137*10465441SEvalZero #endif /* ULOG_USING_COLOR */
138*10465441SEvalZero 
139*10465441SEvalZero /* ulog local object */
140*10465441SEvalZero static struct rt_ulog ulog = { 0 };
141*10465441SEvalZero 
ulog_strcpy(size_t cur_len,char * dst,const char * src)142*10465441SEvalZero size_t ulog_strcpy(size_t cur_len, char *dst, const char *src)
143*10465441SEvalZero {
144*10465441SEvalZero     const char *src_old = src;
145*10465441SEvalZero 
146*10465441SEvalZero     RT_ASSERT(dst);
147*10465441SEvalZero     RT_ASSERT(src);
148*10465441SEvalZero 
149*10465441SEvalZero     while (*src != 0)
150*10465441SEvalZero     {
151*10465441SEvalZero         /* make sure destination has enough space */
152*10465441SEvalZero         if (cur_len++ < ULOG_LINE_BUF_SIZE)
153*10465441SEvalZero         {
154*10465441SEvalZero             *dst++ = *src++;
155*10465441SEvalZero         }
156*10465441SEvalZero         else
157*10465441SEvalZero         {
158*10465441SEvalZero             break;
159*10465441SEvalZero         }
160*10465441SEvalZero     }
161*10465441SEvalZero     return src - src_old;
162*10465441SEvalZero }
163*10465441SEvalZero 
ulog_ultoa(char * s,unsigned long int n)164*10465441SEvalZero size_t ulog_ultoa(char *s, unsigned long int n)
165*10465441SEvalZero {
166*10465441SEvalZero     size_t i = 0, j = 0, len = 0;
167*10465441SEvalZero     char swap;
168*10465441SEvalZero 
169*10465441SEvalZero     do
170*10465441SEvalZero     {
171*10465441SEvalZero         s[len++] = n % 10 + '0';
172*10465441SEvalZero     } while (n /= 10);
173*10465441SEvalZero     s[len] = '\0';
174*10465441SEvalZero     /* reverse string */
175*10465441SEvalZero     for (i = 0, j = len - 1; i < j; ++i, --j)
176*10465441SEvalZero     {
177*10465441SEvalZero         swap = s[i];
178*10465441SEvalZero         s[i] = s[j];
179*10465441SEvalZero         s[j] = swap;
180*10465441SEvalZero     }
181*10465441SEvalZero     return len;
182*10465441SEvalZero }
183*10465441SEvalZero 
output_unlock(void)184*10465441SEvalZero static void output_unlock(void)
185*10465441SEvalZero {
186*10465441SEvalZero     /* is in thread context */
187*10465441SEvalZero     if (rt_interrupt_get_nest() == 0)
188*10465441SEvalZero     {
189*10465441SEvalZero         rt_mutex_release(&ulog.output_locker);
190*10465441SEvalZero     }
191*10465441SEvalZero     else
192*10465441SEvalZero     {
193*10465441SEvalZero #ifdef ULOG_USING_ISR_LOG
194*10465441SEvalZero         rt_hw_interrupt_enable(ulog.output_locker_isr_lvl);
195*10465441SEvalZero #endif
196*10465441SEvalZero     }
197*10465441SEvalZero }
198*10465441SEvalZero 
output_lock(void)199*10465441SEvalZero static void output_lock(void)
200*10465441SEvalZero {
201*10465441SEvalZero     /* is in thread context */
202*10465441SEvalZero     if (rt_interrupt_get_nest() == 0)
203*10465441SEvalZero     {
204*10465441SEvalZero         rt_mutex_take(&ulog.output_locker, RT_WAITING_FOREVER);
205*10465441SEvalZero     }
206*10465441SEvalZero     else
207*10465441SEvalZero     {
208*10465441SEvalZero #ifdef ULOG_USING_ISR_LOG
209*10465441SEvalZero         ulog.output_locker_isr_lvl = rt_hw_interrupt_disable();
210*10465441SEvalZero #endif
211*10465441SEvalZero     }
212*10465441SEvalZero }
213*10465441SEvalZero 
get_log_buf(void)214*10465441SEvalZero static char *get_log_buf(void)
215*10465441SEvalZero {
216*10465441SEvalZero     /* is in thread context */
217*10465441SEvalZero     if (rt_interrupt_get_nest() == 0)
218*10465441SEvalZero     {
219*10465441SEvalZero         return ulog.log_buf_th;
220*10465441SEvalZero     }
221*10465441SEvalZero     else
222*10465441SEvalZero     {
223*10465441SEvalZero #ifdef ULOG_USING_ISR_LOG
224*10465441SEvalZero         return ulog.log_buf_isr;
225*10465441SEvalZero #else
226*10465441SEvalZero         rt_kprintf("Error: Current mode not supported run in ISR. Please enable ULOG_USING_ISR_LOG.\n");
227*10465441SEvalZero         return NULL;
228*10465441SEvalZero #endif
229*10465441SEvalZero     }
230*10465441SEvalZero }
231*10465441SEvalZero 
ulog_formater(char * log_buf,rt_uint32_t level,const char * tag,rt_bool_t newline,const char * format,va_list args)232*10465441SEvalZero RT_WEAK rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *tag, rt_bool_t newline,
233*10465441SEvalZero         const char *format, va_list args)
234*10465441SEvalZero {
235*10465441SEvalZero     /* the caller has locker, so it can use static variable for reduce stack usage */
236*10465441SEvalZero     static rt_size_t log_len, newline_len;
237*10465441SEvalZero     static int fmt_result;
238*10465441SEvalZero 
239*10465441SEvalZero     RT_ASSERT(log_buf);
240*10465441SEvalZero     RT_ASSERT(level <= LOG_LVL_DBG);
241*10465441SEvalZero     RT_ASSERT(tag);
242*10465441SEvalZero     RT_ASSERT(format);
243*10465441SEvalZero 
244*10465441SEvalZero     log_len = 0;
245*10465441SEvalZero     newline_len = rt_strlen(ULOG_NEWLINE_SIGN);
246*10465441SEvalZero 
247*10465441SEvalZero #ifdef ULOG_USING_COLOR
248*10465441SEvalZero     /* add CSI start sign and color info */
249*10465441SEvalZero     if (color_output_info[level])
250*10465441SEvalZero     {
251*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, CSI_START);
252*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, color_output_info[level]);
253*10465441SEvalZero     }
254*10465441SEvalZero #endif /* ULOG_USING_COLOR */
255*10465441SEvalZero 
256*10465441SEvalZero #ifdef ULOG_OUTPUT_TIME
257*10465441SEvalZero     /* add time info */
258*10465441SEvalZero     {
259*10465441SEvalZero #ifdef ULOG_TIME_USING_TIMESTAMP
260*10465441SEvalZero         static time_t now;
261*10465441SEvalZero         static struct tm *tm, tm_tmp;
262*10465441SEvalZero 
263*10465441SEvalZero         now = time(NULL);
264*10465441SEvalZero         tm = gmtime_r(&now, &tm_tmp);
265*10465441SEvalZero 
266*10465441SEvalZero #ifdef RT_USING_SOFT_RTC
267*10465441SEvalZero         rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "%02d-%02d %02d:%02d:%02d.%03d", tm->tm_mon + 1,
268*10465441SEvalZero                 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, rt_tick_get() % 1000);
269*10465441SEvalZero #else
270*10465441SEvalZero         rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "%02d-%02d %02d:%02d:%02d", tm->tm_mon + 1,
271*10465441SEvalZero                 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
272*10465441SEvalZero #endif /* RT_USING_SOFT_RTC */
273*10465441SEvalZero 
274*10465441SEvalZero #else
275*10465441SEvalZero         static rt_size_t tick_len = 0;
276*10465441SEvalZero 
277*10465441SEvalZero         log_buf[log_len] = '[';
278*10465441SEvalZero         tick_len = ulog_ultoa(log_buf + log_len + 1, rt_tick_get());
279*10465441SEvalZero         log_buf[log_len + 1 + tick_len] = ']';
280*10465441SEvalZero         log_buf[log_len + 1 + tick_len + 1] = '\0';
281*10465441SEvalZero #endif /* ULOG_TIME_USING_TIMESTAMP */
282*10465441SEvalZero 
283*10465441SEvalZero         log_len += rt_strlen(log_buf + log_len);
284*10465441SEvalZero     }
285*10465441SEvalZero #endif /* ULOG_OUTPUT_TIME */
286*10465441SEvalZero 
287*10465441SEvalZero #ifdef ULOG_OUTPUT_LEVEL
288*10465441SEvalZero 
289*10465441SEvalZero #ifdef ULOG_OUTPUT_TIME
290*10465441SEvalZero     log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
291*10465441SEvalZero #endif
292*10465441SEvalZero 
293*10465441SEvalZero     /* add level info */
294*10465441SEvalZero     log_len += ulog_strcpy(log_len, log_buf + log_len, level_output_info[level]);
295*10465441SEvalZero #endif /* ULOG_OUTPUT_LEVEL */
296*10465441SEvalZero 
297*10465441SEvalZero #ifdef ULOG_OUTPUT_TAG
298*10465441SEvalZero 
299*10465441SEvalZero #if !defined(ULOG_OUTPUT_LEVEL) && defined(ULOG_OUTPUT_TIME)
300*10465441SEvalZero     log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
301*10465441SEvalZero #endif
302*10465441SEvalZero 
303*10465441SEvalZero     /* add tag info */
304*10465441SEvalZero     log_len += ulog_strcpy(log_len, log_buf + log_len, tag);
305*10465441SEvalZero #endif /* ULOG_OUTPUT_TAG */
306*10465441SEvalZero 
307*10465441SEvalZero #ifdef ULOG_OUTPUT_THREAD_NAME
308*10465441SEvalZero     /* add thread info */
309*10465441SEvalZero     {
310*10465441SEvalZero 
311*10465441SEvalZero #if defined(ULOG_OUTPUT_TIME) || defined(ULOG_OUTPUT_LEVEL) || defined(ULOG_OUTPUT_TAG)
312*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
313*10465441SEvalZero #endif
314*10465441SEvalZero 
315*10465441SEvalZero         /* is not in interrupt context */
316*10465441SEvalZero         if (rt_interrupt_get_nest() == 0)
317*10465441SEvalZero         {
318*10465441SEvalZero             log_len += ulog_strcpy(log_len, log_buf + log_len, rt_thread_self()->name);
319*10465441SEvalZero         }
320*10465441SEvalZero         else
321*10465441SEvalZero         {
322*10465441SEvalZero             log_len += ulog_strcpy(log_len, log_buf + log_len, "ISR");
323*10465441SEvalZero         }
324*10465441SEvalZero     }
325*10465441SEvalZero #endif /* ULOG_OUTPUT_THREAD_NAME */
326*10465441SEvalZero 
327*10465441SEvalZero     log_len += ulog_strcpy(log_len, log_buf + log_len, ": ");
328*10465441SEvalZero 
329*10465441SEvalZero #ifdef ULOG_OUTPUT_FLOAT
330*10465441SEvalZero     fmt_result = vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args);
331*10465441SEvalZero #else
332*10465441SEvalZero     fmt_result = rt_vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args);
333*10465441SEvalZero #endif /* ULOG_OUTPUT_FLOAT */
334*10465441SEvalZero 
335*10465441SEvalZero     /* calculate log length */
336*10465441SEvalZero     if ((log_len + fmt_result <= ULOG_LINE_BUF_SIZE) && (fmt_result > -1))
337*10465441SEvalZero     {
338*10465441SEvalZero         log_len += fmt_result;
339*10465441SEvalZero     }
340*10465441SEvalZero     else
341*10465441SEvalZero     {
342*10465441SEvalZero         /* using max length */
343*10465441SEvalZero         log_len = ULOG_LINE_BUF_SIZE;
344*10465441SEvalZero     }
345*10465441SEvalZero 
346*10465441SEvalZero     /* overflow check and reserve some space for CSI end sign and newline sign */
347*10465441SEvalZero #ifdef ULOG_USING_COLOR
348*10465441SEvalZero     if (log_len + (sizeof(CSI_END) - 1) + newline_len > ULOG_LINE_BUF_SIZE)
349*10465441SEvalZero     {
350*10465441SEvalZero         /* using max length */
351*10465441SEvalZero         log_len = ULOG_LINE_BUF_SIZE;
352*10465441SEvalZero         /* reserve some space for CSI end sign */
353*10465441SEvalZero         log_len -= (sizeof(CSI_END) - 1);
354*10465441SEvalZero #else
355*10465441SEvalZero     if (log_len + newline_len > ULOG_LINE_BUF_SIZE)
356*10465441SEvalZero     {
357*10465441SEvalZero         /* using max length */
358*10465441SEvalZero         log_len = ULOG_LINE_BUF_SIZE;
359*10465441SEvalZero #endif /* ULOG_USING_COLOR */
360*10465441SEvalZero         /* reserve some space for newline sign */
361*10465441SEvalZero         log_len -= newline_len;
362*10465441SEvalZero     }
363*10465441SEvalZero 
364*10465441SEvalZero     /* package newline sign */
365*10465441SEvalZero     if (newline)
366*10465441SEvalZero     {
367*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, ULOG_NEWLINE_SIGN);
368*10465441SEvalZero     }
369*10465441SEvalZero 
370*10465441SEvalZero #ifdef ULOG_USING_COLOR
371*10465441SEvalZero     /* add CSI end sign  */
372*10465441SEvalZero     if (color_output_info[level])
373*10465441SEvalZero     {
374*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, CSI_END);
375*10465441SEvalZero     }
376*10465441SEvalZero #endif /* ULOG_USING_COLOR */
377*10465441SEvalZero 
378*10465441SEvalZero     return log_len;
379*10465441SEvalZero }
380*10465441SEvalZero 
381*10465441SEvalZero void ulog_output_to_all_backend(rt_uint32_t level, const char *tag, rt_bool_t is_raw, const char *log, rt_size_t size)
382*10465441SEvalZero {
383*10465441SEvalZero     rt_slist_t *node;
384*10465441SEvalZero     ulog_backend_t backend;
385*10465441SEvalZero 
386*10465441SEvalZero     if (!ulog.init_ok)
387*10465441SEvalZero         return;
388*10465441SEvalZero 
389*10465441SEvalZero     /* output for all backends */
390*10465441SEvalZero     for (node = rt_slist_first(&ulog.backend_list); node; node = rt_slist_next(node))
391*10465441SEvalZero     {
392*10465441SEvalZero         backend = rt_slist_entry(node, struct ulog_backend, list);
393*10465441SEvalZero #if !defined(ULOG_USING_COLOR) || defined(ULOG_USING_SYSLOG)
394*10465441SEvalZero         backend->output(backend, level, tag, is_raw, log, size);
395*10465441SEvalZero #else
396*10465441SEvalZero         if (backend->support_color)
397*10465441SEvalZero         {
398*10465441SEvalZero             backend->output(backend, level, tag, is_raw, log, size);
399*10465441SEvalZero         }
400*10465441SEvalZero         else
401*10465441SEvalZero         {
402*10465441SEvalZero             /* recalculate the log start address and log size when backend not supported color */
403*10465441SEvalZero             rt_size_t color_info_len = rt_strlen(color_output_info[level]);
404*10465441SEvalZero             if (color_info_len)
405*10465441SEvalZero             {
406*10465441SEvalZero                 rt_size_t color_hdr_len = rt_strlen(CSI_START) + color_info_len;
407*10465441SEvalZero 
408*10465441SEvalZero                 log += color_hdr_len;
409*10465441SEvalZero                 size -= (color_hdr_len + (sizeof(CSI_END) - 1));
410*10465441SEvalZero             }
411*10465441SEvalZero             backend->output(backend, level, tag, is_raw, log, size);
412*10465441SEvalZero         }
413*10465441SEvalZero #endif /* !defined(ULOG_USING_COLOR) || defined(ULOG_USING_SYSLOG) */
414*10465441SEvalZero     }
415*10465441SEvalZero }
416*10465441SEvalZero 
417*10465441SEvalZero static void do_output(rt_uint32_t level, const char *tag, rt_bool_t is_raw, const char *log_buf, rt_size_t log_len)
418*10465441SEvalZero {
419*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
420*10465441SEvalZero     rt_rbb_blk_t log_blk;
421*10465441SEvalZero     ulog_frame_t log_frame;
422*10465441SEvalZero 
423*10465441SEvalZero     /* allocate log frame */
424*10465441SEvalZero     log_blk = rt_rbb_blk_alloc(ulog.async_rbb, RT_ALIGN(sizeof(struct ulog_frame) + log_len, RT_ALIGN_SIZE));
425*10465441SEvalZero     if (log_blk)
426*10465441SEvalZero     {
427*10465441SEvalZero         /* package the log frame */
428*10465441SEvalZero         log_frame = (ulog_frame_t) log_blk->buf;
429*10465441SEvalZero         log_frame->magic = ULOG_FRAME_MAGIC;
430*10465441SEvalZero         log_frame->is_raw = is_raw;
431*10465441SEvalZero         log_frame->level = level;
432*10465441SEvalZero         log_frame->log_len = log_len;
433*10465441SEvalZero         log_frame->tag = tag;
434*10465441SEvalZero         log_frame->log = (const char *)log_blk->buf + sizeof(struct ulog_frame);
435*10465441SEvalZero         /* copy log data */
436*10465441SEvalZero         rt_memcpy(log_blk->buf + sizeof(struct ulog_frame), log_buf, log_len);
437*10465441SEvalZero         /* put the block */
438*10465441SEvalZero         rt_rbb_blk_put(log_blk);
439*10465441SEvalZero         /* send a notice */
440*10465441SEvalZero         rt_sem_release(&ulog.async_notice);
441*10465441SEvalZero     }
442*10465441SEvalZero     else
443*10465441SEvalZero     {
444*10465441SEvalZero         static rt_bool_t already_output = RT_FALSE;
445*10465441SEvalZero         if (already_output == RT_FALSE)
446*10465441SEvalZero         {
447*10465441SEvalZero             rt_kprintf("Warning: There is no enough buffer for saving async log,"
448*10465441SEvalZero                     " please increase the ULOG_ASYNC_OUTPUT_BUF_SIZE option.\n");
449*10465441SEvalZero             already_output = RT_TRUE;
450*10465441SEvalZero         }
451*10465441SEvalZero     }
452*10465441SEvalZero #else
453*10465441SEvalZero     /* is in thread context */
454*10465441SEvalZero     if (rt_interrupt_get_nest() == 0)
455*10465441SEvalZero     {
456*10465441SEvalZero         /* output to all backends */
457*10465441SEvalZero         ulog_output_to_all_backend(level, tag, is_raw, log_buf, log_len);
458*10465441SEvalZero     }
459*10465441SEvalZero     else
460*10465441SEvalZero     {
461*10465441SEvalZero #ifdef ULOG_BACKEND_USING_CONSOLE
462*10465441SEvalZero         /* We can't ensure that all backends support ISR context output.
463*10465441SEvalZero          * So only using rt_kprintf when context is ISR */
464*10465441SEvalZero         extern void ulog_console_backend_output(struct ulog_backend *backend, rt_uint32_t level, const char *tag,
465*10465441SEvalZero                 rt_bool_t is_raw, const char *log, size_t len);
466*10465441SEvalZero         ulog_console_backend_output(NULL, level, tag, is_raw, log_buf, log_len);
467*10465441SEvalZero #endif /* ULOG_BACKEND_USING_CONSOLE */
468*10465441SEvalZero     }
469*10465441SEvalZero #endif /* ULOG_USING_ASYNC_OUTPUT */
470*10465441SEvalZero }
471*10465441SEvalZero 
472*10465441SEvalZero /**
473*10465441SEvalZero  * output the log by variable argument list
474*10465441SEvalZero  *
475*10465441SEvalZero  * @param level level
476*10465441SEvalZero  * @param tag tag
477*10465441SEvalZero  * @param newline has_newline
478*10465441SEvalZero  * @param format output format
479*10465441SEvalZero  * @param args variable argument list
480*10465441SEvalZero  */
481*10465441SEvalZero void ulog_voutput(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, va_list args)
482*10465441SEvalZero {
483*10465441SEvalZero     char *log_buf = NULL;
484*10465441SEvalZero     rt_size_t log_len = 0;
485*10465441SEvalZero 
486*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
487*10465441SEvalZero     RT_ASSERT(level <= LOG_LVL_DBG);
488*10465441SEvalZero #else
489*10465441SEvalZero     RT_ASSERT(LOG_PRI(level) <= LOG_DEBUG);
490*10465441SEvalZero #endif /* ULOG_USING_SYSLOG */
491*10465441SEvalZero 
492*10465441SEvalZero     RT_ASSERT(tag);
493*10465441SEvalZero     RT_ASSERT(format);
494*10465441SEvalZero 
495*10465441SEvalZero     if (!ulog.init_ok)
496*10465441SEvalZero     {
497*10465441SEvalZero         return;
498*10465441SEvalZero     }
499*10465441SEvalZero 
500*10465441SEvalZero #ifdef ULOG_USING_FILTER
501*10465441SEvalZero     /* level filter */
502*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
503*10465441SEvalZero     if (level > ulog.filter.level || level > ulog_tag_lvl_filter_get(tag))
504*10465441SEvalZero     {
505*10465441SEvalZero         return;
506*10465441SEvalZero     }
507*10465441SEvalZero #else
508*10465441SEvalZero     if (((LOG_MASK(LOG_PRI(level)) & ulog.filter.level) == 0)
509*10465441SEvalZero             || ((LOG_MASK(LOG_PRI(level)) & ulog_tag_lvl_filter_get(tag)) == 0))
510*10465441SEvalZero     {
511*10465441SEvalZero         return;
512*10465441SEvalZero     }
513*10465441SEvalZero #endif /* ULOG_USING_SYSLOG */
514*10465441SEvalZero     else if (!rt_strstr(tag, ulog.filter.tag))
515*10465441SEvalZero     {
516*10465441SEvalZero         /* tag filter */
517*10465441SEvalZero         return;
518*10465441SEvalZero     }
519*10465441SEvalZero #endif /* ULOG_USING_FILTER */
520*10465441SEvalZero 
521*10465441SEvalZero     /* get log buffer */
522*10465441SEvalZero     log_buf = get_log_buf();
523*10465441SEvalZero 
524*10465441SEvalZero     /* lock output */
525*10465441SEvalZero     output_lock();
526*10465441SEvalZero 
527*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
528*10465441SEvalZero     log_len = ulog_formater(log_buf, level, tag, newline, format, args);
529*10465441SEvalZero #else
530*10465441SEvalZero     extern rt_size_t syslog_formater(char *log_buf, rt_uint8_t level, const char *tag, rt_bool_t newline, const char *format, va_list args);
531*10465441SEvalZero     log_len = syslog_formater(log_buf, level, tag, newline, format, args);
532*10465441SEvalZero #endif /* ULOG_USING_SYSLOG */
533*10465441SEvalZero 
534*10465441SEvalZero #ifdef ULOG_USING_FILTER
535*10465441SEvalZero     /* keyword filter */
536*10465441SEvalZero     if (ulog.filter.keyword[0] != '\0')
537*10465441SEvalZero     {
538*10465441SEvalZero         /* add string end sign */
539*10465441SEvalZero         log_buf[log_len] = '\0';
540*10465441SEvalZero         /* find the keyword */
541*10465441SEvalZero         if (!rt_strstr(log_buf, ulog.filter.keyword))
542*10465441SEvalZero         {
543*10465441SEvalZero             /* unlock output */
544*10465441SEvalZero             output_unlock();
545*10465441SEvalZero             return;
546*10465441SEvalZero         }
547*10465441SEvalZero     }
548*10465441SEvalZero #endif /* ULOG_USING_FILTER */
549*10465441SEvalZero     /* do log output */
550*10465441SEvalZero     do_output(level, tag, RT_FALSE, log_buf, log_len);
551*10465441SEvalZero 
552*10465441SEvalZero     /* unlock output */
553*10465441SEvalZero     output_unlock();
554*10465441SEvalZero }
555*10465441SEvalZero 
556*10465441SEvalZero /**
557*10465441SEvalZero  * output the log
558*10465441SEvalZero  *
559*10465441SEvalZero  * @param level level
560*10465441SEvalZero  * @param tag tag
561*10465441SEvalZero  * @param newline has newline
562*10465441SEvalZero  * @param format output format
563*10465441SEvalZero  * @param ... args
564*10465441SEvalZero  */
565*10465441SEvalZero void ulog_output(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, ...)
566*10465441SEvalZero {
567*10465441SEvalZero     va_list args;
568*10465441SEvalZero 
569*10465441SEvalZero     /* args point to the first variable parameter */
570*10465441SEvalZero     va_start(args, format);
571*10465441SEvalZero 
572*10465441SEvalZero     ulog_voutput(level, tag, newline, format, args);
573*10465441SEvalZero 
574*10465441SEvalZero     va_end(args);
575*10465441SEvalZero }
576*10465441SEvalZero 
577*10465441SEvalZero /**
578*10465441SEvalZero  * output RAW string format log
579*10465441SEvalZero  *
580*10465441SEvalZero  * @param format output format
581*10465441SEvalZero  * @param ... args
582*10465441SEvalZero  */
583*10465441SEvalZero void ulog_raw(const char *format, ...)
584*10465441SEvalZero {
585*10465441SEvalZero     rt_size_t log_len = 0;
586*10465441SEvalZero     char *log_buf = NULL;
587*10465441SEvalZero     va_list args;
588*10465441SEvalZero     int fmt_result;
589*10465441SEvalZero 
590*10465441SEvalZero     RT_ASSERT(ulog.init_ok);
591*10465441SEvalZero 
592*10465441SEvalZero     /* get log buffer */
593*10465441SEvalZero     log_buf = get_log_buf();
594*10465441SEvalZero 
595*10465441SEvalZero     /* lock output */
596*10465441SEvalZero     output_lock();
597*10465441SEvalZero     /* args point to the first variable parameter */
598*10465441SEvalZero     va_start(args, format);
599*10465441SEvalZero 
600*10465441SEvalZero #ifdef ULOG_OUTPUT_FLOAT
601*10465441SEvalZero     fmt_result = vsnprintf(log_buf, ULOG_LINE_BUF_SIZE, format, args);
602*10465441SEvalZero #else
603*10465441SEvalZero     fmt_result = rt_vsnprintf(log_buf, ULOG_LINE_BUF_SIZE, format, args);
604*10465441SEvalZero #endif /* ULOG_OUTPUT_FLOAT */
605*10465441SEvalZero 
606*10465441SEvalZero     va_end(args);
607*10465441SEvalZero 
608*10465441SEvalZero     /* calculate log length */
609*10465441SEvalZero     if ((fmt_result > -1) && (fmt_result <= ULOG_LINE_BUF_SIZE))
610*10465441SEvalZero     {
611*10465441SEvalZero         log_len = fmt_result;
612*10465441SEvalZero     }
613*10465441SEvalZero     else
614*10465441SEvalZero     {
615*10465441SEvalZero         log_len = ULOG_LINE_BUF_SIZE;
616*10465441SEvalZero     }
617*10465441SEvalZero 
618*10465441SEvalZero     /* do log output */
619*10465441SEvalZero     do_output(LOG_LVL_DBG, NULL, RT_TRUE, log_buf, log_len);
620*10465441SEvalZero 
621*10465441SEvalZero     /* unlock output */
622*10465441SEvalZero     output_unlock();
623*10465441SEvalZero }
624*10465441SEvalZero 
625*10465441SEvalZero /**
626*10465441SEvalZero  * dump the hex format data to log
627*10465441SEvalZero  *
628*10465441SEvalZero  * @param tag name for hex object, it will show on log header
629*10465441SEvalZero  * @param width hex number for every line, such as: 16, 32
630*10465441SEvalZero  * @param buf hex buffer
631*10465441SEvalZero  * @param size buffer size
632*10465441SEvalZero  */
633*10465441SEvalZero void ulog_hexdump(const char *tag, rt_size_t width, rt_uint8_t *buf, rt_size_t size)
634*10465441SEvalZero {
635*10465441SEvalZero #define __is_print(ch)       ((unsigned int)((ch) - ' ') < 127u - ' ')
636*10465441SEvalZero 
637*10465441SEvalZero     rt_size_t i, j;
638*10465441SEvalZero     rt_size_t log_len = 0, name_len = rt_strlen(tag);
639*10465441SEvalZero     char *log_buf = NULL, dump_string[8];
640*10465441SEvalZero     int fmt_result;
641*10465441SEvalZero 
642*10465441SEvalZero     RT_ASSERT(ulog.init_ok);
643*10465441SEvalZero 
644*10465441SEvalZero #ifdef ULOG_USING_FILTER
645*10465441SEvalZero     /* level filter */
646*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
647*10465441SEvalZero     if (LOG_LVL_DBG > ulog.filter.level || LOG_LVL_DBG > ulog_tag_lvl_filter_get(tag))
648*10465441SEvalZero     {
649*10465441SEvalZero         return;
650*10465441SEvalZero     }
651*10465441SEvalZero #else
652*10465441SEvalZero     if ((LOG_MASK(LOG_DEBUG) & ulog.filter.level) == 0)
653*10465441SEvalZero     {
654*10465441SEvalZero         return;
655*10465441SEvalZero     }
656*10465441SEvalZero #endif /* ULOG_USING_SYSLOG */
657*10465441SEvalZero     else if (!rt_strstr(tag, ulog.filter.tag))
658*10465441SEvalZero     {
659*10465441SEvalZero         /* tag filter */
660*10465441SEvalZero         return;
661*10465441SEvalZero     }
662*10465441SEvalZero #endif /* ULOG_USING_FILTER */
663*10465441SEvalZero 
664*10465441SEvalZero     /* get log buffer */
665*10465441SEvalZero     log_buf = get_log_buf();
666*10465441SEvalZero 
667*10465441SEvalZero     /* lock output */
668*10465441SEvalZero     output_lock();
669*10465441SEvalZero 
670*10465441SEvalZero     for (i = 0, log_len = 0; i < size; i += width)
671*10465441SEvalZero     {
672*10465441SEvalZero         /* package header */
673*10465441SEvalZero         if (i == 0)
674*10465441SEvalZero         {
675*10465441SEvalZero             log_len += ulog_strcpy(log_len, log_buf + log_len, "D/HEX ");
676*10465441SEvalZero             log_len += ulog_strcpy(log_len, log_buf + log_len, tag);
677*10465441SEvalZero             log_len += ulog_strcpy(log_len, log_buf + log_len, ": ");
678*10465441SEvalZero         }
679*10465441SEvalZero         else
680*10465441SEvalZero         {
681*10465441SEvalZero             log_len = 6 + name_len + 2;
682*10465441SEvalZero             rt_memset(log_buf, ' ', log_len);
683*10465441SEvalZero         }
684*10465441SEvalZero         fmt_result = rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE, "%04X-%04X: ", i, i + width);
685*10465441SEvalZero         /* calculate log length */
686*10465441SEvalZero         if ((fmt_result > -1) && (fmt_result <= ULOG_LINE_BUF_SIZE))
687*10465441SEvalZero         {
688*10465441SEvalZero             log_len += fmt_result;
689*10465441SEvalZero         }
690*10465441SEvalZero         else
691*10465441SEvalZero         {
692*10465441SEvalZero             log_len = ULOG_LINE_BUF_SIZE;
693*10465441SEvalZero         }
694*10465441SEvalZero         /* dump hex */
695*10465441SEvalZero         for (j = 0; j < width; j++)
696*10465441SEvalZero         {
697*10465441SEvalZero             if (i + j < size)
698*10465441SEvalZero             {
699*10465441SEvalZero                 rt_snprintf(dump_string, sizeof(dump_string), "%02X ", buf[i + j]);
700*10465441SEvalZero             }
701*10465441SEvalZero             else
702*10465441SEvalZero             {
703*10465441SEvalZero                 rt_strncpy(dump_string, "   ", sizeof(dump_string));
704*10465441SEvalZero             }
705*10465441SEvalZero             log_len += ulog_strcpy(log_len, log_buf + log_len, dump_string);
706*10465441SEvalZero             if ((j + 1) % 8 == 0)
707*10465441SEvalZero             {
708*10465441SEvalZero                 log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
709*10465441SEvalZero             }
710*10465441SEvalZero         }
711*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, "  ");
712*10465441SEvalZero         /* dump char for hex */
713*10465441SEvalZero         for (j = 0; j < width; j++)
714*10465441SEvalZero         {
715*10465441SEvalZero             if (i + j < size)
716*10465441SEvalZero             {
717*10465441SEvalZero                 rt_snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
718*10465441SEvalZero                 log_len += ulog_strcpy(log_len, log_buf + log_len, dump_string);
719*10465441SEvalZero             }
720*10465441SEvalZero         }
721*10465441SEvalZero         /* overflow check and reserve some space for newline sign */
722*10465441SEvalZero         if (log_len + rt_strlen(ULOG_NEWLINE_SIGN) > ULOG_LINE_BUF_SIZE)
723*10465441SEvalZero         {
724*10465441SEvalZero             log_len = ULOG_LINE_BUF_SIZE - rt_strlen(ULOG_NEWLINE_SIGN);
725*10465441SEvalZero         }
726*10465441SEvalZero         /* package newline sign */
727*10465441SEvalZero         log_len += ulog_strcpy(log_len, log_buf + log_len, ULOG_NEWLINE_SIGN);
728*10465441SEvalZero         /* do log output */
729*10465441SEvalZero         do_output(LOG_LVL_DBG, NULL, RT_TRUE, log_buf, log_len);
730*10465441SEvalZero     }
731*10465441SEvalZero     /* unlock output */
732*10465441SEvalZero     output_unlock();
733*10465441SEvalZero }
734*10465441SEvalZero 
735*10465441SEvalZero #ifdef ULOG_USING_FILTER
736*10465441SEvalZero /**
737*10465441SEvalZero  * Set the filter's level by different tag.
738*10465441SEvalZero  * The log on this tag which level is less than it will stop output.
739*10465441SEvalZero  *
740*10465441SEvalZero  * example:
741*10465441SEvalZero  *     // the example tag log enter silent mode
742*10465441SEvalZero  *     ulog_set_filter_lvl("example", LOG_FILTER_LVL_SILENT);
743*10465441SEvalZero  *     // the example tag log which level is less than INFO level will stop output
744*10465441SEvalZero  *     ulog_set_filter_lvl("example", LOG_LVL_INFO);
745*10465441SEvalZero  *     // remove example tag's level filter, all level log will resume output
746*10465441SEvalZero  *     ulog_set_filter_lvl("example", LOG_FILTER_LVL_ALL);
747*10465441SEvalZero  *
748*10465441SEvalZero  * @param tag log tag
749*10465441SEvalZero  * @param level The filter level. When the level is LOG_FILTER_LVL_SILENT, the log enter silent mode.
750*10465441SEvalZero  *        When the level is LOG_FILTER_LVL_ALL, it will remove this tag's level filer.
751*10465441SEvalZero  *        Then all level log will resume output.
752*10465441SEvalZero  *
753*10465441SEvalZero  * @return  0 : success
754*10465441SEvalZero  *         -5 : no memory
755*10465441SEvalZero  *         -10: level is out of range
756*10465441SEvalZero  */
757*10465441SEvalZero int ulog_tag_lvl_filter_set(const char *tag, rt_uint32_t level)
758*10465441SEvalZero {
759*10465441SEvalZero     rt_slist_t *node;
760*10465441SEvalZero     ulog_tag_lvl_filter_t tag_lvl = NULL;
761*10465441SEvalZero     int result = RT_EOK;
762*10465441SEvalZero 
763*10465441SEvalZero     if (level > LOG_FILTER_LVL_ALL)
764*10465441SEvalZero         return -RT_EINVAL;
765*10465441SEvalZero 
766*10465441SEvalZero     if (!ulog.init_ok)
767*10465441SEvalZero         return result;
768*10465441SEvalZero 
769*10465441SEvalZero     /* lock output */
770*10465441SEvalZero     output_lock();
771*10465441SEvalZero     /* find the tag in list */
772*10465441SEvalZero     for (node = rt_slist_first(ulog_tag_lvl_list_get()); node; node = rt_slist_next(node))
773*10465441SEvalZero     {
774*10465441SEvalZero         tag_lvl = rt_slist_entry(node, struct ulog_tag_lvl_filter, list);
775*10465441SEvalZero         if (!rt_strncmp(tag_lvl->tag, tag, ULOG_FILTER_TAG_MAX_LEN))
776*10465441SEvalZero         {
777*10465441SEvalZero             break;
778*10465441SEvalZero         }
779*10465441SEvalZero         else
780*10465441SEvalZero         {
781*10465441SEvalZero             tag_lvl = NULL;
782*10465441SEvalZero         }
783*10465441SEvalZero     }
784*10465441SEvalZero     /* find OK */
785*10465441SEvalZero     if (tag_lvl)
786*10465441SEvalZero     {
787*10465441SEvalZero         if (level == LOG_FILTER_LVL_ALL)
788*10465441SEvalZero         {
789*10465441SEvalZero             /* remove current tag's level filter when input level is the lowest level */
790*10465441SEvalZero             rt_slist_remove(ulog_tag_lvl_list_get(), &tag_lvl->list);
791*10465441SEvalZero             rt_free(tag_lvl);
792*10465441SEvalZero         }
793*10465441SEvalZero         else
794*10465441SEvalZero         {
795*10465441SEvalZero             /* update level */
796*10465441SEvalZero             tag_lvl->level = level;
797*10465441SEvalZero         }
798*10465441SEvalZero     }
799*10465441SEvalZero     else
800*10465441SEvalZero     {
801*10465441SEvalZero         /* only add the new tag's level filer when level is not LOG_FILTER_LVL_ALL */
802*10465441SEvalZero         if (level != LOG_FILTER_LVL_ALL)
803*10465441SEvalZero         {
804*10465441SEvalZero             /* new a tag's level filter */
805*10465441SEvalZero             tag_lvl = (ulog_tag_lvl_filter_t)rt_malloc(sizeof(struct ulog_tag_lvl_filter));
806*10465441SEvalZero             if (tag_lvl)
807*10465441SEvalZero             {
808*10465441SEvalZero                 rt_memset(tag_lvl->tag, 0 , sizeof(tag_lvl->tag));
809*10465441SEvalZero                 rt_strncpy(tag_lvl->tag, tag, ULOG_FILTER_TAG_MAX_LEN);
810*10465441SEvalZero                 tag_lvl->level = level;
811*10465441SEvalZero                 rt_slist_append(ulog_tag_lvl_list_get(), &tag_lvl->list);
812*10465441SEvalZero             }
813*10465441SEvalZero             else
814*10465441SEvalZero             {
815*10465441SEvalZero                 result = -RT_ENOMEM;
816*10465441SEvalZero             }
817*10465441SEvalZero         }
818*10465441SEvalZero     }
819*10465441SEvalZero     /* unlock output */
820*10465441SEvalZero     output_unlock();
821*10465441SEvalZero 
822*10465441SEvalZero     return result;
823*10465441SEvalZero }
824*10465441SEvalZero 
825*10465441SEvalZero /**
826*10465441SEvalZero  * get the level on tag's level filer
827*10465441SEvalZero  *
828*10465441SEvalZero  * @param tag log tag
829*10465441SEvalZero  *
830*10465441SEvalZero  * @return It will return the lowest level when tag was not found.
831*10465441SEvalZero  *         Other level will return when tag was found.
832*10465441SEvalZero  */
833*10465441SEvalZero rt_uint32_t ulog_tag_lvl_filter_get(const char *tag)
834*10465441SEvalZero {
835*10465441SEvalZero     rt_slist_t *node;
836*10465441SEvalZero     ulog_tag_lvl_filter_t tag_lvl = NULL;
837*10465441SEvalZero     rt_uint32_t level = LOG_FILTER_LVL_ALL;
838*10465441SEvalZero 
839*10465441SEvalZero     if (!ulog.init_ok)
840*10465441SEvalZero         return level;
841*10465441SEvalZero 
842*10465441SEvalZero     /* lock output */
843*10465441SEvalZero     output_lock();
844*10465441SEvalZero     /* find the tag in list */
845*10465441SEvalZero     for (node = rt_slist_first(ulog_tag_lvl_list_get()); node; node = rt_slist_next(node))
846*10465441SEvalZero     {
847*10465441SEvalZero         tag_lvl = rt_slist_entry(node, struct ulog_tag_lvl_filter, list);
848*10465441SEvalZero         if (!rt_strncmp(tag_lvl->tag, tag, ULOG_FILTER_TAG_MAX_LEN))
849*10465441SEvalZero         {
850*10465441SEvalZero             level = tag_lvl->level;
851*10465441SEvalZero             break;
852*10465441SEvalZero         }
853*10465441SEvalZero     }
854*10465441SEvalZero     /* unlock output */
855*10465441SEvalZero     output_unlock();
856*10465441SEvalZero 
857*10465441SEvalZero     return level;
858*10465441SEvalZero }
859*10465441SEvalZero 
860*10465441SEvalZero /**
861*10465441SEvalZero  * get the tag's level list on filter
862*10465441SEvalZero  *
863*10465441SEvalZero  * @return tag's level list
864*10465441SEvalZero  */
865*10465441SEvalZero rt_slist_t *ulog_tag_lvl_list_get(void)
866*10465441SEvalZero {
867*10465441SEvalZero     return &ulog.filter.tag_lvl_list;
868*10465441SEvalZero }
869*10465441SEvalZero 
870*10465441SEvalZero /**
871*10465441SEvalZero  * set log global filter level
872*10465441SEvalZero  *
873*10465441SEvalZero  * @param level log level: LOG_LVL_ASSERT, LOG_LVL_ERROR, LOG_LVL_WARNING, LOG_LVL_INFO, LOG_LVL_DBG
874*10465441SEvalZero  *              LOG_FILTER_LVL_SILENT: disable all log output, except assert level
875*10465441SEvalZero  *              LOG_FILTER_LVL_ALL: enable all log output
876*10465441SEvalZero  */
877*10465441SEvalZero void ulog_global_filter_lvl_set(rt_uint32_t level)
878*10465441SEvalZero {
879*10465441SEvalZero     RT_ASSERT(level <= LOG_FILTER_LVL_ALL);
880*10465441SEvalZero 
881*10465441SEvalZero     ulog.filter.level = level;
882*10465441SEvalZero }
883*10465441SEvalZero 
884*10465441SEvalZero /**
885*10465441SEvalZero  * get log global filter level
886*10465441SEvalZero  *
887*10465441SEvalZero  * @return log level: LOG_LVL_ASSERT, LOG_LVL_ERROR, LOG_LVL_WARNING, LOG_LVL_INFO, LOG_LVL_DBG
888*10465441SEvalZero  *              LOG_FILTER_LVL_SILENT: disable all log output, except assert level
889*10465441SEvalZero  *              LOG_FILTER_LVL_ALL: enable all log output
890*10465441SEvalZero  */
891*10465441SEvalZero rt_uint32_t ulog_global_filter_lvl_get(void)
892*10465441SEvalZero {
893*10465441SEvalZero     return ulog.filter.level;
894*10465441SEvalZero }
895*10465441SEvalZero 
896*10465441SEvalZero /**
897*10465441SEvalZero  * set log global filter tag
898*10465441SEvalZero  *
899*10465441SEvalZero  * @param tag tag
900*10465441SEvalZero  */
901*10465441SEvalZero void ulog_global_filter_tag_set(const char *tag)
902*10465441SEvalZero {
903*10465441SEvalZero     RT_ASSERT(tag);
904*10465441SEvalZero 
905*10465441SEvalZero     rt_strncpy(ulog.filter.tag, tag, ULOG_FILTER_TAG_MAX_LEN);
906*10465441SEvalZero }
907*10465441SEvalZero 
908*10465441SEvalZero /**
909*10465441SEvalZero  * get log global filter tag
910*10465441SEvalZero  *
911*10465441SEvalZero  * @return tag
912*10465441SEvalZero  */
913*10465441SEvalZero const char *ulog_global_filter_tag_get(void)
914*10465441SEvalZero {
915*10465441SEvalZero     return ulog.filter.tag;
916*10465441SEvalZero }
917*10465441SEvalZero 
918*10465441SEvalZero /**
919*10465441SEvalZero  * set log global filter keyword
920*10465441SEvalZero  *
921*10465441SEvalZero  * @param keyword keyword
922*10465441SEvalZero  */
923*10465441SEvalZero void ulog_global_filter_kw_set(const char *keyword)
924*10465441SEvalZero {
925*10465441SEvalZero     RT_ASSERT(keyword);
926*10465441SEvalZero 
927*10465441SEvalZero     rt_strncpy(ulog.filter.keyword, keyword, ULOG_FILTER_KW_MAX_LEN);
928*10465441SEvalZero }
929*10465441SEvalZero 
930*10465441SEvalZero /**
931*10465441SEvalZero  * get log global filter keyword
932*10465441SEvalZero  *
933*10465441SEvalZero  * @return keyword
934*10465441SEvalZero  */
935*10465441SEvalZero const char *ulog_global_filter_kw_get(void)
936*10465441SEvalZero {
937*10465441SEvalZero     return ulog.filter.keyword;
938*10465441SEvalZero }
939*10465441SEvalZero 
940*10465441SEvalZero #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
941*10465441SEvalZero #include <finsh.h>
942*10465441SEvalZero 
943*10465441SEvalZero static void ulog_tag_lvl(uint8_t argc, char **argv)
944*10465441SEvalZero {
945*10465441SEvalZero     if (argc > 2)
946*10465441SEvalZero     {
947*10465441SEvalZero         if ((atoi(argv[2]) <= LOG_FILTER_LVL_ALL) && (atoi(argv[2]) >= 0))
948*10465441SEvalZero         {
949*10465441SEvalZero             ulog_tag_lvl_filter_set(argv[1], atoi(argv[2]));
950*10465441SEvalZero         }
951*10465441SEvalZero         else
952*10465441SEvalZero         {
953*10465441SEvalZero             rt_kprintf("Please input correct level (0-%d).\n", LOG_FILTER_LVL_ALL);
954*10465441SEvalZero         }
955*10465441SEvalZero     }
956*10465441SEvalZero     else
957*10465441SEvalZero     {
958*10465441SEvalZero         rt_kprintf("Please input: ulog_tag_lvl <tag> <level>.\n");
959*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
960*10465441SEvalZero         rt_kprintf("Assert  : 0\n");
961*10465441SEvalZero         rt_kprintf("Error   : 3\n");
962*10465441SEvalZero         rt_kprintf("Warning : 4\n");
963*10465441SEvalZero         rt_kprintf("Info    : 6\n");
964*10465441SEvalZero         rt_kprintf("Debug   : 7\n");
965*10465441SEvalZero #else
966*10465441SEvalZero         rt_kprintf("EMERG   :   1 (1 << 0)\n");
967*10465441SEvalZero         rt_kprintf("ALERT   :   2 (1 << 1)\n");
968*10465441SEvalZero         rt_kprintf("CRIT    :   4 (1 << 2)\n");
969*10465441SEvalZero         rt_kprintf("ERR     :   8 (1 << 3)\n");
970*10465441SEvalZero         rt_kprintf("WARNING :  16 (1 << 4)\n");
971*10465441SEvalZero         rt_kprintf("NOTICE  :  32 (1 << 5)\n");
972*10465441SEvalZero         rt_kprintf("INFO    :  64 (1 << 6)\n");
973*10465441SEvalZero         rt_kprintf("DEBUG   : 128 (1 << 7)\n");
974*10465441SEvalZero #endif /* ULOG_USING_SYSLOG */
975*10465441SEvalZero     }
976*10465441SEvalZero }
977*10465441SEvalZero MSH_CMD_EXPORT(ulog_tag_lvl, Set ulog filter level by different tag.);
978*10465441SEvalZero 
979*10465441SEvalZero static void ulog_lvl(uint8_t argc, char **argv)
980*10465441SEvalZero {
981*10465441SEvalZero     if (argc > 1)
982*10465441SEvalZero     {
983*10465441SEvalZero         if ((atoi(argv[1]) <= LOG_FILTER_LVL_ALL) && (atoi(argv[1]) >= 0))
984*10465441SEvalZero         {
985*10465441SEvalZero             ulog_global_filter_lvl_set(atoi(argv[1]));
986*10465441SEvalZero         }
987*10465441SEvalZero         else
988*10465441SEvalZero         {
989*10465441SEvalZero             rt_kprintf("Please input correct level (0-%d).\n", LOG_FILTER_LVL_ALL);
990*10465441SEvalZero         }
991*10465441SEvalZero     }
992*10465441SEvalZero     else
993*10465441SEvalZero     {
994*10465441SEvalZero         rt_kprintf("Please input: ulog_lvl <level>.\n");
995*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
996*10465441SEvalZero         rt_kprintf("Assert  : 0\n");
997*10465441SEvalZero         rt_kprintf("Error   : 3\n");
998*10465441SEvalZero         rt_kprintf("Warning : 4\n");
999*10465441SEvalZero         rt_kprintf("Info    : 6\n");
1000*10465441SEvalZero         rt_kprintf("Debug   : 7\n");
1001*10465441SEvalZero #else
1002*10465441SEvalZero         rt_kprintf("EMERG   :   1 (1 << 0)\n");
1003*10465441SEvalZero         rt_kprintf("ALERT   :   2 (1 << 1)\n");
1004*10465441SEvalZero         rt_kprintf("CRIT    :   4 (1 << 2)\n");
1005*10465441SEvalZero         rt_kprintf("ERR     :   8 (1 << 3)\n");
1006*10465441SEvalZero         rt_kprintf("WARNING :  16 (1 << 4)\n");
1007*10465441SEvalZero         rt_kprintf("NOTICE  :  32 (1 << 5)\n");
1008*10465441SEvalZero         rt_kprintf("INFO    :  64 (1 << 6)\n");
1009*10465441SEvalZero         rt_kprintf("DEBUG   : 128 (1 << 7)\n");
1010*10465441SEvalZero #endif /* ULOG_USING_SYSLOG */
1011*10465441SEvalZero     }
1012*10465441SEvalZero }
1013*10465441SEvalZero MSH_CMD_EXPORT(ulog_lvl, Set ulog global filter level.);
1014*10465441SEvalZero 
1015*10465441SEvalZero static void ulog_tag(uint8_t argc, char **argv)
1016*10465441SEvalZero {
1017*10465441SEvalZero     if (argc > 1)
1018*10465441SEvalZero     {
1019*10465441SEvalZero         if (rt_strlen(argv[1]) <= ULOG_FILTER_TAG_MAX_LEN)
1020*10465441SEvalZero         {
1021*10465441SEvalZero             ulog_global_filter_tag_set(argv[1]);
1022*10465441SEvalZero         }
1023*10465441SEvalZero         else
1024*10465441SEvalZero         {
1025*10465441SEvalZero             rt_kprintf("The tag length is too long. Max is %d.\n", ULOG_FILTER_TAG_MAX_LEN);
1026*10465441SEvalZero         }
1027*10465441SEvalZero     }
1028*10465441SEvalZero     else
1029*10465441SEvalZero     {
1030*10465441SEvalZero         ulog_global_filter_tag_set("");
1031*10465441SEvalZero     }
1032*10465441SEvalZero }
1033*10465441SEvalZero MSH_CMD_EXPORT(ulog_tag, Set ulog global filter tag);
1034*10465441SEvalZero 
1035*10465441SEvalZero static void ulog_kw(uint8_t argc, char **argv)
1036*10465441SEvalZero {
1037*10465441SEvalZero     if (argc > 1)
1038*10465441SEvalZero     {
1039*10465441SEvalZero         if (rt_strlen(argv[1]) <= ULOG_FILTER_KW_MAX_LEN)
1040*10465441SEvalZero         {
1041*10465441SEvalZero             ulog_global_filter_kw_set(argv[1]);
1042*10465441SEvalZero         }
1043*10465441SEvalZero         else
1044*10465441SEvalZero         {
1045*10465441SEvalZero             rt_kprintf("The keyword length is too long. Max is %d.\n", ULOG_FILTER_KW_MAX_LEN);
1046*10465441SEvalZero         }
1047*10465441SEvalZero     }
1048*10465441SEvalZero     else
1049*10465441SEvalZero     {
1050*10465441SEvalZero         ulog_global_filter_kw_set("");
1051*10465441SEvalZero     }
1052*10465441SEvalZero }
1053*10465441SEvalZero MSH_CMD_EXPORT(ulog_kw, Set ulog global filter keyword);
1054*10465441SEvalZero 
1055*10465441SEvalZero static void ulog_filter(uint8_t argc, char **argv)
1056*10465441SEvalZero {
1057*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
1058*10465441SEvalZero     const char *lvl_name[] = { "Assert ", "Error  ", "Error  ", "Error  ", "Warning", "Info   ", "Info   ", "Debug  " };
1059*10465441SEvalZero #endif
1060*10465441SEvalZero     const char *tag = ulog_global_filter_tag_get(), *kw = ulog_global_filter_kw_get();
1061*10465441SEvalZero     rt_slist_t *node;
1062*10465441SEvalZero     ulog_tag_lvl_filter_t tag_lvl = NULL;
1063*10465441SEvalZero 
1064*10465441SEvalZero     rt_kprintf("--------------------------------------\n");
1065*10465441SEvalZero     rt_kprintf("ulog global filter:\n");
1066*10465441SEvalZero 
1067*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
1068*10465441SEvalZero     rt_kprintf("level   : %s\n", lvl_name[ulog_global_filter_lvl_get()]);
1069*10465441SEvalZero #else
1070*10465441SEvalZero     rt_kprintf("level   : %d\n", ulog_global_filter_lvl_get());
1071*10465441SEvalZero #endif
1072*10465441SEvalZero 
1073*10465441SEvalZero     rt_kprintf("tag     : %s\n", rt_strlen(tag) == 0 ? "NULL" : tag);
1074*10465441SEvalZero     rt_kprintf("keyword : %s\n", rt_strlen(kw) == 0 ? "NULL" : kw);
1075*10465441SEvalZero 
1076*10465441SEvalZero     rt_kprintf("--------------------------------------\n");
1077*10465441SEvalZero     rt_kprintf("ulog tag's level filter:\n");
1078*10465441SEvalZero     if (rt_slist_isempty(ulog_tag_lvl_list_get()))
1079*10465441SEvalZero     {
1080*10465441SEvalZero         rt_kprintf("settings not found\n");
1081*10465441SEvalZero     }
1082*10465441SEvalZero     else
1083*10465441SEvalZero     {
1084*10465441SEvalZero         /* lock output */
1085*10465441SEvalZero         output_lock();
1086*10465441SEvalZero         /* show the tag level list */
1087*10465441SEvalZero         for (node = rt_slist_first(ulog_tag_lvl_list_get()); node; node = rt_slist_next(node))
1088*10465441SEvalZero         {
1089*10465441SEvalZero             tag_lvl = rt_slist_entry(node, struct ulog_tag_lvl_filter, list);
1090*10465441SEvalZero             rt_kprintf("%-*.s: ", ULOG_FILTER_TAG_MAX_LEN, tag_lvl->tag);
1091*10465441SEvalZero 
1092*10465441SEvalZero #ifndef ULOG_USING_SYSLOG
1093*10465441SEvalZero             rt_kprintf("%s\n", lvl_name[tag_lvl->level]);
1094*10465441SEvalZero #else
1095*10465441SEvalZero             rt_kprintf("%d\n", tag_lvl->level);
1096*10465441SEvalZero #endif
1097*10465441SEvalZero 
1098*10465441SEvalZero         }
1099*10465441SEvalZero         /* unlock output */
1100*10465441SEvalZero         output_unlock();
1101*10465441SEvalZero     }
1102*10465441SEvalZero }
1103*10465441SEvalZero MSH_CMD_EXPORT(ulog_filter, Show ulog filter settings);
1104*10465441SEvalZero #endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
1105*10465441SEvalZero #endif /* ULOG_USING_FILTER */
1106*10465441SEvalZero 
1107*10465441SEvalZero rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool_t support_color)
1108*10465441SEvalZero {
1109*10465441SEvalZero     rt_base_t level;
1110*10465441SEvalZero 
1111*10465441SEvalZero     RT_ASSERT(backend);
1112*10465441SEvalZero     RT_ASSERT(name);
1113*10465441SEvalZero     RT_ASSERT(ulog.init_ok);
1114*10465441SEvalZero     RT_ASSERT(backend->output);
1115*10465441SEvalZero 
1116*10465441SEvalZero     if (backend->init)
1117*10465441SEvalZero     {
1118*10465441SEvalZero         backend->init(backend);
1119*10465441SEvalZero     }
1120*10465441SEvalZero 
1121*10465441SEvalZero     backend->support_color = support_color;
1122*10465441SEvalZero     rt_memcpy(backend->name, name, RT_NAME_MAX);
1123*10465441SEvalZero 
1124*10465441SEvalZero     level = rt_hw_interrupt_disable();
1125*10465441SEvalZero     rt_slist_append(&ulog.backend_list, &backend->list);
1126*10465441SEvalZero     rt_hw_interrupt_enable(level);
1127*10465441SEvalZero 
1128*10465441SEvalZero     return RT_EOK;
1129*10465441SEvalZero }
1130*10465441SEvalZero 
1131*10465441SEvalZero rt_err_t ulog_backend_unregister(ulog_backend_t backend)
1132*10465441SEvalZero {
1133*10465441SEvalZero     rt_base_t level;
1134*10465441SEvalZero 
1135*10465441SEvalZero     RT_ASSERT(backend);
1136*10465441SEvalZero     RT_ASSERT(ulog.init_ok);
1137*10465441SEvalZero 
1138*10465441SEvalZero     if (backend->deinit)
1139*10465441SEvalZero     {
1140*10465441SEvalZero         backend->deinit(backend);
1141*10465441SEvalZero     }
1142*10465441SEvalZero 
1143*10465441SEvalZero     level = rt_hw_interrupt_disable();
1144*10465441SEvalZero     rt_slist_remove(&ulog.backend_list, &backend->list);
1145*10465441SEvalZero     rt_hw_interrupt_enable(level);
1146*10465441SEvalZero 
1147*10465441SEvalZero     return RT_EOK;
1148*10465441SEvalZero }
1149*10465441SEvalZero 
1150*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
1151*10465441SEvalZero /**
1152*10465441SEvalZero  * asynchronous output logs to all backends
1153*10465441SEvalZero  *
1154*10465441SEvalZero  * @note you must call this function when ULOG_ASYNC_OUTPUT_BY_THREAD is disable
1155*10465441SEvalZero  */
1156*10465441SEvalZero void ulog_async_output(void)
1157*10465441SEvalZero {
1158*10465441SEvalZero     rt_rbb_blk_t log_blk;
1159*10465441SEvalZero     ulog_frame_t log_frame;
1160*10465441SEvalZero 
1161*10465441SEvalZero     while ((log_blk = rt_rbb_blk_get(ulog.async_rbb)) != NULL)
1162*10465441SEvalZero     {
1163*10465441SEvalZero         log_frame = (ulog_frame_t) log_blk->buf;
1164*10465441SEvalZero         if (log_frame->magic == ULOG_FRAME_MAGIC)
1165*10465441SEvalZero         {
1166*10465441SEvalZero             /* output to all backends */
1167*10465441SEvalZero             ulog_output_to_all_backend(log_frame->level, log_frame->tag, log_frame->is_raw, log_frame->log,
1168*10465441SEvalZero                     log_frame->log_len);
1169*10465441SEvalZero         }
1170*10465441SEvalZero         rt_rbb_blk_free(ulog.async_rbb, log_blk);
1171*10465441SEvalZero     }
1172*10465441SEvalZero }
1173*10465441SEvalZero 
1174*10465441SEvalZero /**
1175*10465441SEvalZero  * waiting for get asynchronous output log
1176*10465441SEvalZero  *
1177*10465441SEvalZero  * @param time the waiting time
1178*10465441SEvalZero  */
1179*10465441SEvalZero void ulog_async_waiting_log(rt_int32_t time)
1180*10465441SEvalZero {
1181*10465441SEvalZero     rt_sem_control(&ulog.async_notice, RT_IPC_CMD_RESET, RT_NULL);
1182*10465441SEvalZero     rt_sem_take(&ulog.async_notice, time);
1183*10465441SEvalZero }
1184*10465441SEvalZero 
1185*10465441SEvalZero static void async_output_thread_entry(void *param)
1186*10465441SEvalZero {
1187*10465441SEvalZero     while (1)
1188*10465441SEvalZero     {
1189*10465441SEvalZero         ulog_async_waiting_log(RT_WAITING_FOREVER);
1190*10465441SEvalZero         ulog_async_output();
1191*10465441SEvalZero     }
1192*10465441SEvalZero }
1193*10465441SEvalZero #endif /* ULOG_USING_ASYNC_OUTPUT */
1194*10465441SEvalZero 
1195*10465441SEvalZero /**
1196*10465441SEvalZero  * flush all backends's log
1197*10465441SEvalZero  */
1198*10465441SEvalZero void ulog_flush(void)
1199*10465441SEvalZero {
1200*10465441SEvalZero     rt_slist_t *node;
1201*10465441SEvalZero     ulog_backend_t backend;
1202*10465441SEvalZero 
1203*10465441SEvalZero     if (!ulog.init_ok)
1204*10465441SEvalZero         return;
1205*10465441SEvalZero 
1206*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
1207*10465441SEvalZero     ulog_async_output();
1208*10465441SEvalZero #endif
1209*10465441SEvalZero 
1210*10465441SEvalZero     /* flush all backends */
1211*10465441SEvalZero     for (node = rt_slist_first(&ulog.backend_list); node; node = rt_slist_next(node))
1212*10465441SEvalZero     {
1213*10465441SEvalZero         backend = rt_slist_entry(node, struct ulog_backend, list);
1214*10465441SEvalZero         if (backend->flush)
1215*10465441SEvalZero         {
1216*10465441SEvalZero             backend->flush(backend);
1217*10465441SEvalZero         }
1218*10465441SEvalZero     }
1219*10465441SEvalZero }
1220*10465441SEvalZero 
1221*10465441SEvalZero int ulog_init(void)
1222*10465441SEvalZero {
1223*10465441SEvalZero     if (ulog.init_ok)
1224*10465441SEvalZero         return 0;
1225*10465441SEvalZero 
1226*10465441SEvalZero     rt_mutex_init(&ulog.output_locker, "ulog lock", RT_IPC_FLAG_FIFO);
1227*10465441SEvalZero     rt_slist_init(&ulog.backend_list);
1228*10465441SEvalZero 
1229*10465441SEvalZero #ifdef ULOG_USING_FILTER
1230*10465441SEvalZero     rt_slist_init(ulog_tag_lvl_list_get());
1231*10465441SEvalZero #endif
1232*10465441SEvalZero 
1233*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
1234*10465441SEvalZero     RT_ASSERT(ULOG_ASYNC_OUTPUT_STORE_LINES >= 2);
1235*10465441SEvalZero     /* async output ring block buffer */
1236*10465441SEvalZero     ulog.async_rbb = rt_rbb_create(RT_ALIGN(ULOG_ASYNC_OUTPUT_BUF_SIZE, RT_ALIGN_SIZE), ULOG_ASYNC_OUTPUT_STORE_LINES);
1237*10465441SEvalZero     if (ulog.async_rbb == NULL)
1238*10465441SEvalZero     {
1239*10465441SEvalZero         rt_kprintf("Error: ulog init failed! No memory for async rbb.\n");
1240*10465441SEvalZero         rt_mutex_detach(&ulog.output_locker);
1241*10465441SEvalZero         return -RT_ENOMEM;
1242*10465441SEvalZero     }
1243*10465441SEvalZero     /* async output thread */
1244*10465441SEvalZero     ulog.async_th = rt_thread_create("ulog_async", async_output_thread_entry, &ulog, ULOG_ASYNC_OUTPUT_THREAD_STACK,
1245*10465441SEvalZero             ULOG_ASYNC_OUTPUT_THREAD_PRIORITY, 20);
1246*10465441SEvalZero     if (ulog.async_th == NULL)
1247*10465441SEvalZero     {
1248*10465441SEvalZero         rt_kprintf("Error: ulog init failed! No memory for async output thread.\n");
1249*10465441SEvalZero         rt_mutex_detach(&ulog.output_locker);
1250*10465441SEvalZero         rt_rbb_destroy(ulog.async_rbb);
1251*10465441SEvalZero         return -RT_ENOMEM;
1252*10465441SEvalZero     }
1253*10465441SEvalZero 
1254*10465441SEvalZero     rt_sem_init(&ulog.async_notice, "ulog", 0, RT_IPC_FLAG_FIFO);
1255*10465441SEvalZero     /* async output thread startup */
1256*10465441SEvalZero     rt_thread_startup(ulog.async_th);
1257*10465441SEvalZero 
1258*10465441SEvalZero #endif /* ULOG_USING_ASYNC_OUTPUT */
1259*10465441SEvalZero 
1260*10465441SEvalZero #ifdef ULOG_USING_FILTER
1261*10465441SEvalZero     ulog_global_filter_lvl_set(LOG_FILTER_LVL_ALL);
1262*10465441SEvalZero #endif
1263*10465441SEvalZero 
1264*10465441SEvalZero     ulog.init_ok = RT_TRUE;
1265*10465441SEvalZero 
1266*10465441SEvalZero     return 0;
1267*10465441SEvalZero }
1268*10465441SEvalZero INIT_PREV_EXPORT(ulog_init);
1269*10465441SEvalZero 
1270*10465441SEvalZero void ulog_deinit(void)
1271*10465441SEvalZero {
1272*10465441SEvalZero     rt_slist_t *node;
1273*10465441SEvalZero     ulog_backend_t backend;
1274*10465441SEvalZero 
1275*10465441SEvalZero     if (!ulog.init_ok)
1276*10465441SEvalZero         return;
1277*10465441SEvalZero 
1278*10465441SEvalZero     /* deinit all backends */
1279*10465441SEvalZero     for (node = rt_slist_first(&ulog.backend_list); node; node = rt_slist_next(node))
1280*10465441SEvalZero     {
1281*10465441SEvalZero         backend = rt_slist_entry(node, struct ulog_backend, list);
1282*10465441SEvalZero         if (backend->deinit)
1283*10465441SEvalZero         {
1284*10465441SEvalZero             backend->deinit(backend);
1285*10465441SEvalZero         }
1286*10465441SEvalZero     }
1287*10465441SEvalZero 
1288*10465441SEvalZero #ifdef ULOG_USING_FILTER
1289*10465441SEvalZero     /* deinit tag's level filter */
1290*10465441SEvalZero     {
1291*10465441SEvalZero         ulog_tag_lvl_filter_t tag_lvl;
1292*10465441SEvalZero         for (node = rt_slist_first(ulog_tag_lvl_list_get()); node; node = rt_slist_next(node))
1293*10465441SEvalZero         {
1294*10465441SEvalZero             tag_lvl = rt_slist_entry(node, struct ulog_tag_lvl_filter, list);
1295*10465441SEvalZero             rt_free(tag_lvl);
1296*10465441SEvalZero         }
1297*10465441SEvalZero     }
1298*10465441SEvalZero #endif /* ULOG_USING_FILTER */
1299*10465441SEvalZero 
1300*10465441SEvalZero     rt_mutex_detach(&ulog.output_locker);
1301*10465441SEvalZero 
1302*10465441SEvalZero #ifdef ULOG_USING_ASYNC_OUTPUT
1303*10465441SEvalZero     rt_rbb_destroy(ulog.async_rbb);
1304*10465441SEvalZero     rt_thread_delete(ulog.async_th);
1305*10465441SEvalZero #endif
1306*10465441SEvalZero 
1307*10465441SEvalZero     ulog.init_ok = RT_FALSE;
1308*10465441SEvalZero }
1309*10465441SEvalZero 
1310*10465441SEvalZero #endif /* RT_USING_ULOG */
1311