随着 systemd 成了主流的 init 系统,systemd 的功能也在不断的增加,比如对系统日志的管理。Systemd 设计的日志系统好处多多,这里笔者就不再赘述了,本文笔者主要介绍 systemd journal 收集日志的三种方式:

  • 程序使用 libc 库中的 syslog() 函数输出的日志
  • 使用 printf() 函数打印的日志
  • 任何服务进程输出到 STDOUT/STDERR 的所有内容

说明:本文的演示环境为 ubuntu 16.04。

syslog()

该函数的声明如下:

#include <syslog.h>
void syslog(int priority, const char *message, ... /* argument */);

创建下面的 C 语言代码,并保存到文件 clog.c 文件中:

#include <syslog.h>

int main(int argc, char *argv[]) {
syslog(LOG_NOTICE, "C Hello World");
return ;
}

用下面的命令编译程序:

$ gcc -Wall clog.c -o clog

然后执行编译好的 clog 程序,就可以从 journal -f 的输出中看到对应的日志:

这里笔者执行了三次 clog 程序,所以日志输出了三遍。
代码中的 LOG_NOTICE 代表日志的严重等级,我们可以使用下面定义好的等级:

#define    LOG_EMERG    0    /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */

下面尝试在 python 代码中做同样的事情,把下面的代码保存到文件 plog.py 中:

#!/usr/bin/evn python

import syslog
syslog.syslog('P Hello World')

然后执行下面的命令:

$ python plog.py

笔者同样执行了三遍,这次输出的是 python 代码中的日志。

我们还可以通过 journalctl -o json-pretty -f 命令查看 json 格式的日志:

printf()

journal 可以捕获服务进程往 STDOUT/STDERR 输出的所有内容,比如 C 语言中 print 函数打印的内容,Python 中 print 打印的内容,以及 Shell 脚本中 echo 打印的内容等等都可以被 journal 捕获到并加入到日志中。注意,只有以 service 的方式运行程序时,journal 才会捕获 STDOUT/STDERR 输出的内容。
创建下面的 C 语言代码,并保存到文件 printlog.c 文件中:

#include <stdio.h>

int main(int argc, char *argv[]) {
printf("C Print Hello World.\n");
return ;
}

用下面的命令编译程序:

$ gcc -Wall printlog.c -o printlog

配置一个简单的 service,先创建 一个配置文件  /lib/systemd/system/testlog.service,其内容如下:

[Unit]
Description=test log [Service]
ExecStart=/home/nick/projects/journaldemo/printlog [Install]
WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl start testlog.service

Journal 会捕获 STDOUT/STDERR 输出的内容:

默认情况下,这样输出的日志等级为 LOG_INFO(6),我们可以通过 json 格式的日志看到日志等级信息:

我们还可以在打印日志时指定日志的等级,比如在每行打印的内容前加上"<N>",N为需要指定的日志等级。看下面的 C 语言示例:

#include<stdio.h>

#define PREFIX_NOTICE "<5>"

int main(void){
printf(PREFIX_NOTICE "Hello World\n");
fprintf(stderr, "<3>Hello Error\n"); return ;
}

把上面的代码编译为 printlog 程序,再查看下日志,显示的就是我们自己设置的日志等级:

在 Python 中的用法如下:

#!/usr/bin/env python
print '<5>Hello World'

在 bash 中的用法如下:

#!/bin/bash
echo "<5>Hello World"

Systemd 日志库

Systemd 提供了原生的 C 语言库(systemd/sd-journal.h) 用于向 journal 输出日志(ubuntu 16.04 需要通过 sudo apt install libsystemd-dev 命令安装 libsystemd-dev 包),相关函数的声明为:

#include <systemd/sd-journal.h>
int sd_journal_print(int priority, const char *format, ...);
int sd_journal_send(const char *format, ...);

把下面的示例代码会把日志发送给 journal:

#include <systemd/sd-journal.h>

int main(int argc, char *argv[]) {
sd_journal_print(LOG_NOTICE, "Hello World");
return ;
}

相比上文使用 print() 或者 syslog() 提交的日志,使用 sd_journal_print 可以直观的指定 LOG 等级、日志内容等等,另外输出的日志会包含执行代码的位置信息,例如执行到的函数,代码文件位置,代码具体行数,方便开发人员调试。

除了可以包含代码信息,也可以向提交的日志中加入自定义段包含更多自定义信息,配合 journalctl 工具,可以更方便的过滤日志,如下面的代码:

#include <systemd/sd-journal.h>
#include <unistd.h>
#include <stdlib.h> int main(int argc, char *argv[]) {
sd_journal_send("MESSAGE=Hello World!",
"MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555",
"PRIORITY=5",
"HOME=%s", getenv("HOME"),
"TERM=%s", getenv("TERM"),
"PAGE_SIZE=%li", sysconf(_SC_PAGESIZE),
"N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN),
NULL);
return ;
}

我们在日志中添加了自定义的字段,并且可以通过 journalctl 过滤这些字段。

除了 systemd 提供的一套C语言库,目前其他个别语言也衍生了 systemd 的相关扩展,其中就包含了和 journald 相关的扩展。下面是段 python 的演示代码:

from systemd import journal
journal.send('Hello world')
journal.send('Hello, again, world', FIELD2='Greetings!', FIELD3='Guten tag')

在运行上面的代码前你需要先通过 pip 安装 python 的 systemd 模块(pip install systemd ),然后运行这段代码,你就可以从日志中看到它输出的信息了:

展开成 json 格式看下:

我们自定义的字段 FIELD2 和 FIELD3 也都输出到日志中了。

总结

本文介绍了常见的一些往 systemd journal 中写入日志的方式,了解这些日志的写入方式可以帮助我们更好的设计应用的日志输出,并有助于我们通过日志解决问题。

参考:
Systemd 日志管理相关
systemd for Developers III

通过 Systemd Journal 收集日志的更多相关文章

  1. Linux 系统 /var/log/journal/ 垃圾日志清理

    CentOS系统中有两个日志服务,分别是传统的 rsyslog 和 systemd-journal systemd-journald是一个改进型日志管理服务,可以收集来自内核.系统早期启动阶段的日志. ...

  2. ELK收集日志到mysql

    场景需求 在使用ELK对日志进行收集的时候,如果需要对数据进行存档,可以考虑使用数据库的方式.为了便于查询,可以同时写一份数据到Elasticsearch 中. 环境准备 CentOS7系统: 192 ...

  3. ELK快速入门(二)通过logstash收集日志

    ELK快速入门二-通过logstash收集日志 说明 这里的环境接着上面的ELK快速入门-基本部署文章继续下面的操作. 收集多个日志文件 1)logstash配置文件编写 [root@linux-el ...

  4. ELK快速入门(四)filebeat替代logstash收集日志

    ELK快速入门四-filebeat替代logstash收集日志 filebeat简介 Filebeat是轻量级单用途的日志收集工具,用于在没有安装java的服务器上专门收集日志,可以将日志转发到log ...

  5. ELK收集日志到mysql数据库

    场景需求 在使用ELK对日志进行收集的时候,如果需要对数据进行存档,可以考虑使用数据库的方式.为了便于查询,可以同时写一份数据到Elasticsearch 中. 环境准备 CentOS7系统: 192 ...

  6. nginx日志切割并使用flume-ng收集日志

    nginx的日志文件没有rotate功能.如果你不处理,日志文件将变得越来越大,还好我们可以写一个nginx日志切割脚本来自动切割日志文件.第一步就是重命名日志文件,不用担心重命名后nginx找不到日 ...

  7. 使用开源软件sentry来收集日志

    原文地址:http://luxuryzh.iteye.com/blog/1980364 对于一个已经上线的系统,存在未知的bug或者运行时发生异常是很常见的事情,随之而来的几点需求产生了: 1.系统发 ...

  8. nswl 收集日志

    nswl 收集日志 参考链接:https://docs.citrix.com/en-us/citrix-adc/12-1/system/web-server-logging.html PS C:\Us ...

  9. rancher使用fluentd-pilot收集日志分享

    fluentd-pilot简介 fluentd-pilot是阿里开源的docker日志收集工具,Github项目地址:https://github.com/AliyunContainerService ...

随机推荐

  1. XML 和 DTD

    1.XML 1.1xml简介 a)xml,eXtensible Markup Language,可扩展标记语言,是一种标记语言: b)xml是一种非常灵活的语言,没有固定的标签,所有的额标签都可以自定 ...

  2. Python MySQL事务、引擎、索引及第三方库sqlalchemy

    本节内容 1.数据库介绍2.事务3.引擎4.索引5.ORM sqlalchemy 1.数据库介绍 什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,每个数据库都有一 ...

  3. mssql sqlserver两条求和sql脚本相加的方法分享

    转自:http://www.maomao365.com/?p=7205 摘要: 下文分享两条sql求和脚本,再次求和的方法分享 /* 例: 下文已知两条sql求和脚本,现需对两张不同表的求和记录再次求 ...

  4. ArcGIS Server服务器监控

    最近项目上需要对服务器与ArcGISServer服务进行监控,做了一个初步的原型,实现了以下功能. 一.服务器监控 注册服务器 服务器运行状态监控 在线状态 CPU.内存.存储配置监控,由于现在很多采 ...

  5. Linux系统中Redis和Tomcat的PID文件路径设置

    Tomcat: /bin/catalina.sh 文件头注释下面添加一行:CATALINA_PID=/var/run/tomcat.pid Redis: redis.conf配置文件里面搜索pidfi ...

  6. IO Redirect 与 Pipe

    对于任何一个进程,在启动时,都会打开三个流:stdin(标准输入), stdout(标准输出), stderr(标准错误输出).Stdout,stderr是process与Display之间,stdi ...

  7. xshell远程登录工具的星号密码查看方法

    当我们在使用ftp,或者xshell等远程登录工具的时候,连接的密码是用星号*处理的,无法查看到,该如何查看到原始的密码呢? 推荐一款星号密码查看器,可以查看一些软件的带星号的密码,非常好用. 下载地 ...

  8. LeetCode算法题-Longest Palindrome(五种解法)

    这是悦乐书的第220次更新,第232篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第87题(顺位题号是409).给定一个由小写或大写字母组成的字符串,找到可以用这些字母构 ...

  9. puppet 横向扩展(二)

    Table of Contents 1. 概述 2. 实验环境 3. 实验步骤 3.1. 机器B 的环境 3.1.1. 安装puppetmaster 以及 apache passenger 3.1.2 ...

  10. python requests提示警告InsecureRequestWarning

    在Python3中使用以下代码报错: import requests response = requests.get(url='', verify=False) 错误代码如下: InsecureReq ...