SylixOS里的打印【7】--- 内核日志信息打印接口printk

2023-11-03 06:08

本文主要是介绍SylixOS里的打印【7】--- 内核日志信息打印接口printk,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

内核日志信息打印接口printk, 用于内核信息输出,可以在中断函数或者信号句柄中运行,不能在应用层中调用。

内核日志信息打印接口printk本质是API_LogPrintk函数的宏别名。

#ifndef printk
#define printk           API_LogPrintk
#endif

更多printk的详细信息可以查看SylixOS日志系统。

信息等级

printk输出具备信息等级,信息等级用来控制printk打印的这条信息是否在终端上显示的,当日志级别的数值小于控制台级别时,printk要打印的信息才会在控制台打印出来,否则不会显示在控制台!

信息等级通过在字符串开头添加“<n>”(n为0~7)这三个字符来设置,如果不设置则使用默认等级。也可以用宏来设置,可读性更强。

系统定义了8个内核信息等级,和POSIX 标准兼容。

#define KERN_EMERG      "<0>"                                   /* system is unusable                   */
#define KERN_ALERT      "<1>"                                   /* action must be taken immediately     */
#define KERN_CRIT       "<2>"                                   /* critical conditions                  */
#define KERN_ERR        "<3>"                                   /* error conditions                     */
#define KERN_WARNING    "<4>"                                   /* warning conditions                   */
#define KERN_NOTICE     "<5>"                                   /* normal but significant condition     */
#define KERN_INFO       "<6>"                                   /* informational                        */
#define KERN_DEBUG      "<7>"                                   /* debug-level messages                 */
  • KERN_EMERG:会导致主机系统不可用的情况;
  • KERN_ALERT:必须马上采取措施解决的问题;
  • KERN_CRIT:比较严重的情况;
  • KERN_ERR:运行出现错误;
  • KERN_WARNING:可能会影响系统功能的事件;
  • KERN_NOTICE:不会影响系统但值得注意;
  • KERN_INFO:一般信息;
  • KERN_DEBUG:程序或系统调试信息等。

日志等级从上到下依次变低,通常对于系统来说,如果发现等级KERN_EMERG的日志,则代表发生了严重的问题导致系统不可以再运行。等级KERN_DEBUG通常被用于一些调试信息的打印,在SylixOS驱动的开发中,经常使用等级KERN_ERR来打印一些错误信息,使用等级KERN_INFO来打印一些普通信息。

系统还定义了一些等级变量,如终端级别,printk默认级别, 让用户使用的最小级别,默认终端级别。

#define DEFAULT_MESSAGE_LOGLEVEL    4                                   /*  KERN_WARNING                */
#define MINIMUM_CONSOLE_LOGLEVEL    0                                   /*  让用户使用的最小级别        */
#define DEFAULT_CONSOLE_LOGLEVEL    7                                   /*  anything MORE serious than  *//*  KERN_DEBUG                  */
int     console_printk[4] = {DEFAULT_CONSOLE_LOGLEVEL,                                        /*  终端级别                    */DEFAULT_MESSAGE_LOGLEVEL,                                        /*  默认级别                    */MINIMUM_CONSOLE_LOGLEVEL,                                        /*  让用户使用的最小级别        */DEFAULT_CONSOLE_LOGLEVEL,                                        /*  默认终端级别                */
};#define console_loglevel            (console_printk[0])
#define default_message_loglevel    (console_printk[1])
#define minimum_console_loglevel    (console_printk[2])
#define default_console_loglevel    (console_printk[3])

系统初始化时(bspInit.c中)会将终端级别初始化为默认终端级别,代码如下:

console_loglevel = default_message_loglevel;

系统还提供一个loglevel命令,用于查看和设置终端级别。用法如下:
在这里插入图片描述

输出通道

在日志系统初始化完成前,printk也是通过bspDebugMsg函数输出的。使用 bspDebugMsg() 输出时, 需要将 \n 变为 \r\n 序列。

在日志系统初始化完成后,printk输出通道改为一个文件描述符的集合,会向文件集中的所有文件输出。这些文件可以是设备文件(如口/dev/ttyS0),普通文件,socket通道等各种有效文件类型。

系统初始化时向日志文件集添加的第一个文件就是内核标准输出文件(STD_OUT ),所以一般内核打印只能在内核终端看到,在进程终端(如Telnet)中是看不到的。

/*********************************************************************************************************
** 函数名称: halLogInit
** 功能描述: 初始化目标系统日志系统
** 输 入  : NONE
** 输 出  : NONE
*********************************************************************************************************/
#if LW_CFG_LOG_LIB_EN > 0static VOID  halLogInit (VOID)
{fd_set      fdLog;FD_ZERO(&fdLog);FD_SET(STD_OUT, &fdLog);API_LogFdSet(STD_OUT + 1, &fdLog);                                  /*  初始化日志                  */
}#endif   

系统提供logfiles命令用于查看日志文件集中有哪些文件。
在这里插入图片描述

实现原理

API_LogPrintk 函数先借助vsnprintf函数将可变参数格式化为固定字符串,将该字符串拷贝到一个定长的缓存中,然后通过输出接口将字符串输出。

