微服务日志知识点汇总

使用 Spring Boot 日志框架

为什么使用日志框架?

  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日志架构

当应用程序的日志从 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: 合并多行文本
posted @ 2018-12-18 22:56  ReyCG  阅读(4328)  评论(0编辑  收藏  举报