Skip to content

Commit fdc1f40

Browse files
Option to append string to truncated log messages
Detect when a log message is truncated, and append a short string to indicate this. The string is formatted as purple italics to distinguish it from normal log messages. Also appends a newline character, so that the next log message starts on its own line. The string can be changed using menuconfig. An empty string will only print a newline character. It can also be completely disabled.
1 parent 07a0117 commit fdc1f40

2 files changed

Lines changed: 126 additions & 80 deletions

File tree

components/utilities/log_router/Kconfig

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ menu "LOG ROUTER"
3636
Larger buffer can handle longer log messages but uses more stack space.
3737
Range: 256 to 1024 bytes
3838

39+
config LOG_ROUTER_APPEND_STRING_ON_TRUNCATE
40+
bool "Show message on truncate"
41+
default y
42+
help
43+
When enabled, log messages that are truncated because they do not fit
44+
into LOG_ROUTER_FORMAT_BUFFER_SIZE will have a string appended to them,
45+
to indicate that the log message is incomplete.
46+
47+
if LOG_ROUTER_APPEND_STRING_ON_TRUNCATE
48+
config LOG_ROUTER_TRUNCATE_STRING
49+
string
50+
default "<TRUNCATED>"
51+
prompt "Append this string to truncated logs"
52+
help
53+
String appended to truncated log messages. If log colors are enabled,
54+
it will be formatted as purple italics: see CONFIG_LOG_COLORS
55+
56+
A newline character is also added, so that the next log message starts
57+
on its own line.
58+
59+
60+
endif #LOG_ROUTER_APPEND_STRING_ON_TRUNCATE
61+
3962
config LOG_ROUTER_DEBUG_OUTPUT
4063
bool "Enable debug output"
4164
default y

components/utilities/log_router/log_router.c

Lines changed: 103 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@
1515
#include "freertos/FreeRTOS.h"
1616
#include "freertos/semphr.h"
1717
#include "log_router.h"
18+
#include "esp_log_color.h"
19+
20+
#include "sdkconfig.h"
1821

1922
static const char *TAG = "log_router";
2023

24+
// Truncated messages will be immediately followed by this message
25+
#if (CONFIG_LOG_ROUTER_APPEND_STRING_ON_TRUNCATE)
26+
static const char *TRUNCATE_MESSAGE = LOG_ITALIC(LOG_COLOR_PURPLE) "" CONFIG_LOG_ROUTER_TRUNCATE_STRING "" LOG_RESET_COLOR "\n" ;
27+
#endif
2128
// Global mutex for thread safety
2229
static SemaphoreHandle_t g_log_router_mutex = NULL;
2330

@@ -93,6 +100,96 @@ static esp_err_t esp_log_router_flush_buffer(esp_log_router_slist_t *item)
93100
return ESP_OK;
94101
}
95102

