Giter Site home page Giter Site logo

armink / easylogger Goto Github PK

View Code? Open in Web Editor NEW
3.5K 236.0 1.1K 3.42 MB

An ultra-lightweight(ROM<1.6K, RAM<0.3k), high-performance C/C++ log library. | 一款超轻量级(ROM<1.6K, RAM<0.3k)、高性能的 C/C++ 日志库

License: MIT License

C 100.00%
logger c high-performance lightweight log logging

easylogger's Introduction

EasyLogger


1. 介绍

EasyLogger 是一款超轻量级(ROM<1.6K, RAM<0.3K)、高性能的 C/C++ 日志库,非常适合对资源敏感的软件项目,例如: IoT 产品、可穿戴设备、智能家居等等。相比 log4c、zlog 这些知名的 C/C++ 日志库, EasyLogger 的功能更加简单,提供给用户的接口更少,但上手会很快,更多实用功能支持以插件形式进行动态扩展。

1.1 主要特性

  • 支持用户自定义输出方式(例如:终端、文件、数据库、串口、485、Flash...);
  • 日志内容可包含级别、时间戳、线程信息、进程信息等;
  • 日志输出被设计为线程安全的方式,并支持 异步输出缓冲输出 模式;
  • 支持多种操作系统(RT-Thread、UCOS、Linux、Windows、Nuttx...),也支持裸机平台;
  • 日志支持 RAW格式 ,支持 hexdump
  • 支持按 标签级别关键词 进行动态过滤;
  • 各级别日志支持不同颜色显示;
  • 扩展性强,支持以插件形式扩展新功能。

名词解释:

  • 1、RAW格式:未经过格式化的原始日志。
  • 2、标签:在软件中可以按照文件、模块、功能等方面,对需要打印的日志设定标签,实现日志分类。

1.2 插件

  • 1、Flash:使用 EasyFlash 库提供的Flash操作接口,无需文件系统,直接将日志存储在 Flash 中。
  • 2、File:支持文件转档、文件循环保存等与文件日志输出相关功能。
  • 3、敬请期待……

1.3 Star & Fork

后续我还会提供更多插件。也非常欢迎大家设计、开发更多实用插件和功能,一起来完善 EasyLogger (Github|OSChina|Coding) 。如果觉得这个开源项目很赞,可以点击项目主页 右上角的 Star ,同时把它推荐给更多有需要的朋友。

2. 使用

2.1 参数配置

EasyLogger 拥有过滤方式、输出格式、输出开关这些属性。

  • 过滤方式支持按照标签、级别、关键词进行过滤;
  • 可以动态的开启/关闭日志的输出;
  • 可设定动态和静态的输出级别
    • 静态:一级开关,通过宏定义,在编译阶段使用;
    • 动态:二级开关,通过API接口,在运行阶段使用。

注:目前参数配置及输出方式都是单例模式,即全局只支持一种配置方式。此模式下,软件会较为简单,但是无法支持复杂的输出方式。

2.2 输出级别

参考 Android Logcat ,级别最高为 0(Assert) ,最低为 5(Verbose) 。

0.[A]:断言(Assert)
1.[E]:错误(Error)
2.[W]:警告(Warn)
3.[I]:信息(Info)
4.[D]:调试(Debug)
5.[V]:详细(Verbose)

2.2.1 输出缤纷多彩的日志

各个级别日志默认颜色效果如下。用户也可以根据自己的喜好,在 elog_cfg.h 对各个级别日志的颜色及字体风格进行单独设置。

TextColor

2.3 输出过滤

支持按照 级别、标签及关键词 进行过滤。日志内容较多时,使用过滤功能可以更快定位日志,保证日志的可读性。更多的过滤功能设置方法及细节请阅读\docs\zh\api\kernel.md文档

注:RAW格式、hexdump 格式日志不支持标签、关键词过滤

2.4 输出格式

输出格式支持:级别、时间、标签、进程信息、线程信息、文件路径、行号、方法名。每种优先级别可以独立设置输出格式。

2.5 输出方式

通过用户的移植,可以支持任何一种输出方式。只不过对于某种输出方式可能引入的新功能,需要通过插件实现,例如:文件转存,检索Flash日志等等。后期会有更多的插件开源出来。下面简单对比下部分输出方式使用场景:

  • 终端:方便用户动态查看,不具有存储功能;
  • 文件与Flash:都具有存储功能,用户可以查看历史日志。但是文件方式需要文件系统的支持,而Flash方式更加适合应用在无文件系统的小型嵌入式设备中。

2.6 Demo

2.6.1 核心功能

下图为在终端中输入命令来控制日志的输出及过滤器的设置,更加直观的展示了 EasyLogger 核心功能。

easylogger

2.6.2 Flash Log(将日志保存到 Flash 中)

下图过程为通过控制台输出日志,并将输出的日志存储到 Flash 中。重启再读取上次保存的日志,最后清空 Flash 日志。

FlashLog

