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

相关文章

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

go中空接口的具体使用

《go中空接口的具体使用》空接口是一种特殊的接口类型,它不包含任何方法,本文主要介绍了go中空接口的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录接口-空接口1. 什么是空接口?2. 如何使用空接口?第一,第二,第三,3. 空接口几个要注意的坑坑1:坑2:坑3:接口-空接口1. 什么是空接

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

golang 日志log与logrus示例详解

《golang日志log与logrus示例详解》log是Go语言标准库中一个简单的日志库,本文给大家介绍golang日志log与logrus示例详解,感兴趣的朋友一起看看吧... 目录一、Go 标准库 log 详解1. 功能特点2. 常用函数3. 示例代码4. 优势和局限二、第三方库 logrus 详解1.

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

SpringBoot项目使用MDC给日志增加唯一标识的实现步骤

《SpringBoot项目使用MDC给日志增加唯一标识的实现步骤》本文介绍了如何在SpringBoot项目中使用MDC(MappedDiagnosticContext)为日志增加唯一标识,以便于日... 目录【Java】SpringBoot项目使用MDC给日志增加唯一标识,方便日志追踪1.日志效果2.实现步

SQL Server清除日志文件ERRORLOG和删除tempdb.mdf

《SQLServer清除日志文件ERRORLOG和删除tempdb.mdf》数据库再使用一段时间后,日志文件会增大,特别是在磁盘容量不足的情况下,更是需要缩减,以下为缩减方法:如果可以停止SQLSe... 目录缩减 ERRORLOG 文件(停止服务后)停止 SQL Server 服务:找到错误日志文件:删除

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新