From 179f2dacfb2f38fbb11a02f54f0768ac8fc6d2e0 Mon Sep 17 00:00:00 2001 From: "ahreum.jeong" Date: Tue, 2 May 2017 11:37:50 +0900 Subject: [PATCH] Update logm module - Change logics of buffer usage - Add tash commands for logm configuration in run-time - Add prepending timestamp to messages --- os/include/tinyara/logm.h | 10 +++++ os/logm/Kconfig | 36 ++++++++--------- os/logm/Makefile | 11 +++-- os/logm/logm.c | 76 +++++++++++++++++++++++++---------- os/logm/logm.h | 47 ++++++++++++++++++++-- os/logm/logm_get.c | 42 +++++++++++++++++++ os/logm/logm_init.c | 4 ++ os/logm/logm_process.c | 91 +++++++++++++++++++++++++++++++++-------- os/logm/logm_set.c | 43 ++++++++++++++++++++ os/logm/logm_tashcmds.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 397 insertions(+), 63 deletions(-) create mode 100644 os/logm/logm_get.c create mode 100644 os/logm/logm_set.c create mode 100644 os/logm/logm_tashcmds.c diff --git a/os/include/tinyara/logm.h b/os/include/tinyara/logm.h index b2c77d4..98ae4a4 100644 --- a/os/include/tinyara/logm.h +++ b/os/include/tinyara/logm.h @@ -36,6 +36,14 @@ enum logm_loglevels_e { LOGM_OFF /* Is this needed? */ }; +enum logm_param_type_e { + LOGM_BUFSIZE, + LOGM_NEW_BUFSIZE, + LOGM_INTERVAL, + LOGM_PRIORITY + /* This would grow later */ +}; + #undef EXTERN #if defined(__cplusplus) #define EXTERN extern "C" @@ -48,6 +56,8 @@ extern "C" void logm_start(void); int logm_internal(int priority, const char *fmt, va_list valst); int logm(int flag, int mod, int priority, const char *fmt, ...); +int logm_set(enum logm_param_type_e type, int value); +int logm_get(enum logm_param_type_e type, void* value); #undef EXTERN #if defined(__cplusplus) diff --git a/os/logm/Kconfig b/os/logm/Kconfig index 0572f6e..7480992 100644 --- a/os/logm/Kconfig +++ b/os/logm/Kconfig @@ -19,25 +19,25 @@ config SYSLOG2LOGM bool "Route all syslogs through logm" default y -config LOGM_BUFFER_COUNT - int "Number of buffers to store log messages" - default 80 +config LOGM_TIMESTAMP + bool "Prepend timestamp to message" + default n + +config LOGM_BUFFER_SIZE + int "Logm Buffer size" + default 10240 ---help--- - This is the number of messages that can - be queued untill logm task start executing - and start pumping the messages out. - logm would drop messages if buffers are - not sufficient.It depends on logm task - priority, how frequently messages are - written by modules and sleep duration of - logm task which is 1 second now. - -config LOGM_MAX_MSG_LENGTH - int "Maximum msg length for each message" - default 64 + Logm buffer size (default : 10KB) + This value should be sufficient to avoid buffer overflow. + If buffer overflow happens, some messages would be dropped. + +config LOGM_PRINT_INTERVAL + int "Interval for flusing logm buffer (ms)" + default 1000 ---help--- - Each message through logm would be truncated - for this length. + Logm queues messsages for several seconds and then spits out. + This value decides how frequently buffer is flushed. + The smaller this value is, the more frequent messages are shown. config LOGM_TASK_PRIORITY int "Logm Task priority" @@ -45,7 +45,7 @@ config LOGM_TASK_PRIORITY config LOGM_TASK_STACKSIZE int "Logm Task stack size" - default 2048 + default 1024 config LOGM_TEST bool "Test code for logger module " diff --git a/os/logm/Makefile b/os/logm/Makefile index 8260c44..c78ad66 100644 --- a/os/logm/Makefile +++ b/os/logm/Makefile @@ -22,11 +22,14 @@ ASRCS = ifeq ($(CONFIG_LOGM),y) CSRCS += logm_init.c logm_process.c logm.c +CSRCS += logm_get.c logm_set.c +ifeq ($(CONFIG_TASH),y) +CSRCS += logm_tashcmds.c endif - ifeq ($(CONFIG_LOGM_TEST),y) CSRCS += logm_test.c endif +endif DEPPATH = --dep-path . VPATH = . @@ -41,13 +44,13 @@ BIN = liblogm$(LIBEXT) all: $(BIN) $(AOBJS): %$(OBJEXT): %.S - $(call ASSEMBLE, $<, $@) + $(call ASSEMBLE, $<, $(notdir $@)) $(COBJS): %$(OBJEXT): %.c - $(call COMPILE, $<, $@) + $(call COMPILE, $<, $(notdir $@)) $(BIN): $(OBJS) - $(call ARCHIVE, $@, $(OBJS)) + $(call ARCHIVE, $@, $(notdir $(OBJS))) .depend: Makefile $(SRCS) $(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep diff --git a/os/logm/logm.c b/os/logm/logm.c index 0e3a28a..59c77a1 100644 --- a/os/logm/logm.c +++ b/os/logm/logm.c @@ -24,52 +24,86 @@ #include #include #include +#include #ifdef CONFIG_ARCH_LOWPUTC #include #endif - +#ifdef CONFIG_LOGM_TIMESTAMP +#include +#endif #include "logm.h" -/* An additional line is for logm buffer overflow message */ -char g_logm_rsvbuf[LOGM_RSVBUF_COUNT + 1][LOGM_MAX_MSG_LEN]; -int g_logm_head; -int g_logm_tail; -int g_logm_count; +volatile int g_logm_head; +volatile int g_logm_tail; +volatile int g_logm_available; +volatile int g_logm_enqueued_count; +volatile int g_logm_dropmsg_count; +volatile int g_logm_overflow_offset; + +static void logm_putc(FAR struct lib_outstream_s *this, int ch) +{ + if (this->nput < g_logm_available - 1) { + g_logm_rsvbuf[(g_logm_tail + this->nput++) % logm_bufsize] = ch; + } +} + +static void logm_initstream(FAR struct lib_outstream_s *outstream) +{ + outstream->put = logm_putc; +#ifdef CONFIG_STDIO_LINEBUFFER + outstream->flush = lib_noflush; +#endif + outstream->nput = 0; +} /* logm_internal hook for syslog & printfs */ int logm_internal(int priority, const char *fmt, va_list ap) { irqstate_t flags; int ret = 0; + struct lib_outstream_s strm; +#ifdef CONFIG_LOGM_TIMESTAMP + struct timespec ts; +#endif - if (g_logm_isready && !up_interrupt_context()) { + if (LOGM_STATUS(LOGM_READY) && !LOGM_STATUS(LOGM_BUFFER_RESIZE_REQ) && !up_interrupt_context()) { flags = irqsave(); - if (g_logm_count < LOGM_RSVBUF_COUNT) { - ret = vsnprintf((char *)&g_logm_rsvbuf[g_logm_tail], LOGM_MAX_MSG_LEN, fmt, ap); - } else if (g_logm_count == LOGM_RSVBUF_COUNT) { - ret = vsnprintf((char *)&g_logm_rsvbuf[g_logm_tail], LOGM_MAX_MSG_LEN, "LOGM: Buffer Overflow dropping messages\n", ap); - } else { + if (LOGM_STATUS(LOGM_BUFFER_OVERFLOW)) { + g_logm_dropmsg_count++; irqrestore(flags); return 0; } - /* choose a available buffer */ - - if (ret >= LOGM_MAX_MSG_LEN - 1) { - g_logm_rsvbuf[g_logm_tail][LOGM_MAX_MSG_LEN - 1] = '\n'; + if (g_logm_available <= 0) { + LOGM_STATUS_SET(LOGM_BUFFER_OVERFLOW); + g_logm_dropmsg_count = 1; + g_logm_overflow_offset = g_logm_tail; + irqrestore(flags); + return 0; } - g_logm_tail += 1; - if (g_logm_tail >= (LOGM_RSVBUF_COUNT + 1)) { - g_logm_tail -= (LOGM_RSVBUF_COUNT + 1) ; + + /* Initializes a stream for use with logm buffer */ + logm_initstream(&strm); + +#ifdef CONFIG_LOGM_TIMESTAMP + /* Get the current time and prepend timestamp to message */ + if (clock_systimespec(&ts) == OK) { + (void)lib_sprintf((FAR struct lib_outstream_s *)&strm, "[%4d.%4d] ", ts.tv_sec, ts.tv_nsec / 100000); } - g_logm_count++; +#endif + ret = lib_vsprintf(&strm, fmt, ap); + g_logm_rsvbuf[(g_logm_tail + ret) % logm_bufsize] = '\0'; + + /* set g_logm_tail for next entered message */ + g_logm_tail = (g_logm_tail + ret + 1) % logm_bufsize; + g_logm_available -= (ret + 1); + g_logm_enqueued_count++; irqrestore(flags); } else { /* Low Output: Sytem is not yet completely ready or this is called from interrupt handler */ #ifdef CONFIG_ARCH_LOWPUTC - struct lib_outstream_s strm; lib_lowoutstream(&strm); ret = lib_vsprintf(&strm, fmt, ap); #endif diff --git a/os/logm/logm.h b/os/logm/logm.h index 9d56d4d..802ae3f 100644 --- a/os/logm/logm.h +++ b/os/logm/logm.h @@ -25,11 +25,40 @@ /**************************************************************************** * Preprocessor Definitions ****************************************************************************/ -#define LOGM_RSVBUF_COUNT CONFIG_LOGM_BUFFER_COUNT #define LOGM_TASK_PRORITY CONFIG_LOGM_TASK_PRIORITY #define LOGM_TASK_STACKSIZE CONFIG_LOGM_TASK_STACKSIZE -#define LOGM_MAX_MSG_LEN CONFIG_LOGM_MAX_MSG_LENGTH #define LOGM_PRINTERR_AND_RETURN() do { dbg("LOGM Launch Failed \n"); return; } while (0) +#ifdef LOGM_DEBUG +#define lmdbg(format, ...) printf(format, ##__VA_ARGS__) +#else +#define lmdbg(format, ...) +#endif + +#ifdef CONFIG_LOGM_BUFFER_SIZE +#define LOGM_BUFFER_SIZE CONFIG_LOGM_BUFFER_SIZE +#elif defined(CONFIG_LOGM_BUFFER_COUNT) && defined(CONFIG_LOGM_MAX_MSG_LENGTH) +#define LOGM_BUFFER_SIZE CONFIG_LOGM_BUFFER_COUNT * CONFIG_LOGM_MAX_MSG_LENGTH +#else +#define LOGM_BUFFER_SIZE (10240) +#endif + +#ifdef CONFIG_LOGM_PRINT_INTERVAL +#define LOGM_PRINT_INTERVAL CONFIG_LOGM_PRINT_INTERVAL +#else +#define LOGM_PRINT_INTERVAL (1000) +#endif + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +#define LOGM_READY BIT(0) +#define LOGM_BUFFER_RESIZE_REQ BIT(1) +#define LOGM_BUFFER_OVERFLOW BIT(2) + +#define LOGM_STATUS(a) (logm_status & (a)) +#define LOGM_STATUS_SET(a) (logm_status |= (a)) +#define LOGM_STATUS_CLEAR(a) (logm_status &= ~(a)) /**************************************************************************** * Private Declarations @@ -45,12 +74,24 @@ extern "C" { #define EXTERN extern #endif -EXTERN volatile int g_logm_isready; +EXTERN volatile int g_logm_head; +EXTERN volatile int g_logm_tail; +EXTERN volatile int g_logm_available; +EXTERN volatile int g_logm_enqueued_count; +EXTERN volatile int g_logm_overflow_offset; +EXTERN volatile int g_logm_dropmsg_count; +EXTERN char *volatile g_logm_rsvbuf; +EXTERN volatile int logm_bufsize; +EXTERN volatile int new_logm_bufsize; +EXTERN volatile uint8_t logm_status; +EXTERN volatile int logm_print_interval; /************************************************************************************ * Private Function Prototypes ************************************************************************************/ int logm_task(int argc, char *argv[]); +void logm_register_tashcmds(void); +static int logm_tash(int argc, char **args); #undef EXTERN #if defined(__cplusplus) diff --git a/os/logm/logm_get.c b/os/logm/logm_get.c new file mode 100644 index 0000000..3e248e1 --- /dev/null +++ b/os/logm/logm_get.c @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * Copyright 2016 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ +#include +#include "logm.h" + +volatile int new_logm_bufsize = 0; + +/* This will be moved to upper layer or changed for protected build */ +/* Refer logm_param_type_e for getparam values */ +int logm_get(enum logm_param_type_e type, void *value) +{ + switch (type) { + case LOGM_BUFSIZE: + *((int *)value) = logm_bufsize; + break; + case LOGM_INTERVAL: + *((int *)value) = (int)(logm_print_interval / 1000); + break; + case LOGM_NEW_BUFSIZE: + *((int *)value) = new_logm_bufsize; + break; + default: + break; + } + + return 0; // for now, to keep compiler happy +} diff --git a/os/logm/logm_init.c b/os/logm/logm_init.c index 1e4b6a2..8c117f5 100644 --- a/os/logm/logm_init.c +++ b/os/logm/logm_init.c @@ -36,4 +36,8 @@ void logm_start(void) if (!g_logm_tid) { LOGM_PRINTERR_AND_RETURN(); } + + /* Need to add a cofig variable */ + logm_register_tashcmds(); + } diff --git a/os/logm/logm_process.c b/os/logm/logm_process.c index 0228879..7e1d357 100644 --- a/os/logm/logm_process.c +++ b/os/logm/logm_process.c @@ -17,39 +17,96 @@ ****************************************************************************/ #include #include +#include +#include +#include #include +#include #include "logm.h" -volatile int g_logm_isready; -extern char g_logm_rsvbuf[][LOGM_MAX_MSG_LEN]; -extern int g_logm_head; -extern int g_logm_tail; -extern int g_logm_count; +volatile int logm_bufsize = LOGM_BUFFER_SIZE; +volatile int logm_print_interval = LOGM_PRINT_INTERVAL * 1000; +char *volatile g_logm_rsvbuf = NULL; +volatile uint8_t logm_status; -int logm_task(int argc, char *argv[]) +static int logm_change_bufsize(void) { - (void)argc; - (void)argv; + int buflen; + + /* Get new values */ + logm_get(LOGM_NEW_BUFSIZE, &buflen); + + /* Keep using old size because of invalid parameter */ + if (buflen < 0) { + LOGM_STATUS_CLEAR(LOGM_BUFFER_RESIZE_REQ); + return 0; + } + + /* Realloc new buffer with new length */ + g_logm_rsvbuf = (char *)realloc(g_logm_rsvbuf, buflen); + if (!g_logm_rsvbuf) { + return -1; + } + memset(g_logm_rsvbuf, 0, buflen); + lmdbg("logm new malloced address is 0x%x\n", g_logm_rsvbuf); + + /* Reinitialize all */ g_logm_head = 0; g_logm_tail = 0; - g_logm_count = 0; + logm_bufsize = buflen; + g_logm_available = buflen; + g_logm_enqueued_count = 0; + g_logm_dropmsg_count = 0; + g_logm_overflow_offset = -1; + + LOGM_STATUS_CLEAR(LOGM_BUFFER_RESIZE_REQ); // finish + + return 0; +} + +int logm_task(int argc, char *argv[]) +{ + int ret = 0; + irqstate_t flags; + + g_logm_rsvbuf = (char *)malloc(logm_bufsize); + memset(g_logm_rsvbuf, 0, logm_bufsize); + /* Now logm is ready */ - g_logm_isready = 1; + LOGM_STATUS_SET(LOGM_READY); + g_logm_available = logm_bufsize; #ifdef CONFIG_LOGM_TEST logmtest_init(); #endif while (1) { - while (g_logm_count > 0) { - fputs(g_logm_rsvbuf[g_logm_head], stdout); - g_logm_head += 1; - if (g_logm_head >= (LOGM_RSVBUF_COUNT + 1)) { - g_logm_head -= (LOGM_RSVBUF_COUNT + 1); + while (g_logm_enqueued_count > 0) { + ret = 0; + while (*(g_logm_rsvbuf + (g_logm_head + ret) % logm_bufsize)) { + fputc(g_logm_rsvbuf[(g_logm_head + ret++) % logm_bufsize], stdout); } - g_logm_count--; + g_logm_head = (g_logm_head + ret + 1) % logm_bufsize; + g_logm_available += (ret + 1); + + g_logm_enqueued_count--; + + if (LOGM_STATUS(LOGM_BUFFER_OVERFLOW)) { + LOGM_STATUS_CLEAR(LOGM_BUFFER_OVERFLOW); + } + + if (g_logm_overflow_offset >= 0 && g_logm_overflow_offset == g_logm_head) { + fprintf(stdout, "\n[LOGM BUFFER OVERFLOW] %d messages are dropped\n", g_logm_dropmsg_count); + g_logm_overflow_offset = -1; + } + } + + if (LOGM_STATUS(LOGM_BUFFER_RESIZE_REQ)) { + flags = irqsave(); + logm_change_bufsize(); + irqrestore(flags); } - sleep(1); + usleep(logm_print_interval); } return 0; // Just to make compiler happy } diff --git a/os/logm/logm_set.c b/os/logm/logm_set.c new file mode 100644 index 0000000..1d5dca0 --- /dev/null +++ b/os/logm/logm_set.c @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * Copyright 2016 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ +#include +#include +#include "logm.h" + +/* This will be moved to upper layer or changed for protected build */ +/* for setparam types, refer logm_param_type_e */ +int logm_set(enum logm_param_type_e type, int value) +{ + switch (type) { + case LOGM_BUFSIZE: + /* Buffer size should be adjusted to multiples of 4 */ + logm_bufsize = (value + 3) & (~0x3); + break; + case LOGM_INTERVAL: + logm_print_interval = value * 1000; + break; + case LOGM_NEW_BUFSIZE: + /* Buffer size should be adjusted to multiples of 4 */ + new_logm_bufsize = (value + 3) & (~0x3); + break; + default: + break; + } + + return 0; // for now, to keep compiler happy +} diff --git a/os/logm/logm_tashcmds.c b/os/logm/logm_tashcmds.c new file mode 100644 index 0000000..cf8d0f4 --- /dev/null +++ b/os/logm/logm_tashcmds.c @@ -0,0 +1,100 @@ +/**************************************************************************** + * + * Copyright 2016 Samsung Electronics All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + * + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "logm.h" + +const static tash_cmdlist_t logm_tashmds[] = { + {"logm", logm_tash, TASH_EXECMD_SYNC}, + {NULL, NULL, 0} +}; + +void logm_register_tashcmds(void) +{ + tash_cmdlist_install(logm_tashmds); +} + +static void logm_usage(void) +{ + fprintf(stdout, "[LOGM USAGE]\n"); + fprintf(stdout, "usage: logm [-b ] [-i