2.6.2 File Log(将日志保存到文件中)

通过 FIle 插件,可以将日志自动保存至文件中。每个文件可以设定大小,超过规定大小后,自动新建新的文件来存储日志。

3. 文档

具体内容参考\docs\zh\下的文件。务必保证在 阅读文档 后再移植使用。

4. 后期

  • Flash存储:在EasyFlash中增加日志存储、读取功能,让EasyLogger与其无缝对接。使日志可以更加容易的存储在 非文件系统 中,并具有历史日志检索的功能;
  • 配置文件:文件系统下的配置文件;
  • 文件转档:文件系统下支持文件按容量转档,按时间区分;
  • 日志助手:开发跨平台的日志助手,兼容Linux、Windows、Mac系统,打开助手即可查看、过滤(支持正则表达式)、排序、保存日志等。前端:HTML5 + Bootstrap + AngularJS + NW.js,后端:Rust + iron + rust-websocket + serial-rs
  • 异步输出:目前日志输出与用户代码之间是同步的方式,这种方式虽然软件简单,也不存在日志覆盖的问题。但在输出速度较低的平台下,会由于增加日志功能,而降低软件运行速度。所以后期会增加 异步输出 方式,关键字过滤也可以放到异步输出中去;
  • Arduino:增加Arduino lib,并提供其Demo;

5. 许可

MIT Copyright (c) [email protected]

easylogger's People

Contributors

5ooo avatar 675658 avatar advanced-lj avatar aliliao avatar armink avatar cddjr avatar fragrantrye avatar h3n4l avatar idiotstonema avatar jin-w-fs avatar ju5t4fun avatar kaidegit avatar liuxi1989 avatar mrkuan avatar pencil1983 avatar saviourxx avatar slark-yuxj avatar tianlongqin avatar xxxxzzzz000 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easylogger's Issues

此处存在溢出风险

strcpy(log_buf + ELOG_LINE_BUF_SIZE - newline_len, ELOG_NEWLINE_SIGN);

用gcc -O2 编译,在这一行报

warning: call to __builtin___memcpy_chk will always overflow destination buffer

分析:
与elog_strcpy不同,strcpy函数会拷贝ELOG_NEWLINE_SIGN结束的'\0'字符,因此仅仅从log_buf的结尾退回newline_len = strlen(ELOG_NEWLINE_SIGN)个字节是不够的,得多退一个字节,修改成:
strcpy(log_buf + ELOG_LINE_BUF_SIZE - newline_len - 1, ELOG_NEWLINE_SIGN);

没有细看前后文,上文的log_len是否也应该减1?

异步丢log

使用 elog_async.c 在ring buf 满了后会丢log,

Linux下动态开启/关闭日志

动态图中可以在控制台上 输入 elog on/off 来 开启/关闭日志输出。请问在Linux下如何能使用此项功能?

log_cfg 配置

log_cfg.h 这个头文件能不能只包含在那几个.c 文件里面, 不要包含在elog.h 里面,这样对外看到的API 只要有elog.h 就可以

禁止输出时编译错误

在elog.h中elog_a~elog_v的宏定义默认给出了有效定义(187-192行),导致未定义ELOG_OUTPUT_ENABLE时不能将宏有效置空。

easylogger多线程模式下的堆栈资源优化建议

现在的easylogger虽然支持多线程,但是只是使用了一个信号量的保护,在资源占用上还有需要优化的地方。
主要是e_log宏虽然可以扩散到不同的task中,但是最终都是指向elog_output,从调用到最后输出都会在这个函数里面完成,这个函数占用很大的堆栈资源,而且随着每个task都使用e_log输出日志,每个task都要重复的占用这样的一个堆栈的资源。
比较好的一个方案是利用宏分开OS模式和BAREMETAL模式,当OS模式的时候,使用一个queue来存储每一个要发送的log,建立一个task从queue取出log并统一处理所有的输出,可以对queue的长度限制来限定资源。

easyFlash异常情况

continue_ff<4 时,其log_end_addr返回sector_start + EF_ERASE_MIN_SIZE写数据会返回出错情况。

EasyLogger报错

Error: Log sector header error! Now will clean all log area.
或者
Error: There must be only one sector status is USING! Now will clean all log area.

这些问题如何处理??

log 换行符问题

如果log_i("...\n"), 这样log里面已经有了换行符,使用的时候会打印两个换行符,应该去掉一个啊

elog_hexdump数据偏移地址问题

感觉elog_hexdump函数打印的数据偏移好像有点问题:
fmt_result = snprintf(log_buf, ELOG_LINE_BUF_SIZE, "D/HEX %s: %04X-%04X: ", name, i, i + width);
是不是应该改为:
fmt_result = snprintf(log_buf, ELOG_LINE_BUF_SIZE, "D/HEX %s: %04X-%04X: ", name, i, i + width - 1);

使用easylogger打印会出现errno被改变的异常

配置文件:

