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

相关文章

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

java -jar example.jar 产生的日志输出到指定文件的方法

《java-jarexample.jar产生的日志输出到指定文件的方法》这篇文章给大家介绍java-jarexample.jar产生的日志输出到指定文件的方法,本文给大家介绍的非常详细,对大家的... 目录怎么让 Java -jar example.jar 产生的日志输出到指定文件一、方法1:使用重定向1、

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

nginx配置错误日志的实现步骤

《nginx配置错误日志的实现步骤》配置nginx代理过程中,如果出现错误,需要看日志,可以把nginx日志配置出来,以便快速定位日志问题,下面就来介绍一下nginx配置错误日志的实现步骤,感兴趣的可... 目录前言nginx配置错误日志总结前言在配置nginx代理过程中,如果出现错误,需要看日志,可以把

基于Redisson实现分布式系统下的接口限流

《基于Redisson实现分布式系统下的接口限流》在高并发场景下,接口限流是保障系统稳定性的重要手段,本文将介绍利用Redisson结合Redis实现分布式环境下的接口限流,具有一定的参考价值,感兴趣... 目录分布式限流的核心挑战基于 Redisson 的分布式限流设计思路实现步骤引入依赖定义限流注解实现

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

使用Python的requests库调用API接口的详细步骤

《使用Python的requests库调用API接口的详细步骤》使用Python的requests库调用API接口是开发中最常用的方式之一,它简化了HTTP请求的处理流程,以下是详细步骤和实战示例,涵... 目录一、准备工作:安装 requests 库二、基本调用流程(以 RESTful API 为例)1.