diff --git a/README.md b/README.md index f8be073..eb51f27 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,25 @@ # 1. 介绍 -EasyLogger是一款超轻量级(ROM<1.6K, RAM<0.3k)、高性能的C日志库,非常适合对资源敏感的嵌入式软件。相比log4c、zlog这些知名的C日志库,EasyLogger的功能更加简单,提供给用户的接口更少,但上手会很快,也非常适合应用于小型的非嵌入式软件。EasyLogger主要特性如下: +EasyLogger是一款超轻量级(ROM<1.6K, RAM<0.3k)、高性能的C日志库,非常适合对资源敏感的嵌入式软件。相比log4c、zlog这些知名的C日志库,EasyLogger的功能更加简单,提供给用户的接口更少,但上手会很快,更多实用功能支持以插件形式进行动态扩展,非常适合应用于小型的非嵌入式软件。EasyLogger主要特性如下: -- 支持多种输出方式(终端、文件、串口、485、Flash...); +- 支持用户自定义输出方式(例如: 终端、文件、串口、485、Flash...); - 日志内容可包含级别、时间戳、线程、进程信息; - 日志输出被设计为线程安全的方式; - 支持多种操作系统([RT-Thread](http://www.rt-thread.org/)、UCOS、Linux、Windows...),也支持裸机平台; -- 日志支持 **RAW格式** ,可设定按 **标签** 进行过滤。 +- 日志支持 **RAW格式** ,可设定按 **标签** 进行过滤; +- 扩展性强,支持已插件形式扩展新功能。 > 名词解释: 1、RAW格式:未经过格式化的原始日志。 2、标签:在软件中可以按照文件、模块、功能等方面,对需要打印的日志设定标签,实现日志分类。 +EasyLogger目前支持的插件有: + +- 1. Flash Log: 使用[EasyFlash](https://github.com/armink/EasyFlash)库提供的无缝接口,可以把日志直接存储在Flash中。 + +后续我还会提供更多插件。也非常欢迎大家设计、开发更多实用插件和功能,一起来完善EasyLogger **([Github](https://github.com/armink/EasyLogger)|[OSChina](http://git.oschina.net/armink/EasyLogger)|[Coding](https://coding.net/u/armink/p/EasyLogger/git))** ,同时把它推广给更多有需要的朋友。 + # 2. 使用 ### 2.1 参数配置 @@ -72,7 +79,9 @@ EasyLogger拥有过滤方式、输出格式、输出开关这些属性。 ### 2.6 Demo -下图为在终端中输入命令来控制日志的输出及过滤器的设置,更加直观的展示了EasyLogger各项功能。 +### 2.6.1 核心功能 + +下图为在终端中输入命令来控制日志的输出及过滤器的设置,更加直观的展示了EasyLogger核心功能。 ![easylogger](https://raw.githubusercontent.com/armink/EasyLogger/master/docs/images/EasyLoggerDemo.gif) @@ -80,7 +89,7 @@ EasyLogger拥有过滤方式、输出格式、输出开关这些属性。 # 3. 后期 -- 1、Flash存储:在[EasyFlash](https://github.com/armink/EasyFlash)中增加日志存储、读取功能,让EasyLogger与其无缝对接。使日志可以更加容易的存储在 **非文件系统** 中,并具有历史日检索的功能; +- ~~1、Flash存储:在[EasyFlash](https://github.com/armink/EasyFlash)中增加日志存储、读取功能,让EasyLogger与其无缝对接。使日志可以更加容易的存储在 **非文件系统** 中,~~并具有历史日检索的功能; - 2、异步输出:目前日志输出与用户代码之间是同步的方式,这种方式虽然软件简单,也不存在日志覆盖的问题。但在输出速度较低的平台下,会由于增加日志功能,而降低软件运行速度。所以后期会增加 **异步输出** 方式,关键字过滤也会放到异步输出中去; - 3、日志助手:开发跨平台的日志助手,兼容Linux、Windows、Mac系统,打开助手即可查看、过滤(支持正则表达式)、排序、保存日志等,计划使用[NW.js](http://www.oschina.net/p/nwjs)框架; - 4、文件转档:文件系统下支持文件按容量转档,按时间区分; diff --git a/easylogger/inc/elog.h b/easylogger/inc/elog.h index d852a45..50b7d95 100644 --- a/easylogger/inc/elog.h +++ b/easylogger/inc/elog.h @@ -53,13 +53,13 @@ extern "C" { /* output filter's keyword max length */ #define ELOG_FILTER_KW_MAX_LEN 16 /* EasyLogger software version number */ -#define ELOG_SW_VERSION "0.05.25" +#define ELOG_SW_VERSION "0.06.09" /* EasyLogger assert for developer. */ #define ELOG_ASSERT(EXPR) \ if (!(EXPR)) \ { \ - elog_a("ELOG", "(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \ + elog_a("elog", "(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \ while (1); \ } @@ -75,6 +75,20 @@ typedef enum { ELOG_FMT_LINE = 1 << 7, /**< line number */ } ElogFmtIndex; +/* output log's filter */ +typedef struct { + uint8_t level; + char tag[ELOG_FILTER_TAG_MAX_LEN + 1]; + char keyword[ELOG_FILTER_KW_MAX_LEN + 1]; +} ElogFilter, *ElogFilter_t; + +/* easy logger */ +typedef struct { + ElogFilter filter; + size_t enabled_fmt_set; + bool output_enabled; +}EasyLogger, *EasyLogger_t; + /* EasyLogger error code */ typedef enum { ELOG_NO_ERR, @@ -82,6 +96,7 @@ typedef enum { /* elog.c */ ElogErrCode elog_init(void); +void elog_start(void); void elog_set_output_enabled(bool enabled); bool elog_get_output_enabled(void); void elog_set_fmt(size_t set); diff --git a/easylogger/inc/elog_flash.h b/easylogger/inc/elog_flash.h new file mode 100644 index 0000000..f0e84aa --- /dev/null +++ b/easylogger/inc/elog_flash.h @@ -0,0 +1,59 @@ +/* + * This file is part of the EasyLogger Library. + * + * Copyright (c) 2015, Armink, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Function: Is is an head file for flash log plugin. You can see all be called functions. + * Created on: 2015-06-05 + */ + +#ifndef __ELOG_FLASH_H__ +#define __ELOG_FLASH_H__ + +#include "elog.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* EasyLogger flash save plugin's using buffer mode */ +#define ELOG_FLASH_USING_BUF_MODE +/* EasyLogger flash save plugin's RAM buffer size */ +#define ELOG_FLASH_BUF_SIZE 1024 +/* EasyLogger flash save plugin's software version number */ +#define ELOG_FLASH_SW_VERSION "0.06.09" + +/* elog_flash.c */ +ElogErrCode elog_flash_init(void); +void elog_flash_outout_all(void); +void elog_flash_set_filter(uint8_t level,const char *tag,const char *keyword); +void elog_flash_write(const char *log, size_t size); +void elog_flash_clean(void); + +#ifdef ELOG_FLASH_USING_BUF_MODE +void elog_flash_flush(void); +#endif + +/* elog_port.c */ +void elog_flash_port_output(const char *output, size_t size); +void elog_flash_port_lock(void); +void elog_flash_port_unlock(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELOG_FLASH_H__ */ diff --git a/easylogger/port/elog_port.c b/easylogger/port/elog_port.c index 6780da4..5d6e623 100644 --- a/easylogger/port/elog_port.c +++ b/easylogger/port/elog_port.c @@ -21,6 +21,8 @@ */ #include "elog.h" +/* @note If you don't use flash log plugin, you can delete this include. */ +#include "elog_flash.h" /** * EasyLogger port initialize @@ -30,8 +32,8 @@ ElogErrCode elog_port_init(void) { ElogErrCode result = ELOG_NO_ERR; - //add your code here - + /* add your code here */ + return result; } @@ -39,38 +41,66 @@ ElogErrCode elog_port_init(void) { * output log port interface */ void elog_port_output(const char *output, size_t size) { - - //add your code here - + + /* add your code here */ + +} + +/** + * output flash saved log port interface + */ +void elog_flash_port_output(const char *output, size_t size) { + + /* If used flash log plugin, then you must implement this function. */ + } /** * output lock */ void elog_port_output_lock(void) { - - //add your code here - + + /* add your code here */ + } /** * output unlock */ void elog_port_output_unlock(void) { - - //add your code here - + + /* add your code here */ + } +/** + * flash log lock + */ +void elog_flash_port_lock(void) { + + /* If used flash log plugin, then you must implement this function. */ + +} + +/** + * flash log unlock + */ +void elog_flash_port_unlock(void) { + + /* If used flash log plugin, then you must implement this function. */ + +} + + /** * get current time interface * * @return current time */ const char *elog_port_get_time(void) { - - //add your code here - + + /* add your code here */ + } /** @@ -79,9 +109,9 @@ const char *elog_port_get_time(void) { * @return current process name */ const char *elog_port_get_p_info(void) { - - //add your code here - + + /* add your code here */ + } /** @@ -90,7 +120,7 @@ const char *elog_port_get_p_info(void) { * @return current thread name */ const char *elog_port_get_t_info(void) { - - //add your code here - + + /* add your code here */ + } diff --git a/easylogger/src/elog.c b/easylogger/src/elog.c index 8191172..9f264e2 100644 --- a/easylogger/src/elog.c +++ b/easylogger/src/elog.c @@ -25,26 +25,12 @@ #include #include -/* output log's filter */ -typedef struct { - uint8_t level; - char tag[ELOG_FILTER_TAG_MAX_LEN + 1]; - char keyword[ELOG_FILTER_KW_MAX_LEN + 1]; -} ElogFilter, *ElogFilter_t; - -/* easy logger */ -typedef struct { - ElogFilter filter; - size_t enabled_fmt_set; - bool output_enabled; -}EasyLogger, *EasyLogger_t; - /* EasyLogger object */ static EasyLogger elog; /* log buffer */ static char log_buf[ELOG_BUF_SIZE] = { 0 }; /* log tag */ -static const char *tag = "ELOG"; +static const char *tag = "elog"; /* level output info */ static const char *level_output_info[] = { "A/", @@ -68,15 +54,18 @@ ElogErrCode elog_init(void) { result = elog_port_init(); /* set level is ELOG_LVL_VERBOSE */ elog_set_filter_lvl(ELOG_LVL_VERBOSE); + + return result; +} + +/** + * EasyLogger start after initialize. + */ +void elog_start(void) { /* enable output */ elog_set_output_enabled(true); - - if (result == ELOG_NO_ERR) { - elog_d(tag, "EasyLogger V%s is initialize success.", ELOG_SW_VERSION); - } else { - elog_d(tag, "EasyLogger V%s is initialize fail.", ELOG_SW_VERSION); - } - return result; + /* show version */ + elog_i(tag, "EasyLogger V%s is initialize success.", ELOG_SW_VERSION); } /** diff --git a/easylogger/src/elog_flash.c b/easylogger/src/elog_flash.c new file mode 100644 index 0000000..975d0f4 --- /dev/null +++ b/easylogger/src/elog_flash.c @@ -0,0 +1,217 @@ +/* + * This file is part of the EasyLogger Library. + * + * Copyright (c) 2015, Armink, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Function: Save log to flash. Must use EasyFlash(https://github.com/armink/EasyFlash) library. + * Created on: 2015-06-05 + */ + +#include "elog_flash.h" +#include "flash.h" +#include +#include +#include + +#define log_a(...) elog_a("elog.flash", __VA_ARGS__) +#define log_e(...) elog_e("elog.flash", __VA_ARGS__) +#define log_w(...) elog_w("elog.flash", __VA_ARGS__) +#define log_i(...) elog_i("elog.flash", __VA_ARGS__) +#define log_d(...) elog_d("elog.flash", __VA_ARGS__) +#define log_v(...) elog_v("elog.flash", __VA_ARGS__) + +#ifdef ELOG_FLASH_USING_BUF_MODE +/* flash log buffer */ +static char log_buf[ELOG_FLASH_BUF_SIZE] = { 0 }; +/* current flash log buffer write position */ +static size_t cur_buf_size = 0; +#endif + +/* initialize OK flag */ +static bool init_ok = false; + +/** + * EasyLogger flash save plugin initialize. + * + * @return result + */ +ElogErrCode elog_flash_init(void) { + ElogErrCode result = ELOG_NO_ERR; + + /* buffer size must be word alignment */ + ELOG_ASSERT(ELOG_FLASH_BUF_SIZE % 4 == 0) + +#ifdef ELOG_FLASH_USING_BUF_MODE + /* initialize current flash log buffer write position */ + cur_buf_size = 0; +#endif + + /* initialize OK */ + init_ok = true; + + return result; +} + +/** + * Read and output all log which saved in flash. @note It will use filter. @see elog_flash_set_filter + */ +void elog_flash_outout_all(void) { + /* 128 bytes buffer */ + uint32_t buf[32] = { 0 }; + size_t log_total_size = flash_log_get_used_size(); + size_t buf_szie = sizeof(buf); + size_t read_size = 0, read_overage_size = 0; + + /* must be call this function after initialize OK */ + ELOG_ASSERT(init_ok); + /* lock flash log buffer */ + elog_flash_port_lock(); + /* Output all flash saved log. It will use filter */ + while (true) { + if (read_size + buf_szie < log_total_size) { + flash_log_read(read_size, buf, buf_szie); + elog_flash_port_output((const char*)buf, buf_szie); + read_size += buf_szie; + } else { + /* flash read is word alignment */ + if ((log_total_size - read_size) % 4 == 0) { + read_overage_size = 0; + } else { + read_overage_size = 4 - ((log_total_size - read_size) % 4); + } + flash_log_read(read_size, buf, log_total_size - read_size + read_overage_size); + elog_flash_port_output((const char*)buf, log_total_size - read_size); + //TODO CRLF Ҫͳһͷļ궨 + elog_flash_port_output("\r\n", 2); + break; + } + } + /* unlock flash log buffer */ + elog_flash_port_unlock(); +} + +/** + * Write log to flash. The flash write use buffer mode. + * + * @param log log + * @param size log size + */ +void elog_flash_write(const char *log, size_t size) { + +#ifdef ELOG_FLASH_USING_BUF_MODE + size_t write_size = 0, write_index = 0; +#else + size_t write_size_temp = 0; + FlashErrCode result = FLASH_NO_ERR; + /* write some '\r' for word alignment */ + char write_overage_c[4] = { '\r', '\r', '\r', '\r' }; +#endif + + /* must be call this function after initialize OK */ + ELOG_ASSERT(init_ok); + + /* lock flash log buffer */ + elog_flash_port_lock(); + +#ifdef ELOG_FLASH_USING_BUF_MODE + while (true) { + if (cur_buf_size + size > ELOG_FLASH_BUF_SIZE) { + write_size = ELOG_FLASH_BUF_SIZE - cur_buf_size; + memcpy(log_buf + cur_buf_size, log + write_index, write_size); + write_index += write_size; + size -= write_size; + cur_buf_size += write_size; + /* unlock flash log buffer */ + elog_flash_port_unlock(); + /* write all buffered log to flash, cur_buf_size will reset */ + elog_flash_flush(); + /* lock flash log buffer */ + elog_flash_port_lock(); + } else { + memcpy(log_buf + cur_buf_size, log + write_index, size); + cur_buf_size += size; + break; + } + } +#else + /* calculate the word alignment write size */ + write_size_temp = size / 4 * 4; + /* write log to flash */ + result = flash_log_write((uint32_t *) log, write_size_temp); + /* write last word alignment data */ + if ((result == FLASH_NO_ERR) && (write_size_temp != size)) { + memcpy(write_overage_c, log + write_size_temp, size - write_size_temp); + flash_log_write((uint32_t *) write_overage_c, 4); + } +#endif + + /* unlock flash log buffer */ + elog_flash_port_unlock(); +} + +#ifdef ELOG_FLASH_USING_BUF_MODE +/** + * write all buffered log to flash + */ +void elog_flash_flush(void) { + size_t write_overage_size = 0; + + /* must be call this function after initialize OK */ + ELOG_ASSERT(init_ok); + /* lock flash log buffer */ + elog_flash_port_lock(); + /* flash write is word alignment */ + if (cur_buf_size % 4 != 0) { + write_overage_size = 4 - (cur_buf_size % 4); + } + /* fill '\r' for word alignment */ + memset(log_buf + cur_buf_size, '\r', write_overage_size); + /* write all buffered log to flash */ + flash_log_write((uint32_t *) log_buf, cur_buf_size + write_overage_size); + /* reset position */ + cur_buf_size = 0; + /* unlock flash log buffer */ + elog_flash_port_unlock(); +} +#endif + +/** + * clean all log which in flash and ram buffer + */ +void elog_flash_clean(void) { + FlashErrCode clean_result = FLASH_NO_ERR; + + /* must be call this function after initialize OK */ + ELOG_ASSERT(init_ok); + /* lock flash log buffer */ + elog_flash_port_lock(); + /* clean all log which in flash */ + clean_result = flash_log_clean(); + +#ifdef ELOG_FLASH_USING_BUF_MODE + /* reset position */ + cur_buf_size = 0; +#endif + + /* unlock flash log buffer */ + elog_flash_port_unlock(); + + if(clean_result == FLASH_NO_ERR) { + log_i("All logs which in flash is clean OK."); + } else { + log_e("Clean logs which in flash has an error!"); + } +}