/*
 * This file is part of the EasyLogger Library.
 *
 * Copyright (c) 2015, Armink, <[email protected]>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Function: It is the configure head file for this library.
 * Created on: 2015-07-30
 */

#ifndef _ELOG_CFG_H_
#define _ELOG_CFG_H_

/* enable log output. default open this macro */
#define ELOG_OUTPUT_ENABLE
/* setting static output log level */
#define ELOG_OUTPUT_LVL                      ELOG_LVL_VERBOSE
/* enable assert check */
#define ELOG_ASSERT_ENABLE
/* buffer size for every line's log */
#define ELOG_LINE_BUF_SIZE                   5120
/* output line number max length */
#define ELOG_LINE_NUM_MAX_LEN                5
/* output filter's tag max length */
#define ELOG_FILTER_TAG_MAX_LEN              16
/* output filter's keyword max length */
#define ELOG_FILTER_KW_MAX_LEN               16
/* output newline sign */
#define ELOG_NEWLINE_SIGN                    "\n"
/* enable log color */
#define ELOG_COLOR_ENABLE
/* enable asynchronous output mode */
// #define ELOG_ASYNC_OUTPUT_ENABLE
/* the highest output level for async mode, other level will sync output */
#define ELOG_ASYNC_OUTPUT_LVL                ELOG_LVL_DEBUG
/* buffer size for asynchronous output mode */
#define ELOG_ASYNC_OUTPUT_BUF_SIZE           (ELOG_LINE_BUF_SIZE * 100)
/* each asynchronous output's log which must end with newline sign */
//#define ELOG_ASYNC_LINE_OUTPUT
/* asynchronous output mode using POSIX pthread implementation */
#define ELOG_ASYNC_OUTPUT_USING_PTHREAD
//ELOG_BUF_OUTPUT_ENABLE 缓冲输出模式下日志缓冲区满了才会输出,或者手动调用 elog_flush 方法时输出

#endif /* _ELOG_CFG_H_ */

测试程序:

void test_elog(void) {
    while(true) {
        /* test log output for all level */
        errno = 5;
        log_a("Hello EasyLogger! %d", errno);
        log_e("Hello EasyLogger! %d", errno);
        log_w("Hello EasyLogger! %d", errno);
        log_i("Hello EasyLogger! %d", errno);
        log_d("Hello EasyLogger! %d", errno);
        log_v("Hello EasyLogger! %d", errno);
//        elog_raw("Hello EasyLogger!");
        sleep(5);
    }
}

void log_init(void)
{
    /* close printf buffer */
    setbuf(stdout, NULL);
    /* initialize EasyLogger */
    elog_init();
    /* set EasyLogger log format */
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
#ifdef ELOG_COLOR_ENABLE
    elog_set_text_color_enabled(true);
#endif
    /* start EasyLogger */
    elog_start();
    // elog_async_enabled(false);//失能异步输出,否则会出现程序崩溃的时候没有输出的问题
}


int main(int argc, char** argv)
{

    log_init();
    test_elog();
}

程序输出

I/elog     [05-29 18:13:46] EasyLogger V2.0.1 is initialize success.
A/Alfred   [05-29 18:13:46 pid:0704 tid:19956] (alfred.c test_elog:526)Hello EasyLogger! 5
E/Alfred   [05-29 18:13:46] Hello EasyLogger! 2
W/Alfred   [05-29 18:13:46] Hello EasyLogger! 2
I/Alfred   [05-29 18:13:46] Hello EasyLogger! 2
D/Alfred   [05-29 18:13:46 pid:0704 tid:19956] (alfred.c:530)Hello EasyLogger! 2
V/Alfred   [05-29 18:13:46 pid:0704 tid:19956] (alfred.c:531)Hello EasyLogger! 2

使用打印函数之后errno被改变了,应该是elogger内部调用出现了错误,目前还没查出来。

不好意思 新手有点入门级小问题~

不好意思 我还是新手。
我这单片机有点怪 可以装个SD卡 可以使用FILE * 把数据存到SD卡上
用的是arm-none-eabi编译的
有几个疑问:

1 他似乎每个级别的记录都保存,怎么设置某些低级别的记录不保存?这样我就不需要普通的COUT了
直接全部LOG_D就可以了

2 单片机上他会不会自动清除log记录?因为log文件不能无限大啊..
3 elog_file_port.cpp 这个我的单片机是arm-none-eabi 没操作系统.再这个咋办?都空着?如果不写这个他不会保存文件

多线程使用一段时间后出现死锁

arm linux环境

(gdb) bt
#0  0x0000007f90ea9064 in __lll_lock_wait () from target:/lib64/libpthread.so.0
#1  0x0000007f90ea1a4c in pthread_mutex_lock ()
   from target:/lib64/libpthread.so.0
#2  0x00000000004cad80 in elog_port_output_lock ()
    at ./3rd_lib/easylogger/port/elog_port.c:76
#3  0x00000000004cbf78 in elog_get_filter_tag_lvl (tag=0x651c40 "TASK")
    at ./3rd_lib/easylogger/src/elog.c:435
