为什么使用日志框架?

  1. 日志可以输出到文件中,而不是输出到应用程序的控制台中,这样更容易收集和分析
  2. 可以通过异步多线程的方式,将日志输出到文件中,这样不会影响主线程,可以提高程序的吞吐量,节约性能。

通常使用的日志框架有 Log4J 等。

如何在 Spring Boot 中添加日志框架呢?Spring Boot 自带了一款名为 Spring Boot Logging 的插件,它已经为我们提供了日志实现。

使用 Spring Boot Logging 插件

Spring Boot 使用 Commons Logging 作为内部的日志框架,而它是一个日志接口,在实际应用中,我们需要为该接口提供相应的日志实现。Spring 的默认日志实现是 Java.Util.Logging,它是 JDK 自带的日志包,一般场景下很少被用到。Spring Boot 也提供了 Log4J, Logback 这类流行的日志实现,我们只要添加简单的配置,就能开启对这些日志的实现。

在 Java 应用程序中,日志一般分为 5 个级别: ERROR,WARN,INFO,DEBUG,TRACE。

Spring Boot Logging 默认输出到 INFO 级别,如果希望日志可以输出到 DEBUG 级别,需要在 application.yml 中添加如下配置

logging:
  level:
    root: DEBUG

在 java 文件中添加

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

...
 
private static Logger logger = LoggerFactory.getLogger(HelloController.class);

...
logger.debug("log ...");

就可以在运行代码时看到 debug 级别的日志了。

如果不想关注 Spring Boot 框架的日志,则可将日志级别统一设置成 ERROR ,此时只会输出 ERROR 级别的日志。随后,将 Spring Boot 应用程序指定的包设置成 DEBUG 级别的日志,就能看到只有指定包的日志了。

logging:
  level:
    root: ERROR
    demo:
      msa: DEBUG

默认情况下日志框架会将日志输出到控制台中,需要在 application.yml 文件中加入下面配置,才能将日志输出到文件中。

logging:
  level:
    root: ERROR
    demo:
      msa: DEBUG
  file: hello.log

集成 Log4J日志框架

首先需要在 pom.xml 中添加如下 Maven 配置,就能在 Spring Boot 中集成 Log4J。

	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter</artifactId>
	    <exclusions>
	        <exclusion>
	            <groupId>org.springframework.boot</groupId>
	            <artifactId>spring-boot-starter-logging</artifactId>
	        </exclusion>
	    </exclusions>
	</dependency>
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-log4j2</artifactId>
	</dependency>

在第一段中,先排除掉默认的 Logback 日志功能。在第二段的 dependency 配置中,我们自行添加 spring-boot-starter-log4j2 依赖,它是 Spring Boot 提供的 Log4J 插件。

配置完成 Maven 依赖配置后,下面需要在 resources 目录下添加 log4j2.xml 文件,具体内容如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appenders>
    	<File name="file" fileName="${sys:user.home}/logs/hello.log">
    		<PatternLayout pattern="%d{HH:mm:ss:SSS} %p %c (%L) - %m%n"/>
    	</File>
    </appenders>

    <loggers>
        <root level="ERROR">
            <appender-ref ref="file"/>
        </root>
        <logger name="demo.msa" level="DEBUG" />
    </loggers>
</configuration>

这个配置文件分成两部分, appendersloggers 。通过以上配置,就将 Log4j 集成到 Spring Boot 应用中。虽然日志已经成功输出到了文件中,但我们的微服务是以 Docker 容器的方式来运行的,此时输出的日志文件仍然和应用程序在一个 Docker 容器中,我们得想办法将日志文件输出到 Docker 容器外。也就是将数据和程序分离,以便后续更方便的获取并分析日志内容。

将日志输出到 Docker 容器外

最常用的方法就是,通过 Docker 数据卷的方式,将文件路径挂载到 Docker 容器上,这样日志文件自然与 Docker 文件分离了。启动命令如下

[tomcat@ ~]$ docker run -v ~/logs:/root/logs -d -p 18080:8081 demo.msa/mesa-hello:0.0.1-SNAPSHOT

这样就可以随时在宿主机上查看 Docker 容器内部的日志了。但我们还需要到文件中去查看,使用 docker logs 的方式获取日志内容则不会有此限制,一起来看下。

使用 Docker 容器日志

使用 docker logs 命令可以随时查看 Docker 容器内部应用程序运行时产生的日志,这样就可以避免首先进入 Docker 容器,在打开应用程序的过程了。

