zephyr/subsys/shell/shell_log_backend.c
Krzysztof Chruscinski b467de5849 shell: Add dropping of expired messages
Log message get timestamp when being added to shell log message queue.
When adding to log message queue timeouts then all messages added
before timeout are dropped.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
2018-12-19 14:37:00 +01:00

206 lines
4.5 KiB
C

/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <shell/shell_log_backend.h>
#include <shell/shell.h>
#include "shell_ops.h"
#include <logging/log_ctrl.h>
int shell_log_backend_output_func(u8_t *data, size_t length, void *ctx)
{
shell_print_stream(ctx, data, length);
return length;
}
void shell_log_backend_enable(const struct shell_log_backend *backend,
void *ctx, u32_t init_log_level)
{
log_backend_enable(backend->backend, ctx, init_log_level);
log_output_ctx_set(backend->log_output, ctx);
backend->control_block->cnt = 0;
backend->control_block->state = SHELL_LOG_BACKEND_ENABLED;
}
static struct log_msg *msg_from_fifo(const struct shell_log_backend *backend)
{
struct shell_log_backend_msg msg;
int err;
err = k_msgq_get(backend->msgq, &msg, K_NO_WAIT);
return (err == 0) ? msg.msg : NULL;
}
static void fifo_flush(const struct shell_log_backend *backend)
{
struct log_msg *msg;
/* Flush log messages. */
while ((msg = msg_from_fifo(backend)) != NULL) {
log_msg_put(msg);
}
}
static void flush_expired_messages(const struct shell *shell)
{
int err;
struct shell_log_backend_msg msg;
struct k_msgq *msgq = shell->log_backend->msgq;
u32_t timeout = shell->log_backend->timeout;
u32_t now = k_uptime_get_32();
while (1) {
err = k_msgq_peek(msgq, &msg);
if (err == 0 && ((now - msg.timestamp) > timeout)) {
(void)k_msgq_get(msgq, &msg, K_NO_WAIT);
log_msg_put(msg.msg);
if (IS_ENABLED(CONFIG_SHELL_STATS)) {
shell->stats->log_lost_cnt++;
}
} else {
break;
}
}
}
static void msg_to_fifo(const struct shell *shell,
struct log_msg *msg)
{
int err;
struct shell_log_backend_msg t_msg = {
.msg = msg,
.timestamp = k_uptime_get_32()
};
err = k_msgq_put(shell->log_backend->msgq, &t_msg,
shell->log_backend->timeout);
switch (err) {
case 0:
break;
case -EAGAIN:
case -ENOMSG:
{
flush_expired_messages(shell);
err = k_msgq_put(shell->log_backend->msgq, &msg, K_NO_WAIT);
if (err) {
/* Unexpected case as we just freed one element and
* there is no other context that puts into the msgq.
*/
__ASSERT_NO_MSG(0);
}
break;
}
default:
/* Other errors are not expected. */
__ASSERT_NO_MSG(0);
break;
}
}
void shell_log_backend_disable(const struct shell_log_backend *backend)
{
fifo_flush(backend);
log_backend_disable(backend->backend);
backend->control_block->state = SHELL_LOG_BACKEND_DISABLED;
}
static void msg_process(const struct log_output *log_output,
struct log_msg *msg)
{
u32_t flags = LOG_OUTPUT_FLAG_LEVEL |
LOG_OUTPUT_FLAG_TIMESTAMP |
LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP;
if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) {
flags |= LOG_OUTPUT_FLAG_COLORS;
}
log_output_msg_process(log_output, msg, flags);
log_msg_put(msg);
}
bool shell_log_backend_process(const struct shell_log_backend *backend)
{
const struct shell *shell =
(const struct shell *)backend->backend->cb->ctx;
struct log_msg *msg = msg_from_fifo(backend);
if (!msg) {
return false;
}
msg_process(shell->log_backend->log_output, msg);
return true;
}
static void put(const struct log_backend *const backend, struct log_msg *msg)
{
const struct shell *shell = (const struct shell *)backend->cb->ctx;
struct k_poll_signal *signal;
log_msg_get(msg);
switch (shell->log_backend->control_block->state) {
case SHELL_LOG_BACKEND_ENABLED:
msg_to_fifo(shell, msg);
if (IS_ENABLED(CONFIG_MULTITHREADING)) {
signal = &shell->ctx->signals[SHELL_SIGNAL_LOG_MSG];
k_poll_signal_raise(signal, 0);
}
break;
case SHELL_LOG_BACKEND_PANIC:
msg_process(shell->log_backend->log_output, msg);
break;
case SHELL_LOG_BACKEND_DISABLED:
/* fall through */
/* no break */
default:
/* Discard message. */
log_msg_put(msg);
}
}
static void panic(const struct log_backend *const backend)
{
const struct shell *shell = (const struct shell *)backend->cb->ctx;
int err;
err = shell->iface->api->enable(shell->iface, true);
if (err == 0) {
shell->log_backend->control_block->state =
SHELL_LOG_BACKEND_PANIC;
/* Move to the start of next line. */
shell_multiline_data_calc(&shell->ctx->vt100_ctx.cons,
shell->ctx->cmd_buff_pos,
shell->ctx->cmd_buff_len);
shell_op_cursor_vert_move(shell, -1);
shell_op_cursor_horiz_move(shell,
-shell->ctx->vt100_ctx.cons.cur_x);
while (shell_log_backend_process(shell->log_backend)) {
/* empty */
}
} else {
shell_log_backend_disable(shell->log_backend);
}
}
const struct log_backend_api log_backend_shell_api = {
.put = put,
.panic = panic
};