#4  0x00000000004cc2e8 in elog_output (level=2 '\002', tag=0x651c40 "TASK", 
    file=0x651968 "./devices/devices.c", 
    func=0x651f68 <__FUNCTION__.12424> "timer1_handle", line=217, 
    format=0x651c18 "timming update_devices_status %d")
    at ./3rd_lib/easylogger/src/elog.c:528
#5  0x00000000004e9314 in timer1_handle (sig=10) at ./devices/devices.c:217
#6  <signal handler called>
#7  0x0000007f90d0f6d8 in nanosleep () from target:/lib64/libc.so.6
#8  0x0000007f90d0f568 in sleep () from target:/lib64/libc.so.6
#9  0x00000000004e75ec in main (argc=1, argv=0x7fea78d518) at ./main.c:98
(gdb) thread 2
[Switching to thread 2 (Thread 3106.3107)]
#0  0x0000007f90ea9034 in __lll_lock_wait () from target:/lib64/libpthread.so.0
(gdb) bt
#0  0x0000007f90ea9034 in __lll_lock_wait () from target:/lib64/libpthread.so.0
#1  0x0000007f90ea1a4c in pthread_mutex_lock ()
   from target:/lib64/libpthread.so.0
#2  0x00000000004cad80 in elog_port_output_lock ()
    at ./3rd_lib/easylogger/port/elog_port.c:76
#3  0x00000000004cbf78 in elog_get_filter_tag_lvl (tag=0x651c40 "TASK")
    at ./3rd_lib/easylogger/src/elog.c:435
#4  0x00000000004cc2e8 in elog_output (level=2 '\002', tag=0x651c40 "TASK", 
    file=0x651968 "./devices/devices.c", 
    func=0x651f68 <__FUNCTION__.12424> "timer1_handle", line=226, 
    format=0x651c48 "timming check_devices_status %d")
    at ./3rd_lib/easylogger/src/elog.c:528
#5  0x00000000004e93b4 in timer1_handle (sig=10) at ./devices/devices.c:226
#6  <signal handler called>
#7  0x0000007f90d2e6e8 in write () from target:/lib64/libc.so.6
#8  0x0000007f90cddeb0 in _IO_file_write () from target:/lib64/libc.so.6
#9  0x0000007f90cdd2f8 in ?? () from target:/lib64/libc.so.6
#10 0x0000007f90cde648 in _IO_file_xsputn () from target:/lib64/libc.so.6
#11 0x0000007f90cb8e90 in ?? () from target:/lib64/libc.so.6
#12 0x0000007f90cb6824 in vfprintf () from target:/lib64/libc.so.6
#13 0x0000007f90cbd948 in printf () from target:/lib64/libc.so.6
#14 0x00000000004cad54 in elog_port_output (
    log=0x7065b8 <poll_get_buf> "D/HEX JP_PLC: 0000-0017: 55 ...***... 0A"..., size=127)
    at ./3rd_lib/easylogger/port/elog_port.c:65
#15 0x00000000004cde18 in async_output (arg=0x0)
    at ./3rd_lib/easylogger/src/elog_async.c:299
#16 0x0000007f90e9f0e8 in start_thread () from target:/lib64/libpthread.so.0
#17 0x0000007f90d3af4c in ?? () from target:/lib64/libc.so.6
(gdb) thread 3
[Switching to thread 3 (Thread 3106.3108)]
#0  0x0000007f90ea9064 in __lll_lock_wait () from target:/lib64/libpthread.so.0
(gdb) bt
#0  0x0000007f90ea9064 in __lll_lock_wait () from target:/lib64/libpthread.so.0
#1  0x0000007f90ea1a4c in pthread_mutex_lock () from target:/lib64/libpthread.so.0
#2  0x00000000004cad80 in elog_port_output_lock ()
    at ./3rd_lib/easylogger/port/elog_port.c:76
#3  0x00000000004cbf78 in elog_get_filter_tag_lvl (tag=0x651c40 "TASK")
    at ./3rd_lib/easylogger/src/elog.c:435
#4  0x00000000004cc2e8 in elog_output (level=2 '\002', tag=0x651c40 "TASK", 
    file=0x651968 "./devices/devices.c", 
    func=0x651f68 <__FUNCTION__.12424> "timer1_handle", line=226, 
    format=0x651c48 "timming check_devices_status %d")
    at ./3rd_lib/easylogger/src/elog.c:528
#5  0x00000000004e93b4 in timer1_handle (sig=10) at ./devices/devices.c:226
#6  <signal handler called>
#7  0x0000007f90d0f6d8 in nanosleep () from target:/lib64/libc.so.6
#8  0x0000007f90d34d08 in usleep () from target:/lib64/libc.so.6
#9  0x00000000004e6bf4 in http_deal (arg=0x0) at ./service/http.c:415
#10 0x0000007f90e9f0e8 in start_thread () from target:/lib64/libpthread.so.0
#11 0x0000007f90d3af4c in ?? () from target:/lib64/libc.so.6