Docker logs 的执行过程如下: 它会监控容器中操作系统的标准输出设备 (STDOUT), 一旦 STDOUT 有产生,就会将这些数据传输到另一个设备中,该设备在 Docker 的世界中被称为日志驱动(Logging Driver)。

Docker 日志驱动

以 nginx 为例,通过下面 Docker 命令启动 Nginx 容器

docker run -d -p 80:80 --name nginx nginx

打开浏览器,在地址栏输入 http://localhost:80,就可以看到 nginx 的首页。这时就可以使用 docker logs 命令,查看 Nginx 容器的日志。

docker logs -f nginx

其中 -f 是指监控日志尾部的意思。

由此看出,只要 Docker 容器内部的应用程序在控制台中有日志输出,就能通过 docker logs 命令来查看响应的日志。那么 Docker 是如何做到的呢?

首先来执行下 命令

docker info |grep "Logging Driver"

可以得到 Docker 当前设置的日志驱动类型,就是 json-file

json-file 表示 JSON 文件,就是说 Docker 容器内部的应用程序输出的日志,将自动写入一个 JSON 文件中,并存放在 /var/lib/docker/containers/<container_id>目录中 <container_id>-json.log ,它就是要找的日志文件。

json-file 只是 Docker 日志驱动的一个默认选项,除了这个选项,我们还可以显式的指定其他的类型:

  • none 不输出任何日志
  • syslog 容器输出的日志写入宿主机的 Syslog
  • ...

我们可以在 docker run 命令中通过 --log-driver 参数来设置具体的 Docker 日志驱动。并且可以通过 --log-opt 参数来指定对应日志驱动的相关选项。就拿默认的 json-file 来说,可以这样来启动 Docker 容器。

 docker run -d -p 80:80 --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 --name nginx nginx:1.14

--log-opt 参数有两个选项:

  • max-file 表示 JSON 文件最多为 3 个
  • max-size 表示 JSON 文件最大为 10M,超过 10M 会自动生成新文件

在上面这些日志驱动类型,最为常用的是 Syslog, 它是 Linux 的日志系统,很多日志分析工具都可以从 Syslog 获取日志。比如流行的 ELK 日志中心,它包括下面 3 个部分

  • 日志存储 Elasticsearch
  • 日志收集 Logstash
  • 日志查询 Kibana 负责

在这 3 个组件中, Logstash 用于收集日志, Syslog 写入的日志可转发到 Logstash 中,随后会存储到 Elasticsearch 中。

使用 Docker 容器日志

Linux 日志系统:Syslog

默认情况下,Linux 操作系统已经安装了 syslog 软件包,叫做 Rsyslog。Rsyslog 是 syslog 标准的一种实现。

可以通过下面命令可以查看 Rsyslog 是否已经安装。

rsyslogd -v

如果要开启 Rsyslog 服务,必须对 Rsyslog进行配置,打开配置文件

vi /etc/rsyslog.conf

手工开启(去掉配置前面的注释),启动 TCP 链接的 Rsyslog 的 514 端口。

# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514

配置文件修改完毕后,手工重启 Rsyslog 服务。

service rsyslog restart
or
systemctl restart rsyslog

检查下本地是否对外开启了 514 端口。

[root@ ~]# netstat -anpt |grep 514
tcp        0      0 0.0.0.0:514                 0.0.0.0:*                   LISTEN      63516/rsyslogd
tcp        0      0 :::514                      :::*                        LISTEN      63516/rsyslogd

下面就启动 Nginx 容器,并选择 Syslog 作为日志驱动。

docker run -d -p 80:80 --log-driver syslog --log-opt syslog-address=tcp://localhost:514 --name nginx nginx

其中

  • --log-driver 表示指定 Syslog 为日志驱动
  • --log-opt 指定了 Docker 环境可以通过 TCP 协议连接本地的 514 端口

可以使用下面命令来查看 linux 系统日志文件,该文件的内容就是 Syslog 所生成的日志

tail -f /var/log/messages

通常会在一台宿主机上同时运行多个 Docker 容器,如果每个容器都通过 Syslog 来聚合日志,那么在系统日志文件通过 Docker 容器的 ID 是很难识别出是哪个容器的。如何能区分某条日志是来自哪个容器呢?

Docker 日志驱动已经为我们提供了支持,只需要在 --log-opt 参数中添加一个 tag 选项,并在这个选项上给出恰当的命名,就能更好的识别出相应的日志。

