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