elog_init是不是不能重复初始化

一个进程中有多个文件使用elog,是每个文件里都需要初始化,还是主程序初始化一次,其他的直接调打印log的函数就可以了

怎么才能编译呢?

一定要包含 rtthread.h 吗?

介绍里不是说支持多种操作系统(RT-Thread、UCOS、Linux、Windows...),也支持裸机平台
所以呢??Linux、Windows 该如何编译呢?

elog 死锁

配置如下:

/*
 * This file is part of the EasyLogger Library.
 *
 * Copyright (c) 2015, Armink, <[email protected]>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Function: It is the configure head file for this library.
 * Created on: 2015-07-30
 */

#ifndef _ELOG_CFG_H_
#define _ELOG_CFG_H_

/* enable log output. default open this macro */
#define ELOG_OUTPUT_ENABLE
/* setting static output log level */
#define ELOG_OUTPUT_LVL                      ELOG_LVL_VERBOSE
/* enable assert check */
#define ELOG_ASSERT_ENABLE
/* buffer size for every line's log */
#define ELOG_LINE_BUF_SIZE                   1024000
/* output line number max length */
#define ELOG_LINE_NUM_MAX_LEN                5
/* output filter's tag max length */
#define ELOG_FILTER_TAG_MAX_LEN              16
/* output filter's keyword max length */
#define ELOG_FILTER_KW_MAX_LEN               16
/* output newline sign */
#define ELOG_NEWLINE_SIGN                    "\n"
/* enable log color */
#define ELOG_COLOR_ENABLE
/* enable asynchronous output mode */
// #define ELOG_ASYNC_OUTPUT_ENABLE
/* the highest output level for async mode, other level will sync output */
#define ELOG_ASYNC_OUTPUT_LVL                ELOG_LVL_DEBUG
/* buffer size for asynchronous output mode */
#define ELOG_ASYNC_OUTPUT_BUF_SIZE           (ELOG_LINE_BUF_SIZE * 100)
/* each asynchronous output's log which must end with newline sign */
//#define ELOG_ASYNC_LINE_OUTPUT
/* asynchronous output mode using POSIX pthread implementation */
#define ELOG_ASYNC_OUTPUT_USING_PTHREAD
//ELOG_BUF_OUTPUT_ENABLE 缓冲输出模式下日志缓冲区满了才会输出,或者手动调用 elog_flush 方法时输出

#endif /* _ELOG_CFG_H_ */

初始化代码如下:

 void log_init(void)
{/* close printf buffer */
    setbuf(stdout, NULL);
    /* initialize EasyLogger */
    elog_init();
    /* set EasyLogger log format */
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
#ifdef ELOG_COLOR_ENABLE
    elog_set_text_color_enabled(true);
#endif
    /* start EasyLogger */
    elog_start();
}

gdb信息如下:

[~]# ./gdb -p 8793
GNU gdb (GDB) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-buildroot-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 8793
[New LWP 8794]
[New LWP 8795]
[New LWP 8796]

warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.

warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.
0x76e47ba4 in __libc_do_syscall () from /lib/libpthread.so.0
(gdb) bt
#0  0x76e47ba4 in __libc_do_syscall () from /lib/libpthread.so.0
#1  0x76e4568c in __lll_lock_wait () from /lib/libpthread.so.0
#2  0x76e415ba in pthread_mutex_lock () from /lib/libpthread.so.0
#3  0x00017184 in elog_port_output_lock () at ../../easylogger/port/elog_port.c:128
#4  0x00016080 in elog_output_lock () at ../../easylogger/src/elog.c:306
#5  0x00016254 in elog_output (level=3 '\003', tag=0x192bc "NO_TAG", file=0x192b4 "db.c",
    func=0x197e0 <__FUNCTION__.7622> "db_get_retained_count", line=239,
    format=0x19538 "db get retained message count %d") at ../../easylogger/src/elog.c:413
#6  0x0001253c in db_get_retained_count () at db.c:239
#7  0x0001363e in sync_publishRetainedMsg (clientPt=0x2c0d4 <_client>) at sync.c:258
#8  0x0001588a in main (argc=2, argv=0x7e983e44) at transceiver.c:809
(gdb) where
#0  0x76e47ba4 in __libc_do_syscall () from /lib/libpthread.so.0
#1  0x76e4568c in __lll_lock_wait () from /lib/libpthread.so.0
#2  0x76e415ba in pthread_mutex_lock () from /lib/libpthread.so.0
#3  0x00017184 in elog_port_output_lock () at ../../easylogger/port/elog_port.c:128
#4  0x00016080 in elog_output_lock () at ../../easylogger/src/elog.c:306
#5  0x00016254 in elog_output (level=3 '\003', tag=0x192bc "NO_TAG", file=0x192b4 "db.c",
    func=0x197e0 <__FUNCTION__.7622> "db_get_retained_count", line=239,
    format=0x19538 "db get retained message count %d") at ../../easylogger/src/elog.c:413
