Skip to content

Commit 31f49ba

Browse files
Damian-Nordicjukkar
authored andcommitted
logging: rpc: get rid of global output buffer
1. Remove the global log output and output buffer from the nRF RPC logging backend. 2. Add helper functions to format a log message into a buffer, and align the backend to use these helpers. Thanks to these changes, it is possible to format log messages from multiple threads, which will be utilized in an upcoming PR. Additionally, even a large message can now be sent in a single RPC event. Signed-off-by: Damian Krolik <[email protected]>
1 parent 13c0c90 commit 31f49ba

File tree

2 files changed

+125
-65
lines changed

2 files changed

+125
-65
lines changed

subsys/logging/Kconfig

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ menuconfig LOG_BACKEND_RPC
3131

3232
if LOG_BACKEND_RPC
3333

34-
config LOG_BACKEND_RPC_BUFFER_SIZE
35-
int "nRF RPC logging backend buffer size"
36-
default 256
34+
config LOG_BACKEND_RPC_OUTPUT_BUFFER_SIZE
35+
int "Output buffer size"
36+
default 128
3737
help
38-
Defines the maximum log line length that can be sent to the log forwarder
39-
over nRF RPC without fragmentation.
38+
Defines the size of stack buffer that is used by the RPC logging backend
39+
while formatting a log message.
4040

4141
config LOG_BACKEND_RPC_CRASH_LOG
4242
bool "nRF RPC crash log"

subsys/logging/log_backend_rpc.c

Lines changed: 120 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@ static const char *const filtered_out_sources[] = {
3838
"NRF_RPC",
3939
};
4040

41+
static const uint32_t common_output_flags =
42+
LOG_OUTPUT_FLAG_TIMESTAMP | LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
43+
4144
static bool panic_mode;
4245
static uint32_t log_format = LOG_OUTPUT_TEXT;
43-
static enum log_rpc_level current_level;
4446
static enum log_rpc_level stream_level = LOG_RPC_LEVEL_NONE;
45-
static uint8_t log_output_buffer[CONFIG_LOG_BACKEND_RPC_BUFFER_SIZE];
4647

4748
/*
4849
* Verify that Zephyr logging level can be used as the nRF RPC logging level without translation.
@@ -89,29 +90,33 @@ static void crash_log_clear(void)
8990
crash_log_max_size = (size_t)rc - sizeof(crash_log_header_t);
9091
}
9192

92-
static void retain(const uint8_t *data, size_t length)
93+
static int output_to_retention(uint8_t *data, size_t length, void *output_ctx)
9394
{
9495
const struct device *const crash_log = CRASH_LOG_DEV;
96+
9597
crash_log_header_t header;
96-
int rc;
98+
size_t saved_length;
99+
100+
ARG_UNUSED(output_ctx);
97101

98102
if (crash_log_cur_size >= crash_log_max_size) {
99103
/* Crash log partition overflow. */
100-
return;
104+
goto out;
101105
}
102106

103-
length = MIN(length, crash_log_max_size - crash_log_cur_size);
107+
saved_length = MIN(length, crash_log_max_size - crash_log_cur_size);
104108

105-
rc = retention_write(crash_log, sizeof(header) + crash_log_cur_size, data, length);
106-
107-
if (rc) {
108-
return;
109+
if (retention_write(crash_log, sizeof(header) + crash_log_cur_size, data, saved_length)) {
110+
goto out;
109111
}
110112

111-
crash_log_cur_size += length;
113+
crash_log_cur_size += saved_length;
112114
header.size = crash_log_cur_size;
113115

114116
(void)retention_write(crash_log, 0, (const uint8_t *)&header, sizeof(header));
117+
118+
out:
119+
return (int)length;
115120
}
116121