103+
static void router_fwrite(const void *__restrict buffer, size_t size, size_t n, esp_log_router_slist_t *item, uint32_t now)
104+
{
105+
bool should_flush = false;
106+
107+
size_t len = n * size;
108+
109+
// Check if we need to flush due to threshold
110+
if ((item->buffer_pos + len) >= item->flush_threshold) {
111+
should_flush = true;
112+
log_router_debug_printf("Flush buffer due to threshold\n");
113+
}
114+
115+
// Check if we need to flush due to timeout
116+
if ((now - item->last_flush_time) >= item->flush_timeout_ms) {
117+
should_flush = true;
118+
log_router_debug_printf("Flush buffer due to timeout\n");
119+
}
120+
121+
// Flush buffer if needed
122+
if (should_flush) {
123+
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
124+
uint64_t flush_start_time = esp_timer_get_time();
125+
#endif
126+
esp_err_t flush_ret = esp_log_router_flush_buffer(item);
127+
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
128+
uint32_t flush_duration_us = esp_timer_get_time() - flush_start_time;
129+
log_router_debug_printf("Flush operation took %ums, file: %s\n", flush_duration_us / 1000, item->file_path);
130+
#endif
131+
if (flush_ret != ESP_OK) {
132+
log_router_debug_printf("Failed to flush buffer: %s\n", esp_err_to_name(flush_ret));
133+
// Flush failed, write directly to file
134+
size_t written = fwrite(buffer, 1, len, item->log_fp);
135+
if (written != len) {
136+
log_router_debug_printf("Failed to write directly to file, written: %zu, expected: %d\n", written, len);
137+
// Try to seek to beginning and retry
138+
if (fseek(item->log_fp, 0, SEEK_SET) == 0 && ftruncate(fileno(item->log_fp), 0) == 0) {
139+
log_router_debug_printf("File truncated, retrying direct write\n");
140+
written = fwrite(buffer, 1, len, item->log_fp);
141+
if (written != len) {
142+
log_router_debug_printf("Retry direct write also failed\n");
143+
return;
144+
}
145+
} else {
146+
log_router_debug_printf("Failed to seek/truncate file for direct write\n");
147+
return;
148+
}
149+
}
150+
fflush(item->log_fp);
151+
fsync(fileno(item->log_fp));
152+
return; // Skip buffer write since we already wrote to file
153+
}
154+
// Flush successful, buffer is now empty, continue to buffer write
155+
}
156+
157+
// Try to add to buffer, if still too large, write directly to file
158+
if ((item->buffer_pos + len) < item->buffer_size) {
159+
memcpy(item->buffer + item->buffer_pos, buffer, len);
160+
item->buffer_pos += len;
161+
} else {
162+
// Buffer is too small, write directly to file
163+
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
164+
uint64_t write_start_time = esp_timer_get_time();
165+
#endif
166+
size_t written = fwrite(buffer, 1, len, item->log_fp);
167+
if (written != len) {
168+
log_router_debug_printf("Failed to write directly to file, written: %zu, expected: %d\n", written, len);
169+
// Try to seek to beginning and retry
170+
if (fseek(item->log_fp, 0, SEEK_SET) == 0 && ftruncate(fileno(item->log_fp), 0) == 0) {
171+
log_router_debug_printf("File truncated, retrying direct write\n");
172+
written = fwrite(buffer, 1, len, item->log_fp);
173+
if (written != len) {
174+
log_router_debug_printf("Retry direct write also failed\n");
175+
return;
176+
}
177+
} else {
178+
log_router_debug_printf("Failed to seek/truncate file for direct write\n");
179+
return;
180+
}
181+
}
182+
fflush(item->log_fp);
183+
fsync(fileno(item->log_fp));
184+
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
185+
uint32_t write_duration_us = esp_timer_get_time() - write_start_time;
186+
log_router_debug_printf("Direct write took %ums, size: %d, file: %s\n", write_duration_us / 1000, len, item->file_path);
187+
#endif
188+
}
189+
190+
return;
191+
}
192+
96193
int esp_log_router_flash_vprintf(const char *format, va_list args)
97194
{
98195
int ret = 0;
@@ -124,8 +221,9 @@ int esp_log_router_flash_vprintf(const char *format, va_list args)
124221
esp_log_router_slist_t *item;
125222
int len = vsnprintf(vprintf_buffer, sizeof(vprintf_buffer), format, args);
126223
if (len > 0) {
224+
int trunc_b = 0;
127225
if (len > (sizeof(vprintf_buffer) - 1)) {
128-
int trunc_b = len - (sizeof(vprintf_buffer) - 1);
226+
trunc_b = len - (sizeof(vprintf_buffer) - 1);
129227
log_router_debug_printf("Buffer too small, lost %d bytes\n", trunc_b);
130228
len = sizeof(vprintf_buffer) - 1;
131229
}
@@ -161,88 +259,13 @@ int esp_log_router_flash_vprintf(const char *format, va_list args)
161259
bool tag_match = (item->tag == NULL) || (tag_len > 0 && strncmp(tag_start, item->tag, tag_len) == 0 && item->tag[tag_len] == '\0');
162260

163261
if (level_match && tag_match && item->log_fp) {
164-
bool should_flush = false;
165-
166-
// Check if we need to flush due to threshold
167-
if ((item->buffer_pos + len) >= item->flush_threshold) {
168-
should_flush = true;
169-
log_router_debug_printf("Flush buffer due to threshold\n");
170-
}
262+
router_fwrite(vprintf_buffer, 1, len, item, now);
171263

172-
// Check if we need to flush due to timeout
173-
if ((now - item->last_flush_time) >= item->flush_timeout_ms) {
174-
should_flush = true;
175-
log_router_debug_printf("Flush buffer due to timeout\n");
264+
#if (CONFIG_LOG_ROUTER_APPEND_STRING_ON_TRUNCATE)
265+
if (trunc_b > 0) {
266+
router_fwrite(TRUNCATE_MESSAGE, 1, strlen(TRUNCATE_MESSAGE), item, now);
176267
}
177-
178-
// Flush buffer if needed
179-
if (should_flush) {
180-
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
181-
uint64_t flush_start_time = esp_timer_get_time();
182268
#endif
183-
esp_err_t flush_ret = esp_log_router_flush_buffer(item);
184-
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
185-
uint32_t flush_duration_us = esp_timer_get_time() - flush_start_time;
186-
log_router_debug_printf("Flush operation took %ums, file: %s\n", flush_duration_us / 1000, item->file_path);
187-
#endif
188-
if (flush_ret != ESP_OK) {
189-
log_router_debug_printf("Failed to flush buffer: %s\n", esp_err_to_name(flush_ret));
190-
// Flush failed, write directly to file
191-
size_t written = fwrite(vprintf_buffer, 1, len, item->log_fp);
192-
if (written != len) {
193-
log_router_debug_printf("Failed to write directly to file, written: %zu, expected: %d\n", written, len);
194-
// Try to seek to beginning and retry
195-
if (fseek(item->log_fp, 0, SEEK_SET) == 0 && ftruncate(fileno(item->log_fp), 0) == 0) {
196-
log_router_debug_printf("File truncated, retrying direct write\n");
197-
written = fwrite(vprintf_buffer, 1, len, item->log_fp);
198-
if (written != len) {
199-
log_router_debug_printf("Retry direct write also failed\n");
200-
continue;
201-
}
202-
} else {
203-
log_router_debug_printf("Failed to seek/truncate file for direct write\n");
204-
continue;
205-
}
206-
}
207-
fflush(item->log_fp);
208-
fsync(fileno(item->log_fp));
209-
continue; // Skip buffer write since we already wrote to file
210-
}
211-
// Flush successful, buffer is now empty, continue to buffer write
212-
}
213-
214-
// Try to add to buffer, if still too large, write directly to file
215-
if ((item->buffer_pos + len) < item->buffer_size) {
216-
memcpy(item->buffer + item->buffer_pos, vprintf_buffer, len);
217-
item->buffer_pos += len;
218-
} else {
219-
// Buffer is too small, write directly to file
220-
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
221-
uint64_t write_start_time = esp_timer_get_time();
222-
#endif
223-
size_t written = fwrite(vprintf_buffer, 1, len, item->log_fp);
224-
if (written != len) {
225-
log_router_debug_printf("Failed to write directly to file, written: %zu, expected: %d\n", written, len);
226-
// Try to seek to beginning and retry
227-
if (fseek(item->log_fp, 0, SEEK_SET) == 0 && ftruncate(fileno(item->log_fp), 0) == 0) {
228-
log_router_debug_printf("File truncated, retrying direct write\n");
229-
written = fwrite(vprintf_buffer, 1, len, item->log_fp);
230-
if (written != len) {
231-
log_router_debug_printf("Retry direct write also failed\n");
232-
continue;
233-
}
234-
} else {
235-
log_router_debug_printf("Failed to seek/truncate file for direct write\n");
236-
continue;
237-
}
238-
}
239-
fflush(item->log_fp);
240-
fsync(fileno(item->log_fp));
241-
#ifdef CONFIG_LOG_ROUTER_DEBUG_OUTPUT
242-
uint32_t write_duration_us = esp_timer_get_time() - write_start_time;
243-
log_router_debug_printf("Direct write took %ums, size: %d, file: %s\n", write_duration_us / 1000, len, item->file_path);
244-
#endif
245-
}
246269
}
247270
}
248271
}

0 commit comments

Comments
 (0)