#6  0x0001253c in db_get_retained_count () at db.c:239
#7  0x0001363e in sync_publishRetainedMsg (clientPt=0x2c0d4 <_client>) at sync.c:258
#8  0x0001588a in main (argc=2, argv=0x7e983e44) at transceiver.c:809
(gdb)

看了别的 issue 断言的时候要把几个锁关掉,但是整个程序中没有使用到断言。
仔细查看了下代码,发现日志初始化代码运行了两次,也就是log_init()调用了两次,是否和这个有关系?

关于COLOR enable出现不能写入flash的问题。

版本:EasyLogger V2.0.0 is initialize success

ElogErrCode elog_init(void) {
......
#ifdef ELOG_COLOR_ENABLE
/* disable text color by default /
elog_set_text_color_enabled(false);
#endif
......
}
void elog_output(...)
{
#ifdef ELOG_COLOR_ENABLE
/
add CSI start sign and color info */
if (elog.text_color_enabled) {
log_len += elog_strcpy(log_len, log_buf + log_len, CSI_START);
log_len += elog_strcpy(log_len, log_buf + log_len, color_output_info[level]);
}
#endif
}

这里默认是disable的,但是elog_find_lvl里没有判断text_color_enable,导致获取不到正确的lvl。

int8_t elog_find_lvl(const char log) {
#ifdef ELOG_COLOR_ENABLE
uint8_t i;
size_t csi_start_len = strlen(CSI_START);
for(i = 0; i < ELOG_LVL_TOTAL_NUM; i ++) {
if (!strncmp(color_output_info[i], log + csi_start_len, strlen(color_output_info[i]))) {
return i;
}
}
/
found failed */
return -1;
#else
...
}

可以用作多进程吗?

我有两个进程client和server,我想把两个进程的日志写到一起,而且保持时序,方便debug,就是android的日志系统一样,这个工具是否可行?

中文API文档”简化方式2“似乎有错

https://github.com/armink/EasyLogger/blob/master/docs/zh/api/kernel.md#131-%E8%BE%93%E5%87%BA%E5%9F%BA%E6%9C%AC%E6%97%A5%E5%BF%97

1.3.1 输出基本日志

#define elog_assert(tag, ...)
#define elog_a(tag, ...) //简化方式1,每次需填写 LOG_TAG
#define log_a(...) //简化方式2,LOG_TAG 已经在文件顶部定义,使用前无需填写 LOG_TAG

#define elog_error(tag, ...)
#define elog_e(tag, ...)
#define log_a(...)

...
后面几项的log_a(...)似乎应该是log_e, log_w ...

异步输出可能导致日志输出不完整

EasyLogger/src/elog_async.c:
开启ELOG_ASYNC_OUTPUT_USING_PTHREAD情况下,主线程创建线程完成后,才将init_ok设置为true.如:
#ifdef ELOG_ASYNC_OUTPUT_USING_PTHREAD
pthread_attr_t thread_attr;
struct sched_param thread_sched_param;

sem_init(&output_notice, 0, 0);
......
**pthread_create(&async_output_thread, &thread_attr, async_output, NULL);**
......

#endif
//此时,子线程极有可能已经开始执行async_output,而在async_out一开始就断言init_ok为false,
如: ELOG_ASSERT(init_ok); 子程序就有可能再也没有机会执行后边的sem_wait了。
init_ok = true;

最后,只会输出 level < OUTPUT_LVL内容了。

filter过滤问题

过滤的代码逻辑是不是搞反了?比如调用:elog_set_filter_tag("main");时,用意应该是过滤掉所有的tag是main的打印,而elog_output输出时,却是用:else if (!strstr(name, elog.filter.tag)) { /* tag filter */
进行过滤判断,就达不到过滤main标签的目的,应该改为else if ((NULL != strstr(tag, elog.filter.tag))&&(strlen(elog.filter.tag)>0)),其它几处判断也是类似

怎么没有文件port

找了半天才闹明白,原来每个输出“目标”都是通过port定义的。为什么会没有file port呢?

elog_flash_flush()并没有输出缓冲区中的全部日志

我是这样发现的,按下某一按键后执行

{log_a(xxx);    elog_flash_flush();}

然后按下另一按键执行

elog_flash_output_recent(300);

结果发现最后一次log_a的信息没有输出。
通过仿真,发现elog_async.c中定义的log_buf[]里是存在最后一次log_a的信息的,但flash上却没有。
图中:红框部分是最后一次log_a信息的结尾,绿框是上一次log_a信息的结尾。
elog_flash_flush_bug

ps: elog_cfg.h中定义了ELOG_ASYNC_OUTPUT_ENABLEELOG_ASYNC_LINE_OUTPUT

程序崩溃前的日志信息无法输出

程序如下:

int main()
{
    /* close printf buffer */
    setbuf(stdout, NULL);
    /* initialize EasyLogger */
    elog_init();
    /* set EasyLogger log format */
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC);
#ifdef ELOG_COLOR_ENABLE
    elog_set_text_color_enabled(true);
#endif
    /* start EasyLogger */
    elog_start();

    log_e("This is test message");
    char *a = NULL;//制造崩溃
    *a = 0;

}