117122
static void log_rpc_get_crash_log_handler(const struct nrf_rpc_group *group,
@@ -180,42 +185,105 @@ static void crash_log_clear(void)
180185
{
181186
}
182187

183-
static void retain(const uint8_t *data, size_t length)
188+
static int output_to_retention(uint8_t *data, size_t length, void *output_ctx)
184189
{
185190
ARG_UNUSED(data);
186191
ARG_UNUSED(length);
192+
ARG_UNUSED(output_ctx);
193+
194+
return (int)length;
187195
}
188196
#endif /* CONFIG_LOG_BACKEND_RPC_CRASH_LOG */
189197

190-
static void send(const uint8_t *data, size_t length)
198+
static void format_message(struct log_msg *msg, uint32_t flags, log_output_func_t output_func,
199+
void *output_ctx)
191200
{
192-
struct nrf_rpc_cbor_ctx ctx;
193-
194-
NRF_RPC_CBOR_ALLOC(&log_rpc_group, ctx, 4 + length);
195-
nrf_rpc_encode_uint(&ctx, current_level);
196-
nrf_rpc_encode_buffer(&ctx, data, length);
197-
nrf_rpc_cbor_evt_no_err(&log_rpc_group, LOG_RPC_EVT_MSG, &ctx);
201+
uint8_t output_buffer[CONFIG_LOG_BACKEND_RPC_OUTPUT_BUFFER_SIZE];
202+
struct log_output_control_block control_block = {.ctx = output_ctx};
203+
struct log_output output = {
204+
.func = output_func,
205+
.control_block = &control_block,
206+
.buf = output_buffer,
207+
.size = sizeof(output_buffer),
208+
};
209+
log_format_func_t log_formatter;
210+
211+
log_formatter = log_format_func_t_get(log_format);
212+
log_formatter(&output, msg, flags);
198213
}
199214

200-
static int flush(uint8_t *data, size_t length, void *context)
201-
{
202-
ARG_UNUSED(context);
215+
struct output_to_buf_ctx {
216+
uint8_t *out;
217+
size_t out_len;
218+
size_t total_len;
219+
};
203220

204-
if (panic_mode) {
205-
retain(data, length);
206-
} else {
207-
send(data, length);
221+
static int output_to_buf(uint8_t *data, size_t length, void *ctx)
222+
{
223+
struct output_to_buf_ctx *output_ctx = ctx;
224+
size_t saved_length;
225+
226+
if (output_ctx->out != NULL) {
227+
saved_length = MIN(length, output_ctx->out_len);
228+
memcpy(output_ctx->out, data, saved_length);
229+
output_ctx->out += saved_length;
230+
output_ctx->out_len -= saved_length;
208231
}
209232

210-
/*
211-
* Log output does not handle error codes gracefully, so pretend the buffer has been
212-
* flushed to move on and not enter an infinite loop.
213-
*/
233+
output_ctx->total_len += length;
214234

215235
return (int)length;
216236
}
217237

218-
LOG_OUTPUT_DEFINE(log_output_rpc, flush, log_output_buffer, sizeof(log_output_buffer));
238+
static size_t format_message_to_buf(struct log_msg *msg, uint32_t flags, uint8_t *out,
239+
size_t out_len)
240+
{
241+
struct output_to_buf_ctx output_ctx = {
242+
.out = out,
243+
.out_len = out_len,
244+
.total_len = 0,
245+
};
246+
247+
format_message(msg, flags, output_to_buf, &output_ctx);
248+
249+
return output_ctx.total_len;
250+
}
251+
252+
static void retain_message(struct log_msg *msg)
253+
{
254+
const uint32_t flags = common_output_flags | LOG_OUTPUT_FLAG_CRLF_LFONLY;
255+
256+
if (!IS_ENABLED(CONFIG_LOG_BACKEND_RPC_CRASH_LOG)) {
257+
return;
258+
}
259+
260+
format_message(msg, flags, output_to_retention, NULL);
261+
}
262+
263+
static void stream_message(struct log_msg *msg)
264+
{
265+
const uint32_t flags = common_output_flags | LOG_OUTPUT_FLAG_CRLF_NONE;
266+
267+
struct nrf_rpc_cbor_ctx ctx;
268+
size_t length;
269+
size_t max_length;
270+
271+
/* 1. Calculate the formatted message length to allocate a sufficient CBOR encode buffer */
272+
length = format_message_to_buf(msg, flags, NULL, 0);
273+
274+
NRF_RPC_CBOR_ALLOC(&log_rpc_group, ctx, 6 + length);
275+
nrf_rpc_encode_uint(&ctx, log_msg_get_level(msg));
276+
277+
/* 2. Format the message directly into the CBOR encode buffer. */
278+
if (zcbor_bstr_start_encode(ctx.zs)) {
279+
max_length = ctx.zs[0].payload_end - ctx.zs[0].payload_mut;
280+
length = format_message_to_buf(msg, flags, ctx.zs[0].payload_mut, max_length);
281+
ctx.zs[0].payload_mut += MIN(length, max_length);
282+
zcbor_bstr_end_encode(ctx.zs, NULL);
283+
}
284+
285+
nrf_rpc_cbor_evt_no_err(&log_rpc_group, LOG_RPC_EVT_MSG, &ctx);
286+
}
219287

220288
static const char *log_msg_source_name_get(struct log_msg *msg)
221289
{
@@ -243,26 +311,12 @@ static bool starts_with(const char *str, const char *prefix)
243311
return strncmp(str, prefix, strlen(prefix)) == 0;
244312
}
245313

246-
static void process(const struct log_backend *const backend, union log_msg_generic *msg)
314+
static void process(const struct log_backend *const backend, union log_msg_generic *msg_generic)
247315
{
248-
const log_format_func_t log_formatter = log_format_func_t_get(log_format);
249-
const char *source_name = log_msg_source_name_get(&msg->log);
250-
uint32_t flags = LOG_OUTPUT_FLAG_TIMESTAMP | LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
251-
enum log_rpc_level level = (enum log_rpc_level)log_msg_get_level(&msg->log);
252-
enum log_rpc_level max_level = stream_level;
253-
254-
/*
255-
* Panic mode: logs are appended to the buffer in retained RAM, so include LF characters.
256-
* Otherwise: if nRF RPC group is ready, logs are sent in separate messages, so skip LFs.
257-
*/
258-
if (panic_mode) {
259-
flags |= LOG_OUTPUT_FLAG_CRLF_LFONLY;
260-
max_level = LOG_RPC_LEVEL_DBG;
261-
} else if (NRF_RPC_GROUP_STATUS(log_rpc_group)) {
262-
flags |= LOG_OUTPUT_FLAG_CRLF_NONE;
263-
} else {
264-
return;
265-
}
316+
struct log_msg *msg = &msg_generic->log;
317+
const char *source_name = log_msg_source_name_get(msg);
318+
enum log_rpc_level level = (enum log_rpc_level)log_msg_get_level(msg);
319+
enum log_rpc_level max_level;
266320

267321
if (source_name != NULL) {
268322
for (size_t i = 0; i < ARRAY_SIZE(filtered_out_sources); i++) {
@@ -272,14 +326,20 @@ static void process(const struct log_backend *const backend, union log_msg_gener
272326
}
273327
}
274328

275-
/*
276-
* The "max_level != LOG_RPC_LEVEL_NONE" condition seems redundant but is neeed because log
277-
* messages can be generated without specifying the level. Such messages should still be
278-
* rejected if the maximum level is LOG_RPC_LEVEL_NONE.
279-
*/
329+
if (panic_mode) {
330+
retain_message(msg);
331+
return;
332+
}
333+
334+
max_level = stream_level;
335+
280336
if (max_level != LOG_RPC_LEVEL_NONE && level <= max_level) {
281-
current_level = level;
282-
log_formatter(&log_output_rpc, &msg->log, flags);
337+
/*
338+
* The "max_level != LOG_RPC_LEVEL_NONE" condition seems redundant but is in fact
339+
* needed, because a log message can be generated with the level NONE, and such
340+
* a message should also be discarded if the configured maximum level is NONE.
341+
*/
342+
stream_message(msg);
283343
}
284344
}
285345

@@ -303,9 +363,9 @@ static void dropped(const struct log_backend *const backend, uint32_t cnt)
303363

304364
/*
305365
* Due to an issue in Zephyr logging subsystem (see upstream PR 78145), this function
306-
* may be called more often than the configured periodicity (1000ms by default), which
307-
* might cause sending RPC events to the RPC client indefinitely, wasting the bandwidth
308-
* of the RPC communication.
366+
* may be called more often than the configured periodicity (1000ms by default).
367+
* This might cause sending excessively many RPC events to the RPC client, which would
368+
* waste the RCP transport's bandwidth.
309369
*
310370
* For this reason, do not report the dropped log messages until this issue is fixed.
311371
*/

0 commit comments

Comments
 (0)