在日志系统初始化完成前API_LogPrintk 使用的是静态缓存,并通过bspDebugMsg函数输出。
在日志系统初始化完成后API_LogPrintk 使用缓存池中动态分配出的缓存,并先发往消息队列,后由日志服务的线程再转发至日志文件集。

API_LogPrintk 的详细实现原理请查看SylixOS日志系统,这里只列了API_LogPrintk 函数的源码,里面对主要过程有详细注释。

/*********************************************************************************************************
** 函数名称: API_LogPrintk
** 功能描述: 记录格式化日志信息
** 输 入  : pcFormat                   格式化字串
**           ...                        变长字串
** 输 出  : 打印长度
*********************************************************************************************************/
INT  API_LogPrintk (CPCHAR   pcFormat, ...)
{static   CHAR          cBspMsgBuf[__MAX_MSG_LEN];                   /*  没有初始化之前暂时使用      *//*  线程不安全!                 */va_list       varlist;LW_LOG_MSG    logmsg;REGISTER INT           iRet;REGISTER PCHAR         pcBuffer;REGISTER ULONG         ulError;BOOL          bHaveLevel = LW_FALSE;BOOL          bBspMsg    = LW_FALSE;/** 获取打印缓存* 根据日志消息队列是否已初始化,选择使用静态数组或内存池分配空间* 总之使用一个固定大小的内存,LW_CFG_LOG_MSG_LEN_MAX一般为1024*/if (_G_hLogMsgHandle == LW_OBJECT_HANDLE_INVALID) {                 /*  log 还没有初始化            */pcBuffer = cBspMsgBuf;bBspMsg  = LW_TRUE;} else {pcBuffer = (PCHAR)__LOG_PRINTK_GET_BUFFER();if (pcBuffer == LW_NULL) {_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);return  (PX_ERROR);}}/** 获取打印等级* 先读取默认打印等级* 如果参数中设置了打印等级则解析并覆盖*/logmsg.LOGMSG_iLevel = default_message_loglevel;if (lib_strnlen(pcFormat, 3) >= 3) {if ((pcFormat[0] == '<') && (pcFormat[2] == '>')) {if ((pcFormat[1] <= '9') && (pcFormat[1] >= '0')) {logmsg.LOGMSG_iLevel = pcFormat[1] - '0';bHaveLevel = LW_TRUE;}}}/** 检查本次打印等级是否大于控制台级别* 当日志级别的数值小于控制台级别时,printk要打印的信息才会在控* 制台打印出来,否则不会显示在控制台!*/if (logmsg.LOGMSG_iLevel > console_loglevel) {                      /*  至少应该为 7                */if (bBspMsg == LW_FALSE) {__LOG_PRINTK_FREE_BUFFER(pcBuffer);}return  (ERROR_NONE);                                           /*  等级太低, 无法打印          */}/** 格式化输出到缓存中* 如果显示设置了打印等级,则跳过设置,即不输出打印等级字串* 通过vsnprintf函数解析打印格式* 超出__MAX_MSG_LEN长度的内容会被丢弃*/if (bHaveLevel) {va_start(varlist, pcFormat);iRet = vsnprintf(pcBuffer, __MAX_MSG_LEN, &pcFormat[3], varlist);va_end(varlist);} else {va_start(varlist, pcFormat);iRet = vsnprintf(pcBuffer, __MAX_MSG_LEN, pcFormat, varlist);va_end(varlist);}logmsg.LOGMSG_pcPrintk = pcBuffer;logmsg.LOGMSG_pcFormat = pcFormat;logmsg.LOGMSG_bIsNeedHeader = LW_FALSE;                             /*  不需要打印头部              */logmsg.LOGMSG_ulThreadId    = LW_OBJECT_HANDLE_INVALID;/** 输出日志信息* 根据日志消息队列是否已初始化,选择通过内核调试接口输出还是* 先发送至消息队列,后由日志服务的线程再转发至日志文件集* 消息队列发送操作可能存在失败,失败时打印输出丢弃*/if (bBspMsg) {                                                      /*  log 还没有初始化            *///通过内核调试接口输出__logBspMsg(pcBuffer);} else {//先发送至消息队列,后由日志服务的线程再转发至日志文件集ulError = API_MsgQueueSend(_G_hLogMsgHandle, &logmsg, sizeof(LW_LOG_MSG));if (ulError) {__LOG_PRINTK_FREE_BUFFER(pcBuffer);_G_iLogMsgsLost++;_DebugHandle(__ERRORMESSAGE_LEVEL, "log message lost.\r\n");_ErrorHandle(ERROR_LOG_LOST);return  (PX_ERROR);}}return  (iRet);
}

这篇关于SylixOS里的打印【7】--- 内核日志信息打印接口printk的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/336114

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

MySQL 打开binlog日志的方法及注意事项

《MySQL打开binlog日志的方法及注意事项》本文给大家介绍MySQL打开binlog日志的方法及注意事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、默认状态二、如何检查 binlog 状态三、如何开启 binlog3.1 临时开启(重启后失效)

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

Golang 日志处理和正则处理的操作方法

《Golang日志处理和正则处理的操作方法》:本文主要介绍Golang日志处理和正则处理的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录1、logx日志处理1.1、logx简介1.2、日志初始化与配置1.3、常用方法1.4、配合defer