此时This is test message这条信息是无法输出的,造成了调试和信息记录上面的误解以为是log_e("This is test message");之前就已经崩溃了。

Windows <pthread.h>

Hello.

demo/os/windows/easylogger/port/elog_port.c:
[32] #include <pthread.h>

pthread.h: No such file or directory

Thanks.

assert问题&elog_hex_dump

1、我们需要使用hex_dump功能,我参考ulog_hex_demp实现了,我可以提交一个pr吗?
2、elog_async_init中init_ok = true;建议提前到ifdef ELOG_ASYNC_OUTPUT_USING_PTHREAD宏定义前,我修改异步输出任务调度方式为SCHED_FIFO时发现,在任务还没有返回时async_output回调就被调用,会在该函数中ELOG_ASSERT(init_ok);导致无法输出。

请问,过滤TAG 函数,只是符合TAG能打印出来,我想过滤这个TAG不打印出来怎么弄

如题

elog_set_filter_tag 这个API是LOG中TAG符合才会输出,我想要个API,符合不输出,应该,好弄把

    else if (!strstr(tag, elog.filter.tag))     /* tag filter */
    {
        //TODO 可以考虑采用KMP及朴素模式匹配字符串,提升性能
        return;
    }

这块 改成?

    else if (strstr(tag, elog.filter.tag))     /* tag filter */
    {
        //TODO 可以考虑采用KMP及朴素模式匹配字符串,提升性能
        return;
    }

或者为了保持原来的 elog_set_filter_tag 接口,增加个 elog_set_unfilter_tag 接口

   //伪代码演示
    else if (!strstr(tag, elog.filter.tag) && filter_mode == true)     /* tag filter */
   {
  
   }
    else if (!strstr(tag, elog.filter.tag)&& filter_mode == false) )     /* tag filter */
    {
        //TODO 可以考虑采用KMP及朴素模式匹配字符串,提升性能
        return;
    }

FreeRTOS下有时候会导致外部中断进不去

MCU是STM32L4,使用ST的HAL库,FreeRTOS下移植使用信号量进行elog_port_output_lock和elog_port_output_unlock,有时候会导致STM32不能进入不能进入外部中断函数,请问该怎么解决?谢谢!

static SemaphoreHandle_t log_sem;
/**

  • EasyLogger port initialize

  • @return result
    */
    ElogErrCode elog_port_init(void) {
    ElogErrCode result = ELOG_NO_ERR;

    /* add your code here */
    log_sem = xSemaphoreCreateBinary();
    if (log_sem != NULL) {
    xSemaphoreGive(log_sem);
    }
    return result;
    }

/**

  • output lock
    */
    void elog_port_output_lock(void) {

    /* add your code here */
    //__disable_irq();
    if (log_sem == NULL) {
    return;
    }

    xSemaphoreTake(log_sem, portMAX_DELAY);
    }

/**

  • output unlock
    */
    void elog_port_output_unlock(void) {

    /* add your code here */
    //__enable_irq();
    if (log_sem == NULL) {
    return;
    }

    xSemaphoreGive(log_sem);
    }

easylooger使用过程中遇到的问题,读写flash起始地址不一致。

问题描述:每次读取日志的时候,开头4个字节是FF。
经过检查发现:假设日志地址:0x08033000
读日志时,读取的地址是从0x08033000开始读去的。但是写日志的时候,却是从0x08033004地址开始写的。所以,每次查看日志的适合前4个字节内容为FF;
请问我是不是哪里设置有问题?
EasyFlash设置flash地址200KB开始,开启了 环境变量、掉电保护。
EasyLogger设置基本没改动。
使用的是您项目里面的RTT演示部源码,但是看你介绍的动画图又没有这个情况。。。

存在数组越界

#ifdef ELOG_COLOR_ENABLE
/* add CSI end sign */
if (elog.text_color_enabled) {
log_len += elog_strcpy(log_len, log_buf + log_len + fmt_result, CSI_END);
}
#endif

log_buf + log_len + fmt_result可能超过ELOG_LINE_BUF_SIZE,导致数组越界

缓冲输出模式的bug

elog_buf_output()函数有问题,输出不完整
`void elog_buf_output(const char *log, size_t size) {
size_t write_size = 0, write_index = 0;

if (!is_enabled) {
    elog_port_output(log, size);
    return;
}

//循环有什么用?每次调用此处只会被执行一次
while (true) {
if (buf_write_size + size > ELOG_BUF_OUTPUT_BUF_SIZE) {
//缓冲区满时log被拆分输出?
write_size = ELOG_BUF_OUTPUT_BUF_SIZE - buf_write_size;
memcpy(log_buf + buf_write_size, log + write_index, write_size);
//write_index不是静态局部变量,此处有意义?
write_index += write_size;
size -= write_size;
buf_write_size += write_size;
/* output log /
elog_port_output(log_buf, buf_write_size);
/
reset write index */
buf_write_size = 0;
} else {
memcpy(log_buf + buf_write_size, log + write_index, size);
buf_write_size += size;
break;
}
}
}`

