Skip to content

Commit 1b99377

Browse files
committed
feat(ulog): add targeted emergency log dump function
1 parent 666fa24 commit 1b99377

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

components/utilities/ulog/ulog.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,72 @@ void ulog_flush(void)
14851485
}
14861486
}
14871487

1488+
/**
1489+
* @brief Safely dumps pending ulog async logs to a single specified backend.
1490+
*
1491+
* This function is designed for use in critical error handlers (e.g., stack
1492+
* overflow, hard fault, assertion failures). It avoids calling the general
1493+
* `ulog_flush()` function, which could trigger unstable backends (like
1494+
* filesystems or network sockets) and cause secondary crashes. Instead, it
1495+
* finds a specific, trusted backend by name and directly invokes its output
1496+
* and flush functions.
1497+
*
1498+
* @param[in] backend_name The name of the target backend to dump logs to.
1499+
* For maximum safety, this should be a simple,
1500+
* polling-based UART console backend (e.g., "console").
1501+
*
1502+
* @note This function will have no effect if the ulog asynchronous output
1503+
* (`ULOG_USING_ASYNC_OUTPUT`) feature is not enabled.
1504+
*/
1505+
void ulog_emergency_dump_to(const char *backend_name)
1506+
{
1507+
rt_rbb_blk_t log_blk;
1508+
ulog_frame_t log_frame;
1509+
ulog_backend_t target_backend = RT_NULL;
1510+
1511+
if (!ulog.init_ok || !backend_name)
1512+
{
1513+
return;
1514+
}
1515+
1516+
target_backend = ulog_backend_find(backend_name);
1517+
if (target_backend == RT_NULL)
1518+
{
1519+
return;
1520+
}
1521+
1522+
#ifdef ULOG_USING_ASYNC_OUTPUT
1523+
while ((log_blk = rt_rbb_blk_get(ulog.async_rbb)) != RT_NULL)
1524+
{
1525+
log_frame = (ulog_frame_t) log_blk->buf;
1526+
if (log_frame->magic == ULOG_FRAME_MAGIC)
1527+
{
1528+
target_backend->output(target_backend, log_frame->level, log_frame->tag,
1529+
log_frame->is_raw, log_frame->log, log_frame->log_len);
1530+
}
1531+
rt_rbb_blk_free(ulog.async_rbb, log_blk);
1532+
}
1533+
1534+
rt_size_t log_len = rt_ringbuffer_data_len(ulog.async_rb);
1535+
if (ulog.async_rb && log_len > 0)
1536+
{
1537+
char *log = rt_malloc(log_len + 1);
1538+
if (log)
1539+
{
1540+
rt_size_t len = rt_ringbuffer_get(ulog.async_rb, (rt_uint8_t *)log, (rt_uint16_t)log_len);
1541+
log[log_len] = '\0';
1542+
ulog_output_to_all_backend(LOG_LVL_DBG, "", RT_TRUE, log, len);
1543+
rt_free(log);
1544+
}
1545+
}
1546+
#endif
1547+
1548+
if (target_backend->flush)
1549+
{
1550+
target_backend->flush(target_backend);
1551+
}
1552+
}
1553+
14881554
/**
14891555
* @brief ulog initialization
14901556
*

components/utilities/ulog/ulog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const char *ulog_global_filter_kw_get(void);
7474
* flush all backends's log
7575
*/
7676
void ulog_flush(void);
77+
void ulog_emergency_dump_to(const char *backend_name);
7778

7879
#ifdef ULOG_USING_ASYNC_OUTPUT
7980
/*

src/scheduler_comm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ void rt_scheduler_stack_check(struct rt_thread *thread)
485485
rt_err_t hook_result = -RT_ERROR;
486486

487487
LOG_E("thread:%s stack overflow\n", thread->parent.name);
488+
ulog_emergency_dump_to("console");
488489

489490
#if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
490491
if (rt_stack_overflow_hook != RT_NULL)

0 commit comments

Comments
 (0)