1.什么是日志?
日志(Logging)是一种记录程序运行时发生的事件、状态变化、错误消息或其他重要信息的方法。它对于开发者来说是一个宝贵的工具,用于调试程序、监控运行时行为以及诊断问题。
我们之前printf输出信息就是最简单、常用的一种日志形式
2.什么是RTT
全称为Real Time Transfer(实时传输)调试,是SEGGER公司推出的一种用于嵌入式系统监控和交互的技术。该技术结合了SWO(单线输出)和半主机(Semi-hosting)的优点,提供了极高的性能,允许开发者从目标MCU(微控制器)上快速输出调试信息和数据,同时不影响MCU的实时性。
RTT的原理
- RTT在芯片内存中使用控制块结构来管理数据的读取和写入。控制块包含一个ID,以便通过连接的JLINK在内存中找到它,并为每个可用通道提供一个结构体,用于描述缓冲区及其状态。
- 可用通道的最大数量可以在编译时进行配置,并且每个缓冲区都可以在运行时由应用程序进行配置和添加。上行和下行缓冲区可以分开处理。
- 每个通道可以配置为阻塞或非阻塞:
- 在阻塞模式下,当缓冲区已满时,应用程序将等待,直到有空间可以写入数据,虽然应用程序状态被阻止,但可以防止数据丢失。
- 在非阻塞模式下,只有不超过缓冲区大小的数据被写入,其余的数据将被丢弃。即使没有连接调试器,也可以实时运行。
- 而且开发人员不必创建特殊的调试版本,代码可以保留在以后发布的项目工程中。
3.什么是EasyLogger?
EasyLogger 是一款超轻量级、高性能的 C/C++ 日志库,非常适合对资源敏感的软件项目,例如: IoT 产品、可穿戴设备、智能家居等等。相比 log4c、zlog 这些知名的 C/C++ 日志库, EasyLogger 的功能更加简单,提供给用户的接口更少,但上手会很快,更多实用功能支持以插件形式进行动态扩展。
我用RTT已经可以实现不同颜色日志输出,为什么还要使用日志库?
- a.多种输出方式:EasyLogger支持用户自定义输出方式,包括终端、文件、数据库、串口、485、Flash等。这种灵活性使得它能适应不同的应用场景(真正项目开发中,不一定使用RTT输出)
- b.线程安全和异步输出:EasyLogger的日志输出设计为线程安全,并支持异步输出及缓冲输出模式,这在多线程环境中尤其重要,能够提高系统的稳定性和性能
- c,丰富的日志内容:EasyLogger的日志内容可以包含级别、时间戳、线程信息、进程信息等,这些信息对于调试和维护非常有用
- d.动态过滤和颜色显示:EasyLogger支持按标签、级别、关键词进行动态过滤,并且各级别日志支持不同颜色显示,便于日志的分类和快速识别
- e.EasyLogger支持以插件形式扩展新功能,如将日志存储在Flash中或文件中,极大地增强了其功能和适应性
EasyLoggerr中多种类型输出,一般如何选取?
答:先逐个解析,最后再总结一下
- assert:用于在代码中发现逻辑错误或不应该发生的情况,不太常用
- warning:用于提示可能存在的非致命性问题,代码仍然可以运行,但需要注意这些警告。
- error:致命错误,出现这种情况程序就死机了
- info:用于输出一般性信息,帮助了解程序的运行状态。
- debug:用于输出调试信息,帮助开发人员进行问题排查。
- verbose:翻译过来就是啰嗦,任何无关紧要的可能都会输出,不太常用
一般最常用warning,代码运行时出现错误,但是只要程序还能继续运行,都会归到warning
info和debug在开发调试时也经常使用
为什么RTT的log采集不影响MCU运行的实时性?
原因如下:
- RTT使用的是内存映射技术,通过将内存区域直接映射到调试器,数据可以在CPU执行的过程中直接读取。这避免了像UART那样必须等待串行传输完成的情况,从而减少了阻塞时间和中断处理时间。
- 非阻塞传输:RTT的设计是非阻塞的,意思是日志数据可以被快速写入内存缓冲区,而不会阻塞或等待传输完成(了解一下异步IO的概念)。这对实时系统非常重要,因为在关键任务运行时,任何阻塞或延迟都可能导致系统响应时间延长。
- 循环缓冲区:RTT使用了循环缓冲区,确保日志数据能够持续写入和读取。即使数据的传输速度赶不上数据生成的速度,RTT的缓冲区也可以暂时存储数据,防止丢失。这样,MCU可以专注于执行主要任务,而不用等待日志传输。
RTT的log输出相较于串口Iog输出好在哪?
- 更快的数据传输速度:RTT通过SWD接口传输数据,其速度通常远高于UART,这使得日志输出的效率更高,能够更快地传输大量数据。
- 实时性更强:由于RTT是非阻塞的,它对实时性要求高的应用程序影响很小。串口传输在高频率下容易产生堵塞和丢包问题
- 占用资源少:RTT不占用MCU的UART接口资源,也不会占用太多的CPU时间和中断资源,这对于资源有限的嵌入式系统尤其重要。相比之下,UART的输出是阻塞式的,并且会占用一个物理串口。
- 无须额外硬件:RTT只需使用调试接口(如SWD)即可进行通信,不需要额外的硬件连接,这使得调试更加方便和灵活。串口则通常需要接线和调试器连接。
RTT输出的原理是什么(看下源码,找到RTT的缓冲区),为什么能把数据传出来?
RTT输出原理,基于内存共享和环形缓冲区机制。
-
内存映射:通过调试接口将MCU的内存直接映射到主机,这样数据可以在主机和MCU之间快速传输,而不需要通过传统的串行通信方式。
-
非阻塞模式:RTT采用非阻塞模式进行数据写入,使得MCU在写入日志时不会因为等待传输完成而阻塞,保持了系统的实时性。
-
调试器的持续轮询:调试器会持续地从上行缓冲区读取数据,并传输到主机。由于调试器的操作对MCU来说是透明的(jlink自动读取缓冲区,不需要占用cpu),McU几乎不会感受到数据传输的负担。
-
Up Buffer Descriptors :表示上行缓冲区描述符,即由芯片通过 JLINK 向电脑端上传缓冲区中的数据。
Down Buffer Descriptors :表示下行缓冲区描述符,即由电脑端通过 JLINK 向芯片下行缓冲区发送数据。
每个缓冲区大小可以单独配置。缓冲区中的灰色区域是包含有效数据的区域。对于上行缓冲区,写入指针由芯片代码写入,读取指针由JLINK 写入。当读取和写入指针指向相同的元素时 缓冲区为空。 -
控制块代码:
typedef struct { char acID[16]; int MaxNumUpBuffers; int MaxNumDownBuffers; SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; SEGGER_RTT_BUFFER_DOWN aDoWn[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; #if SEGGER_RTT__CB_PADDING unsigned char aDummy[SEGGER_RTT__CB_PADDING]; #endif } SEGGER_RTT_CB; SEGGER_RTT_CB _SEGGER_RTT;
什么是日志的异步输出?
日志的异步输出是一种日志记录方式,在这种方式下,日志信息的生成和实际输出 (写入文件、发送到控制台或传输到远程服务器等)是分离的,彼此独立进行。这意味着,当程序生成一条日志时,它并不会立即阻塞当前线程等待日志输出完成,而是将日志信息暂时存储起来 ( (通常在内存缓冲区中),然后由另一个线程或进程负责异步地将这些日志信息输出到目标位置。
主要特点:
- 非阻塞:异步输出的最大特点是非阻塞。程序的主线程或主要逻辑不需要等待日志写入完成,可以继续执行其他任务,从而提高系统的响应性和并发性能。
- 缓冲区使用:异步日志通常会将日志信息写入一个缓冲区中,由一个单独的日志处理线程从缓冲区中提取日志并将其输出。这个缓冲区可以是固定大小的内存区域。
- 高效性能:由于日志输出操作可能涉及磁盘I/O或网络I/O,这些操作通常是耗时的。异步输出通过让日志输出在后台进行,避免了主线程因为1/O操作而产生的延迟。
- 顺序保证:尽管是异步输出,许多日志系统仍然会保证日志的顺序性,即日志在输出目标上的顺序与其生成的顺序相同。这通常通过队列(FIFO)实现。
异步输出的实现方式:
- 多线程:常见的实现方式是创建一个专门的日志线程,主线程将日志消息写入共享的缓冲区,日志线程不断检查缓冲区并将日志信息写入目标(如文件、网络)。
- 事件驱动:有些日志系统使用事件驱动的方式,在日志生成时触发一个事件,由事件处理机制来异步地处理日志输出
- 队列:主线程将日志消息放入队列中,日志处理线程从队列中提取消息并处理输出。这种方式通常也结合了线程池等机制,以提高日志处理的效率。
异步输出的优缺点:
- 优点:
提高性能:减少主线程的等待时间,提高系统吞吐量。
平滑I/O操作:通过批量处理或延迟写入的方式,降低频繁I/O操作对系统性能的影响。
- 缺点:
复杂性增加:实现异步日志系统需要额外的线程管理和缓冲区管理,增加了系统的复杂性。
潜在数据丢失风险:在系统崩溃或缓冲区溢出时,可能会丢失尚未输出的日志信息。 所以要根据实际数据量设计好缓冲区大小)