修改成以下代码后测试正常:
`void elog_buf_output(const char *log, size_t size)
{
//未使能缓冲输出时直接输出
if (!is_enabled) {
elog_port_output(log, size);
return;
}
//缓冲区空间不足时先输出
if (buf_write_size + size > ELOG_BUF_OUTPUT_BUF_SIZE) {
elog_port_output(log_buf, buf_write_size);
buf_write_size = 0;
}
//日志拷贝至缓冲区
memcpy(log_buf + buf_write_size, log, size);
buf_write_size += size;

}`

多进程或多应用调用easylog调用会丢失log

我还没有能力贡献代码,就贡献测试出的bug吧。

使用linux demo的代码,以so库的方式调用,设定文件大小为100k, rotate为2,同时启动四个程序,是为了测试多进程下log是否完整。
预期结果:
在elog_file.log中出现如下有序或无序,但自增数字连续的日志记录:
A: 000 Hello EasyLogger!
B: 000 Hello EasyLogger!
C: 000 Hello EasyLogger!
D: 000 Hello EasyLogger!

测试结果:
当第一个elog_file.log.0产生前,log是预期的的结果;
当第一个elog_file.log.0产生后,log记录出现错乱,log只出现其中一个程序的所有log,比如:
...
B: 199 Hello EasyLogger!
B: 200 Hello EasyLogger!
B: 201 Hello EasyLogger!
B: 202 Hello EasyLogger!
...
其他三个程序的log全部没有记录。shell显示程序还在正常产生log。

备注:
单进程无此问题。
我还没有能力直接分析解决,所以只能提issue。:-(

easylogger和fal的宏定义冲突

packages\EasyLogger-v2.0.0\inc\elog.h(209): warning: #47-D: incompatible redefinition of macro "log_e" (declared at line 98 of "packages\fal-latest\inc\fal_def.h")

fal_def.h:
/* info level log */
#ifdef log_i
#undef log_i
#endif
#define log_i(...) FAL_PRINTF("\033[32;22m[I/FAL] ");

在easylogger中是使用log_x的宏,但是fal中也是使用log_x,虽然是不同的东西,但是看到作者都是你,所以提一下。

多线程写日志时,输出的线程id不是子线程的id

修改linux demo为多线程模式,verbose里面的tid不是子线程本身的id?
I/elog [12-25 18:28:36] EasyLogger V2.0.3 is initialize success.
do multithread test...
start create thread........
start create thread........
id=0
tid =3152430848
id=1
tid =3144038144
elog_output----tid:13995
A/main [12-25 18:28:36 pid:31856 tid:13995] (main.c test_elog:86)Hello EasyLogger! 0
E/main [12-25 18:28:36] Hello EasyLogger! 0
W/main [12-25 18:28:36] Hello EasyLogger! 0
I/main [12-25 18:28:36] Hello EasyLogger! 0
elog_output----tid:13995
elog_output----tid:13995
elog_output----tid:13995
A/main [12-25 18:28:36 pid:31856 tid:13995] (main.c test_elog:86)Hello EasyLogger! 1
E/main [12-25 18:28:36] Hello EasyLogger! 1
W/main [12-25 18:28:36] Hello EasyLogger! 1
I/main [12-25 18:28:36] Hello EasyLogger! 1
elog_output----tid:13995
elog_output----tid:13995
D/main [12-25 18:28:36 pid:31856 tid:13995] (main.c:90)Hello EasyLogger! 0
V/main [12-25 18:28:36 pid:31856 tid:13995] (main.c:91)Hello EasyLogger! 0
D/main [12-25 18:28:36 pid:31856 tid:13995] (main.c:90)Hello EasyLogger! 1
V/main [12-25 18:28:36 pid:31856 tid:13995] (main.c:91)Hello EasyLogger! 1

关于打印数据的调试问题

在调试过程中,很多时候会遇到打印一个数组的每个元素。比如串口调试时,可能会打印接收或者发送数组中的每个数据。
我现在的做法是:
`
for(uint16_t i = 0; i < len; i++){

 elog_raw("%02X ",pbuff[i]);

}

elog_raw("\r\n");
但这样会造成打印繁琐问题,而且在关闭打印之后,for循环会空跑一圈,造成时间浪费。 我现在的想法是:
void elog_buff(char *type,char *pbuff,uint8_t len)
{

    //在这儿添加相关屏蔽操作
for(uint16_t i = 0; i < len; i++){

	elog_raw(type,pbuff[i]);

}
elog_raw("\r\n");

}
`
不知道大伙感觉这个方法怎么样?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.