[components][utilities][ulog] Improve the HEX LOG by new formater. (#6490)
- 重构格式化器 - 重写 HEX 日志功能,与标准日志使用相同的格式化器。与标准日志在日志过滤功能和日志头显示功能上一致
This commit is contained in:
parent
560a21207e
commit
a48f446a0f
|
@ -246,20 +246,16 @@ static char *get_log_buf(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RT_WEAK rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *tag, rt_bool_t newline,
|
RT_WEAK rt_size_t ulog_head_formater(char *log_buf, rt_uint32_t level, const char *tag)
|
||||||
const char *format, va_list args)
|
|
||||||
{
|
{
|
||||||
/* the caller has locker, so it can use static variable for reduce stack usage */
|
/* the caller has locker, so it can use static variable for reduce stack usage */
|
||||||
static rt_size_t log_len, newline_len;
|
static rt_size_t log_len;
|
||||||
static int fmt_result;
|
|
||||||
|
|
||||||
RT_ASSERT(log_buf);
|
RT_ASSERT(log_buf);
|
||||||
RT_ASSERT(level <= LOG_LVL_DBG);
|
RT_ASSERT(level <= LOG_LVL_DBG);
|
||||||
RT_ASSERT(tag);
|
RT_ASSERT(tag);
|
||||||
RT_ASSERT(format);
|
|
||||||
|
|
||||||
log_len = 0;
|
log_len = 0;
|
||||||
newline_len = rt_strlen(ULOG_NEWLINE_SIGN);
|
|
||||||
|
|
||||||
#ifdef ULOG_USING_COLOR
|
#ifdef ULOG_USING_COLOR
|
||||||
/* add CSI start sign and color info */
|
/* add CSI start sign and color info */
|
||||||
|
@ -370,19 +366,18 @@ RT_WEAK rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *ta
|
||||||
#endif /* ULOG_OUTPUT_THREAD_NAME */
|
#endif /* ULOG_OUTPUT_THREAD_NAME */
|
||||||
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, ": ");
|
log_len += ulog_strcpy(log_len, log_buf + log_len, ": ");
|
||||||
fmt_result = rt_vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args);
|
|
||||||
|
|
||||||
/* calculate log length */
|
return log_len;
|
||||||
if ((log_len + fmt_result <= ULOG_LINE_BUF_SIZE) && (fmt_result > -1))
|
}
|
||||||
{
|
|
||||||
log_len += fmt_result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* using max length */
|
|
||||||
log_len = ULOG_LINE_BUF_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
RT_WEAK rt_size_t ulog_tail_formater(char *log_buf, rt_size_t log_len, rt_bool_t newline, rt_uint32_t level)
|
||||||
|
{
|
||||||
|
/* the caller has locker, so it can use static variable for reduce stack usage */
|
||||||
|
static rt_size_t newline_len;
|
||||||
|
|
||||||
|
RT_ASSERT(log_buf);
|
||||||
|
newline_len = rt_strlen(ULOG_NEWLINE_SIGN);
|
||||||
/* overflow check and reserve some space for CSI end sign, newline sign and string end sign */
|
/* overflow check and reserve some space for CSI end sign, newline sign and string end sign */
|
||||||
#ifdef ULOG_USING_COLOR
|
#ifdef ULOG_USING_COLOR
|
||||||
if (log_len + (sizeof(CSI_END) - 1) + newline_len + sizeof((char)'\0') > ULOG_LINE_BUF_SIZE)
|
if (log_len + (sizeof(CSI_END) - 1) + newline_len + sizeof((char)'\0') > ULOG_LINE_BUF_SIZE)
|
||||||
|
@ -423,6 +418,86 @@ RT_WEAK rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *ta
|
||||||
return log_len;
|
return log_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RT_WEAK rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *tag, rt_bool_t newline,
|
||||||
|
const char *format, va_list args)
|
||||||
|
{
|
||||||
|
/* the caller has locker, so it can use static variable for reduce stack usage */
|
||||||
|
static rt_size_t log_len;
|
||||||
|
static int fmt_result;
|
||||||
|
|
||||||
|
RT_ASSERT(log_buf);
|
||||||
|
RT_ASSERT(format);
|
||||||
|
|
||||||
|
/* log head */
|
||||||
|
log_len = ulog_head_formater(log_buf, level, tag);
|
||||||
|
/* log content */
|
||||||
|
fmt_result = rt_vsnprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, format, args);
|
||||||
|
/* calculate log length */
|
||||||
|
if ((log_len + fmt_result <= ULOG_LINE_BUF_SIZE) && (fmt_result > -1))
|
||||||
|
{
|
||||||
|
log_len += fmt_result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* using max length */
|
||||||
|
log_len = ULOG_LINE_BUF_SIZE;
|
||||||
|
}
|
||||||
|
/* log tail */
|
||||||
|
return ulog_tail_formater(log_buf, log_len, newline, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
RT_WEAK rt_size_t ulog_hex_formater(char *log_buf, const char *tag, const rt_uint8_t *buf, rt_size_t size, rt_size_t width, rt_base_t addr)
|
||||||
|
{
|
||||||
|
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
||||||
|
/* the caller has locker, so it can use static variable for reduce stack usage */
|
||||||
|
static rt_size_t log_len, j;
|
||||||
|
static int fmt_result;
|
||||||
|
char dump_string[8];
|
||||||
|
|
||||||
|
RT_ASSERT(log_buf);
|
||||||
|
RT_ASSERT(buf);
|
||||||
|
|
||||||
|
/* log head */
|
||||||
|
log_len = ulog_head_formater(log_buf, LOG_LVL_DBG, tag);
|
||||||
|
/* log content */
|
||||||
|
fmt_result = rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE, "%04X-%04X: ", addr, addr + size);
|
||||||
|
/* calculate log length */
|
||||||
|
if ((fmt_result > -1) && (fmt_result <= ULOG_LINE_BUF_SIZE))
|
||||||
|
{
|
||||||
|
log_len += fmt_result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_len = ULOG_LINE_BUF_SIZE;
|
||||||
|
}
|
||||||
|
/* dump hex */
|
||||||
|
for (j = 0; j < width; j++)
|
||||||
|
{
|
||||||
|
if (j < size)
|
||||||
|
{
|
||||||
|
rt_snprintf(dump_string, sizeof(dump_string), "%02X ", buf[j]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_strncpy(dump_string, " ", sizeof(dump_string));
|
||||||
|
}
|
||||||
|
log_len += ulog_strcpy(log_len, log_buf + log_len, dump_string);
|
||||||
|
if ((j + 1) % 8 == 0)
|
||||||
|
{
|
||||||
|
log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
|
||||||
|
/* dump char for hex */
|
||||||
|
for (j = 0; j < size; j++)
|
||||||
|
{
|
||||||
|
rt_snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf[j]) ? buf[j] : '.');
|
||||||
|
log_len += ulog_strcpy(log_len, log_buf + log_len, dump_string);
|
||||||
|
}
|
||||||
|
/* log tail */
|
||||||
|
return ulog_tail_formater(log_buf, log_len, RT_TRUE, LOG_LVL_DBG);
|
||||||
|
}
|
||||||
|
|
||||||
static void ulog_output_to_all_backend(rt_uint32_t level, const char *tag, rt_bool_t is_raw, const char *log, rt_size_t len)
|
static void ulog_output_to_all_backend(rt_uint32_t level, const char *tag, rt_bool_t is_raw, const char *log, rt_size_t len)
|
||||||
{
|
{
|
||||||
rt_slist_t *node;
|
rt_slist_t *node;
|
||||||
|
@ -552,24 +627,28 @@ static void do_output(rt_uint32_t level, const char *tag, rt_bool_t is_raw, cons
|
||||||
* @param level level
|
* @param level level
|
||||||
* @param tag tag
|
* @param tag tag
|
||||||
* @param newline has_newline
|
* @param newline has_newline
|
||||||
|
* @param hex_buf != RT_NULL: enable hex log mode, data buffer
|
||||||
|
* @param hex_size hex data buffer size
|
||||||
|
* @param hex_width hex log width
|
||||||
|
* @param hex_addr hex data address
|
||||||
* @param format output format
|
* @param format output format
|
||||||
* @param args variable argument list
|
* @param args variable argument list
|
||||||
*/
|
*/
|
||||||
void ulog_voutput(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, va_list args)
|
void ulog_voutput(rt_uint32_t level, const char *tag, rt_bool_t newline, const rt_uint8_t *hex_buf, rt_size_t hex_size,
|
||||||
|
rt_size_t hex_width, rt_base_t hex_addr, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
static rt_bool_t ulog_voutput_recursion = RT_FALSE;
|
static rt_bool_t ulog_voutput_recursion = RT_FALSE;
|
||||||
char *log_buf = RT_NULL;
|
char *log_buf = RT_NULL;
|
||||||
rt_size_t log_len = 0;
|
static rt_size_t log_len = 0;
|
||||||
|
|
||||||
RT_ASSERT(tag);
|
RT_ASSERT(tag);
|
||||||
RT_ASSERT(format);
|
RT_ASSERT((format && !hex_buf) || (!format && hex_buf));
|
||||||
#ifndef ULOG_USING_SYSLOG
|
#ifndef ULOG_USING_SYSLOG
|
||||||
RT_ASSERT(level <= LOG_LVL_DBG);
|
RT_ASSERT(level <= LOG_LVL_DBG);
|
||||||
#else
|
#else
|
||||||
RT_ASSERT(LOG_PRI(level) <= LOG_DEBUG);
|
RT_ASSERT(LOG_PRI(level) <= LOG_DEBUG);
|
||||||
#endif /* ULOG_USING_SYSLOG */
|
#endif /* ULOG_USING_SYSLOG */
|
||||||
|
|
||||||
|
|
||||||
if (!ulog.init_ok)
|
if (!ulog.init_ok)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -603,10 +682,10 @@ void ulog_voutput(rt_uint32_t level, const char *tag, rt_bool_t newline, const c
|
||||||
output_lock();
|
output_lock();
|
||||||
|
|
||||||
/* If there is a recursion, we use a simple way */
|
/* If there is a recursion, we use a simple way */
|
||||||
if (ulog_voutput_recursion == RT_TRUE)
|
if ((ulog_voutput_recursion == RT_TRUE) && (hex_buf == RT_NULL))
|
||||||
{
|
{
|
||||||
rt_kprintf(format, args);
|
rt_kprintf(format, args);
|
||||||
if(newline == RT_TRUE)
|
if (newline == RT_TRUE)
|
||||||
{
|
{
|
||||||
rt_kprintf(ULOG_NEWLINE_SIGN);
|
rt_kprintf(ULOG_NEWLINE_SIGN);
|
||||||
}
|
}
|
||||||
|
@ -616,12 +695,20 @@ void ulog_voutput(rt_uint32_t level, const char *tag, rt_bool_t newline, const c
|
||||||
|
|
||||||
ulog_voutput_recursion = RT_TRUE;
|
ulog_voutput_recursion = RT_TRUE;
|
||||||
|
|
||||||
|
if (hex_buf == RT_NULL)
|
||||||
|
{
|
||||||
#ifndef ULOG_USING_SYSLOG
|
#ifndef ULOG_USING_SYSLOG
|
||||||
log_len = ulog_formater(log_buf, level, tag, newline, format, args);
|
log_len = ulog_formater(log_buf, level, tag, newline, format, args);
|
||||||
#else
|
#else
|
||||||
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);
|
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);
|
||||||
log_len = syslog_formater(log_buf, level, tag, newline, format, args);
|
log_len = syslog_formater(log_buf, level, tag, newline, format, args);
|
||||||
#endif /* ULOG_USING_SYSLOG */
|
#endif /* ULOG_USING_SYSLOG */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* hex mode */
|
||||||
|
log_len = ulog_hex_formater(log_buf, tag, hex_buf, hex_size, hex_width, hex_addr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ULOG_USING_FILTER
|
#ifdef ULOG_USING_FILTER
|
||||||
/* keyword filter */
|
/* keyword filter */
|
||||||
|
@ -664,7 +751,7 @@ void ulog_output(rt_uint32_t level, const char *tag, rt_bool_t newline, const ch
|
||||||
/* args point to the first variable parameter */
|
/* args point to the first variable parameter */
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
ulog_voutput(level, tag, newline, format, args);
|
ulog_voutput(level, tag, newline, RT_NULL, 0, 0, 0, format, args);
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
@ -727,150 +814,23 @@ void ulog_raw(const char *format, ...)
|
||||||
* @param buf hex buffer
|
* @param buf hex buffer
|
||||||
* @param size buffer size
|
* @param size buffer size
|
||||||
*/
|
*/
|
||||||
void ulog_hexdump(const char *tag, rt_size_t width, rt_uint8_t *buf, rt_size_t size)
|
void ulog_hexdump(const char *tag, rt_size_t width, const rt_uint8_t *buf, rt_size_t size, ...)
|
||||||
{
|
{
|
||||||
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
rt_size_t i, len;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
rt_size_t i, j;
|
va_start(args, size);
|
||||||
rt_size_t log_len = 0, name_len = rt_strlen(tag);
|
|
||||||
#ifdef ULOG_OUTPUT_TIME
|
|
||||||
rt_size_t time_head_len = 0;
|
|
||||||
#endif
|
|
||||||
char *log_buf = RT_NULL, dump_string[8];
|
|
||||||
int fmt_result;
|
|
||||||
|
|
||||||
RT_ASSERT(ulog.init_ok);
|
for (i = 0; i < size; i += width, buf += width)
|
||||||
|
|
||||||
#ifdef ULOG_USING_FILTER
|
|
||||||
/* level filter */
|
|
||||||
#ifndef ULOG_USING_SYSLOG
|
|
||||||
if (LOG_LVL_DBG > ulog.filter.level || LOG_LVL_DBG > ulog_tag_lvl_filter_get(tag))
|
|
||||||
{
|
{
|
||||||
return;
|
if (i + size < width)
|
||||||
}
|
len = size - i;
|
||||||
#else
|
|
||||||
if ((LOG_MASK(LOG_DEBUG) & ulog.filter.level) == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif /* ULOG_USING_SYSLOG */
|
|
||||||
else if (!rt_strstr(tag, ulog.filter.tag))
|
|
||||||
{
|
|
||||||
/* tag filter */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif /* ULOG_USING_FILTER */
|
|
||||||
|
|
||||||
#ifdef ULOG_USING_ASYNC_OUTPUT
|
|
||||||
if (ulog.async_rb == RT_NULL)
|
|
||||||
{
|
|
||||||
ulog.async_rb = rt_ringbuffer_create(ULOG_ASYNC_OUTPUT_BUF_SIZE);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* get log buffer */
|
|
||||||
log_buf = get_log_buf();
|
|
||||||
|
|
||||||
/* lock output */
|
|
||||||
output_lock();
|
|
||||||
|
|
||||||
for (i = 0, log_len = 0; i < size; i += width)
|
|
||||||
{
|
|
||||||
/* package header */
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
#ifdef ULOG_OUTPUT_TIME
|
|
||||||
/* add time info */
|
|
||||||
#ifdef ULOG_TIME_USING_TIMESTAMP
|
|
||||||
static time_t now;
|
|
||||||
static struct tm *tm, tm_tmp;
|
|
||||||
|
|
||||||
now = time(RT_NULL);
|
|
||||||
tm = gmtime_r(&now, &tm_tmp);
|
|
||||||
|
|
||||||
#ifdef RT_USING_SOFT_RTC
|
|
||||||
rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "%02d-%02d %02d:%02d:%02d.%03d ", tm->tm_mon + 1,
|
|
||||||
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, rt_tick_get() % 1000);
|
|
||||||
#else
|
|
||||||
rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE - log_len, "%02d-%02d %02d:%02d:%02d ", tm->tm_mon + 1,
|
|
||||||
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
||||||
#endif /* RT_USING_SOFT_RTC */
|
|
||||||
|
|
||||||
#else
|
|
||||||
static rt_size_t tick_len = 0;
|
|
||||||
|
|
||||||
log_buf[log_len] = '[';
|
|
||||||
tick_len = ulog_ultoa(log_buf + log_len + 1, rt_tick_get());
|
|
||||||
log_buf[log_len + 1 + tick_len] = ']';
|
|
||||||
log_buf[log_len + 2 + tick_len] = ' ';
|
|
||||||
log_buf[log_len + 3 + tick_len] = '\0';
|
|
||||||
#endif /* ULOG_TIME_USING_TIMESTAMP */
|
|
||||||
time_head_len = rt_strlen(log_buf + log_len);
|
|
||||||
log_len += time_head_len;
|
|
||||||
#endif /* ULOG_OUTPUT_TIME */
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, "D/HEX ");
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, tag);
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, ": ");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
len = width;
|
||||||
log_len = 6 + name_len + 2;
|
ulog_voutput(LOG_LVL_DBG, tag, RT_TRUE, buf, len, width, i, RT_NULL, args);
|
||||||
#ifdef ULOG_OUTPUT_TIME
|
|
||||||
log_len += time_head_len;
|
|
||||||
#endif
|
|
||||||
rt_memset(log_buf, ' ', log_len);
|
|
||||||
}
|
|
||||||
fmt_result = rt_snprintf(log_buf + log_len, ULOG_LINE_BUF_SIZE, "%04X-%04X: ", i, i + width - 1);
|
|
||||||
/* calculate log length */
|
|
||||||
if ((fmt_result > -1) && (fmt_result <= ULOG_LINE_BUF_SIZE))
|
|
||||||
{
|
|
||||||
log_len += fmt_result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_len = ULOG_LINE_BUF_SIZE;
|
|
||||||
}
|
|
||||||
/* dump hex */
|
|
||||||
for (j = 0; j < width; j++)
|
|
||||||
{
|
|
||||||
if (i + j < size)
|
|
||||||
{
|
|
||||||
rt_snprintf(dump_string, sizeof(dump_string), "%02X ", buf[i + j]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rt_strncpy(dump_string, " ", sizeof(dump_string));
|
|
||||||
}
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, dump_string);
|
|
||||||
if ((j + 1) % 8 == 0)
|
|
||||||
{
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, " ");
|
|
||||||
/* dump char for hex */
|
|
||||||
for (j = 0; j < width; j++)
|
|
||||||
{
|
|
||||||
if (i + j < size)
|
|
||||||
{
|
|
||||||
rt_snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, dump_string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* overflow check and reserve some space for newline sign */
|
|
||||||
if (log_len + rt_strlen(ULOG_NEWLINE_SIGN) > ULOG_LINE_BUF_SIZE)
|
|
||||||
{
|
|
||||||
log_len = ULOG_LINE_BUF_SIZE - rt_strlen(ULOG_NEWLINE_SIGN);
|
|
||||||
}
|
|
||||||
/* package newline sign */
|
|
||||||
log_len += ulog_strcpy(log_len, log_buf + log_len, ULOG_NEWLINE_SIGN);
|
|
||||||
/*add string end sign*/
|
|
||||||
log_buf[log_len] = '\0';
|
|
||||||
/* do log output */
|
|
||||||
do_output(LOG_LVL_DBG, RT_NULL, RT_TRUE, log_buf, log_len);
|
|
||||||
}
|
}
|
||||||
/* unlock output */
|
|
||||||
output_unlock();
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ULOG_USING_FILTER
|
#ifdef ULOG_USING_FILTER
|
||||||
|
|
|
@ -87,12 +87,11 @@ rt_err_t ulog_async_waiting_log(rt_int32_t time);
|
||||||
/*
|
/*
|
||||||
* dump the hex format data to log
|
* dump the hex format data to log
|
||||||
*/
|
*/
|
||||||
void ulog_hexdump(const char *tag, rt_size_t width, rt_uint8_t *buf, rt_size_t size);
|
void ulog_hexdump(const char *tag, rt_size_t width, const rt_uint8_t *buf, rt_size_t size, ...);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Another log output API. This API is more difficult to use than LOG_X API.
|
* Another log output API. This API is more difficult to use than LOG_X API.
|
||||||
*/
|
*/
|
||||||
void ulog_voutput(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, va_list args);
|
|
||||||
void ulog_output(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, ...);
|
void ulog_output(rt_uint32_t level, const char *tag, rt_bool_t newline, const char *format, ...);
|
||||||
void ulog_raw(const char *format, ...);
|
void ulog_raw(const char *format, ...);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue