Linux syslog 使用方法

发布于:2025-08-07 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、syslog 机制原理

1. 基本概念

  • syslog 是 Linux 系统中实现日志记录的标准机制,用于系统进程、内核及应用程序将日志信息发送到中央日志服务器或本地文件。
  • syslog 三要素:
    • 日志生成者:内核模块、用户进程通过特定 API 生成日志。
    • 日志传输:通过 Unix 域套接字、网络协议(UDP/TCP)传输日志。
    • 日志处理者:syslog 守护进程接收并存储日志。

2. 工作流程

  1. 日志生成:
    • 内核通过printk将消息写入内核环形缓冲区。
    • 用户进程通过syslog()API 发送日志到本地 syslog 套接字。
  2. 日志收集:
    • syslog 守护进程监听本地套接字(如/dev/log)和网络端口(UDP 514/TCP 514)。

3. 日志优先级

syslog 定义了 8 个日志级别,从高到低为:

LOG_EMERG    (0) 系统不可用
LOG_ALERT    (1) 必须立即处理
LOG_CRIT     (2) 严重情况
LOG_ERR      (3) 错误情况
LOG_WARNING  (4) 警告情况
LOG_NOTICE   (5) 正常但值得注意
LOG_INFO     (6) 一般信息
LOG_DEBUG    (7) 调试信息

二、syslog 在内核中的使用方法

1. 使用 printk 输出内核日志

  • 基本语法:

    printk(KERN_LEVEL "日志消息\n");
    

    示例:

    printk(KERN_ERR "磁盘I/O错误: 设备未响应\n");
    

2. 常用内核日志级别

#define KERN_EMERG  "<0>"  /* 系统崩溃 */
#define KERN_ALERT  "<1>"  /* 必须立即处理 */
#define KERN_CRIT   "<2>"  /* 严重错误 */
#define KERN_ERR    "<3>"  /* 错误 */
#define KERN_WARNING "<4>" /* 警告 */
#define KERN_NOTICE "<5>"  /* 正常但需注意 */
#define KERN_INFO   "<6>"  /* 信息 */
#define KERN_DEBUG  "<7>"  /* 调试 */

3. 动态调整日志级别

  • 查看当前日志级别:

    cat /proc/sys/kernel/printk
    

    输出格式:当前控制台日志级别 默认日志级别 最低日志级别 默认控制台日志级别

  • 临时修改日志级别:

    echo "8 4 1 7" > /proc/sys/kernel/printk  # 提高控制台日志级别
    

4. 内核模块示例

示例代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int __init demo_init(void) {
    printk(KERN_INFO "syslog_demo: 模块加载成功\n");
    return 0;
}

static void __exit demo_exit(void) {
    printk(KERN_INFO "syslog_demo: 模块卸载成功\n");
}

module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

三、syslog 在用户空间的使用方法

1. C 语言 API 使用

  • 步骤

    1. 调用openlog()初始化连接

    2. 使用setlogmask(LOG_UPTO(log_level))设置日志掩码(只记录高于或等于指定级别的日志)

    3. 使用syslog()发送日志

    4. 调用closelog()关闭连接

      注:LOG_UPTO 宏是通过位操作来实现的,它会根据传参生成一个掩码。

      #define LOG_UPTO(pri)     ((1 << ((pri)+1)) - 1) /* all priorities through pri */
      
  • 示例代码

    #include <syslog.h>
    
    #define DEFAULT_LOG_LEVEL LOG_INFO
    
    int main() {
        int log_level = DEFAULT_LOG_LEVEL;
        // 初始化syslog连接
        openlog("myapp", LOG_PID | LOG_CONS, LOG_USER);
        
        // 设置日志掩码(只记录高于或等于指定级别的日志)
        setlogmask(LOG_UPTO(log_level));
        
        // 记录不同级别的日志
        syslog(LOG_INFO, "程序启动成功");
        syslog(LOG_INFO, "hello zgl");
        syslog(LOG_WARNING, "配置文件不存在,使用默认配置");
        
        // 带参数的日志
        int error_code = 500;
        syslog(LOG_ERR, "处理请求失败,错误码: %d", error_code);
        
        // 关闭连接
        closelog();
        return 0;
    }
    

运行两次,预计打印两次 log 信息。
在这里插入图片描述

查看 log :

sudo sh -c 'journalctl SYSLOG_IDENTIFIER=myapp > /var/log/myapp.log'
cat myapp.log

在这里插入图片描述

2. 命令行工具

logger 基本语法:

Usage: logger [OPTIONS] [MESSAGE]

Write MESSAGE (or stdin) to syslog

        -s      Log to stderr as well as the system log
        -t TAG  Log using the specified tag (defaults to user name)
        -p PRIO Priority (numeric or facility.level pair)
  • -s:不仅写入系统日志,同时输出到标准错误(stderr)(方便终端查看)
  • -t TAG:指定日志的标签(默认是当前用户名)
  • -p PRIO:设置优先级,格式为 facility.level(如 user.error)或数字

应用示例:在终端输入以下命令

logger -s "Debug message"
logger -t myapp "zgl_app_test"
logger -p user.info "zgltest"

然后查看日志:

tail -f syslog | grep "Debug message"
tail -f syslog | grep "zgl_app_test"
tail -f syslog | grep "zgltest"

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、在开发板示例

应用层:syslog_demo_user.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>

#define DEFAULT_LOG_LEVEL LOG_INFO
#define APP_NAME "syslog_demo_user"

int main(int argc, char *argv[]) {
    int log_level = DEFAULT_LOG_LEVEL;

    // 打开syslog连接
    openlog(APP_NAME, LOG_PID | LOG_CONS, LOG_USER);

    // 设置日志掩码(只记录高于或等于指定级别的日志)
    setlogmask(LOG_UPTO(log_level));

    // 记录不同级别的日志
    syslog(LOG_EMERG, "TEST syslog This is emerg");
    syslog(LOG_ALERT, "ALERT: This is ALERT");
    syslog(LOG_CRIT, "CRIT: This is CRIT");
    syslog(LOG_ERR, "ERR: This is CRIT");
    syslog(LOG_WARNING, "WARNING: This is WARNING");
    syslog(LOG_NOTICE, "NOTICE: This is NOTICE");
    syslog(LOG_INFO, "INFO: This is INFO");
    syslog(LOG_DEBUG, "DEBUG: This is DEBUG");

    // 关闭syslog连接
    closelog();

    return 0;
}

驱动层:syslog_demo_kernel.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static char *module_name = "syslog_demo_kernel";
module_param(module_name, charp, 0644);
MODULE_PARM_DESC(module_name, "syslog_demo name");

static char *message = "syslog message test";
module_param(message, charp, 0644);
MODULE_PARM_DESC(message, "message text param");

static int __init syslog_demo_init(void)
{
    printk(KERN_EMERG "[%s] emerg: syslog_demo module load\n", module_name);
    printk(KERN_ALERT "[%s] alert: syslog_demo module load\n", module_name);
    printk(KERN_CRIT "[%s] crit: syslog_demo module load\n", module_name);
    printk(KERN_ERR "[%s] err: syslog_demo module load\n", module_name);
    printk(KERN_WARNING "[%s] warning: module_name = %s\n", module_name, module_name);
    printk(KERN_INFO "[%s] info: text = %s\n", module_name, message);
    printk(KERN_DEBUG "debug: syslog_demo debug\n");
    
    return 0;
}

static void __exit syslog_demo_exit(void)
{
    printk(KERN_ERR "[%s] err: syslog_demo module rmmod\n", module_name);
    
    printk(KERN_WARNING "[%s] warning: syslog_demo module rmmod\n", module_name);
    
    printk(KERN_INFO "info: syslog_demo rmmod finish\n");

    printk(KERN_DEBUG "debug: syslog_demo release ipc\n");
}

module_init(syslog_demo_init);
module_exit(syslog_demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxxxx");
MODULE_DESCRIPTION("Syslog demo");

Makefile:

# 基础配置
a-cockpit_DIR ?= /home/zgl/New/a-cockpit
KERNEL_DIR ?= $(a-cockpit_DIR)/kernel/
ARCH ?= arm
CROSS_COMPILE ?= $(a-cockpit_DIR)/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
export ARCH CROSS_COMPILE

CROSS_COMPILE_USER ?= $(a-cockpit_DIR)/prebuilts/gcc/linux-x86/arm/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-

# 模块定义
obj-m := syslog_demo_kernel.o
USER_MODULE := syslog_demo_user

# 输出目录配置
OUTPUT_DIR ?= $(CURDIR)/output
KERNEL_MODULE_DIR := $(OUTPUT_DIR)/kernel_modules
USER_MODULE_DIR := $(OUTPUT_DIR)/user_binaries

# 创建输出目录
$(shell mkdir -p $(KERNEL_MODULE_DIR) $(USER_MODULE_DIR))

# 内核模块编译目标
all: kernel_module user_module

kernel_module:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
	@cp -f *.ko $(KERNEL_MODULE_DIR)/ 2>/dev/null || true

# 用户空间模块编译目标
user_module: $(USER_MODULE).c
	$(CROSS_COMPILE_USER)gcc -o $(USER_MODULE_DIR)/$(USER_MODULE) $(USER_MODULE).c

.PHONY: clean
clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
	rm -rf $(OUTPUT_DIR)

编译生成:syslog 可执行程序和可加载的内核模块
在这里插入图片描述

将生成的可执行程序和内核模块传输到开发板:

在这里插入图片描述

在开发板上运行可执行程序和加载内核模块,并实时查看 log:

tail -n 0 -f syslog

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到