docker run -d -p 80:80 --log-driver syslog --log-opt syslog-address=tcp://localhost:514 --log-opt tag="nginx" nginx:1.14

将 tag 选项设置成 nginx (容器名称),就能在日志中看到带有 nginx 的标识,这样我们可以更加容易的识别这条日志来自 Nginx 容器。

如果不指定 tag 选项,则默认的 tag 为容器 ID 的前 12 个字符。也可以在 tag 选项中使用 Docker 已经提供的模板标签,可将这些标签理解为 tag 选项中的占位符。

  • {{.ID}} : 容器 ID 的前 12 个字符
  • {{.FullID}} 容器 ID 的完整名称
  • {{.Name}} 容器名称
  • {{.ImageID}} 容器镜像 ID 的前 12 个字符
  • {{.ImageName}} 容器镜像名称

下面将这些 tag 标签来个大融合

 docker run -d -p 80:80 -v /etc/localtime:/etc/localtime --log-driver syslog --log-opt syslog-address=tcp://localhost:514 --log-opt tag="{{.ImageName}}/{{.Name}}/{{.ID}}" nginx:1.14

docker 时区问题

 docker run -d -p 80:80 -v /etc/localtime:/etc/localtime --log-driver syslog --log-opt syslog-address=tcp://localhost:514 --log-opt tag="{{.ImageName}}/{{.Name}}/{{.ID}}" nginx:1.14

重点是 -v /etc/localtime:/etc/localtime 当然还有其他方法,可参考这篇链接 http://www.cnblogs.com/zengming/p/10190317.html

Docker 日志架构

Docker 容器中的应用程序 Application 将日志吸入到标准输出设备 STDOUT, Docker Daemon 负责从 STDOUT 中获取日志,并将日志写入对应的日志驱动中。

微服务日志知识点汇总

当应用程序的日志从 Docker 容器内部写入宿主机的 Syslog 中后,后面我们要做的就是将 Syslog 中的日志转发到 ELK 平台的 Logstash 中,从而建立我们需要的日志中心

微服务日志知识点汇总

搭建应用日志中心

开源日志中心: ELK

Elastic 官方推出了 6 款开源产品

  • Kibana: 用于数据可视化
  • Elasticsearch: 用于数据搜索,分析与存储
  • Logstash: 用于数据收集,将数据存入 Elasticsearch 中
  • Beats: 用于数据传输,将数据从磁盘传输到 Logstash 中
  • X-Pack: 提供了一些扩展功能,包括安全,预警,监控,报表和图形化等
  • Elasticsearch Cloud: 提供 Elastic 栈的云服务,提供公有云与私有云的解决方案

日志收集系统

Logstash 是一款开源的数据收集引擎,它既提供了实时管道数据能力,也提供了灵活的插件机制。我们可以自由选择已有的插件,也能自行开发所需的插件。我们使用 Logstash 更多的时候都在做参数配置,以实现我们所需的功能。

从系统架构的角度来看,它提供了 3 个内部组件,分别是输入组件,过滤组件,输出组件,而且每个组件都提供了插件机制。可以将这些组件及其插件想象成一个管道(pipeline),数据从数据源(Data Source)流向 INPUTS,FILTERS,OUTPUT,最终到达 Elasticsearch 中存储。

微服务日志知识点汇总

上面 3 个组件包含的常用插件如下:

  1. 输入插件
    1. file: 读取文本文件
    2. syslog: 读取 syslog,包含 Rsyslog
    3. redis: 读取 Redis 消息队列
    4. beats: 处理 Filebeat 事件
  2. 过滤插件
    1. grok: 解析日志文本
    2. mutate: 修改事件字段
    3. drop: 删除事件
    4. clone: 复制事件
    5. geoip: 添加 IP 地理位置
  3. 输出插件
    1. elasticsearch: 写入 elasticsearch
    2. file: 写入文本文件
    3. graphite: 一种开源工具,用于存储与图形化指标
    4. statsd: 写入 statsd 统计服务,监听 UDP 端口
  4. 编解码插件
    1. json:编解码为 json 格式
    2. multiline: 合并多行文本

相关文章:

  • 2021-05-15
  • 2021-05-01
  • 2021-05-31
  • 2021-11-04
  • 2017-12-02
  • 2021-07-01
  • 2022-01-28
  • 2021-06-29
猜你喜欢
  • 2021-04-12
  • 2021-06-22
  • 2022-02-05
  • 2021-10-14
  • 2021-06-29
  • 2021-05-19
  • 2021-12-19
相关资源
相似解决方案