实战 | 后端日志的前世今生 - mySoul

/ 0评 / 0

小小这里对后端日志技术体系进行分析,这里将会阐述后端日志的前世今生。从小到大

程序控制台日志

这里使用System.out.println 进行打印,输出相关的控制台的信息。
编写代码如下

System.out.println("hello world")

这里将会直接输出相关的日志内容:

Hello World

这就完成了最简单的程序控制台的日志的输出

单体应用日志

这里将会针对单体应用,实现相关的日志系统。
这里主要使用的将会是Log4J,slf4j
这里针对单体应用实现简单的入门

Log4J

新建maven文件

<!-- log4j support -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

新建配置文件

这里进行新建配置文件
配置文件信息如下

 ### 设置###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=/home/duqi/logs/debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = /home/duqi/logs/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=/home/admin/logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =/home/admin/logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

输出日志

这里进行日志的信息的输出
使用 logger.debug 进行简单的输出

package com.javadu.log;

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

public class Log4JTest {
    private static final Logger logger = LoggerFactory.getLogger(Log4JTest.class);

    public static void main(String[] args) {
        // 记录debug级别的信息
        logger.debug("This is debug message.");
        // 记录info级别的信息
        logger.info("This is info message.");
        // 记录error级别的信息
        logger.error("This is error message.");
    }
}

控制台输出

这里控制台进行相关的输出。输出的内容如下

如此就完成了控制台的基本的输出

slf4j

这里针对 slf4j 进行相关的输出。

定义

什么是slf4j
slf4j只是定义了一组日志接口,但并未提供任何实现 只需要针对这个日志接口进行相关的实践,就能完成基本的定义。

使用教程

添加maven包

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.21</version>
</dependency>

添加两个日志的关联包

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.21</version>
</dependency>

针对代码声明进行更改

这里针对代码的声明进行相关的更改

import org.apache.log4j.Logger;
class Test {
    final Logger log = Logger.getLogger(Test.class);
    public void test() {
        log.info("hello this is log4j info log");
    }
}

更改为

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class Test {
    Logger log = LoggerFactory.getLogger(Test.class);
    public void test() {
        log.info("hello, my name is {}", "chengyi");
    }
}

这样就完成了两个日志的联合使用

ELK使用

这里添加ELK进行基本的使用

三个软件的简介

Logstash

Logstash 主要用于收集服务器日志,它是一个开源数据收集引擎,具有实时管道功能。Logstash 可以动态地将来自不同数据源的数据统一起来,并将数据标准化到您所选择的目的地。

Logstash 收集数据的过程主要分为以下三个部分:

输入:数据(包含但不限于日志)往往都是以不同的形式、格式存储在不同的系统中,而 Logstash 支持从多种数据源中收集数据(File、Syslog、MySQL、消息中间件等等)。
过滤器:实时解析和转换数据,识别已命名的字段以构建结构,并将它们转换成通用格式。
输出:Elasticsearch 并非存储的唯一选择,Logstash 提供很多输出选择。

Elasticsearch

Elasticsearch (ES)是一个分布式的 Restful 风格的搜索和数据分析引擎,它具有以下特点:

查询:允许执行和合并多种类型的搜索 — 结构化、非结构化、地理位置、度量指标 — 搜索方式随心而变。
分析:Elasticsearch 聚合让您能够从大处着眼,探索数据的趋势和模式。
速度:很快,可以做到亿万级的数据,毫秒级返回。
可扩展性:可以在笔记本电脑上运行,也可以在承载了 PB 级数据的成百上千台服务器上运行。
弹性:运行在一个分布式的环境中,从设计之初就考虑到了这一点。
灵活性:具备多个案例场景。支持数字、文本、地理位置、结构化、非结构化,所有的数据类型都欢迎。

Kibana

Kibana 可以使海量数据通俗易懂。它很简单,基于浏览器的界面便于您快速创建和分享动态数据仪表板来追踪 Elasticsearch 的实时数据变化。其搭建过程也十分简单,您可以分分钟完成 Kibana 的安装并开始探索 Elasticsearch 的索引数据 — 没有代码、不需要额外的基础设施。

对于以上三个组件在 《ELK 协议栈介绍及体系结构》 一文中有具体介绍,这里不再赘述。

在 ELK 中,三大组件的大概工作流程如下图所示,由 Logstash 从各个服务中采集日志并存放至 Elasticsearch 中,然后再由 Kiabana 从 Elasticsearch 中查询日志并展示给终端用户。

图 1. ELK 的大致工作流程

图 1. ELK 的大致工作流程

安装 Logstash

  1. 解压压缩包:
tar -xzvf logstash-7.3.0.tar.gz
  1. 简单用例测试,进入到解压目录,并启动一个将控制台输入输出到控制台的管道。
cd logstash-7.3.0
elk@elk:~/elk/logstash-7.3.0$ bin/logstash -e 'input { stdin {} } output { { stdout {} } }'
  1. Logstash 启动成功日志

安装 Elasticsearch

  1. 解压安装包
tar -xzvf elasticsearch-7.3.0-linux-x86_64.tar.gz
  1. 启动 Elasticsearch:
cd elasticsearch-7.3.0/
bin/elasticsearch

安装 Kibana

  1. 解压安装包:
tar -xzvf kibana-7.3.0-linux-x86_64.tar.gz
  1. 修改配置文件 config/kibana.yml ,主要指定 Elasticsearch 的信息。
#Elasticsearch主机地址
elasticsearch.hosts: "http://ip:9200"
# 允许远程访问
server.host: "0.0.0.0"
# Elasticsearch用户名 这里其实就是我在服务器启动Elasticsearch的用户名
elasticsearch.username: "es"
# Elasticsearch鉴权密码 这里其实就是我在服务器启动Elasticsearch的密码
elasticsearch.password: "es"
  1. 启动 Kibana:

启动 Kibana:

cd kibana-7.3.0-linux-x86_64/bin
./kibana
  1. 在浏览器中访问 http://ip:5601 ,若出现以下界面,则表示 Kibana 安装成功。

在 Spring Boot 中使用 ELK

修改并部署 Spring Boot 项目

  1. 在项目 resources 目录下创建 spring-logback.xml 配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <contextName>Logback For demo Mobile</contextName>
    <property name="LOG_HOME" value="/log" />
    <springProperty scope="context" name="appName" source="spring.application.name"
                    defaultValue="localhost" />
    ...

    <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        ...
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{25} ${appName} -%msg%n</pattern>
        </encoder>
        ...
    </appender>
    ...
</configuration>
  1. 打包并部署 Spring Boot 项目
# 打包命令
mvn package -Dmaven.test.skip=true
# 部署命令
java -jar sb-elk-start-0.0.1-SNAPSHOT.jar
  1. 查看日志文件, logback 配置文件中我将日志存放在 /log/sb-log.log 文件中,执行 more /log/sb-log.log 命令,出现以下结果表示部署成功。

docker 日志

查看容器日志

先使用 docker run -it --rm -d -p 80:80 nginx:1.15.8-alpine 命令启动一个nginx容器。如果没有异常,会得到容器ID如 d2408a7931c95a3a83ffeca2fba887763cf925a67890ef3be4d9ff838aa25b00 的长串。再使用 curl -i http://127.0.0.1 访问服务,确认nginx容器正常启动运行。最后使用 docker logs -f d24 查看容器的日志输出,大概如下:

172.17.0.1 - - [24/Mar/2019:03:51:21 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

容器日志文件存储

容器的日志会以json文件方式存储在本地磁盘,可以使用下面方式查看文件路径 docker inspect d42 | grep Log 可以找到:

"LogPath": "/var/lib/docker/containers/d2408a7931c95a3a83ffeca2fba887763cf925a67890ef3be4d9ff838aa25b00/d2408a7931c95a3a83ffeca2fba887763cf925a67890ef3be4d9ff838aa25b00-json.log",

容器日志文件滚动策略

docker容器日志默认写入json文件,在线上运行时候会有磁盘写满的风险。可以调整策略,让其进行滚动。修改/etc/docker/daemon.json(如果没有就手工创建一个),增加下面内容:

{
  "log-opts": {
    "max-size": "1m",
    "max-file": "3"
  }
}

k8s 日志信息

编写yml进行相关的配置信息

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']

获取日志信息

[root@node1 blog]# kubectl get pod |grep counter
counter            1/1     Running   0          9s
[root@node1 blog]# kubectl logs counter
0: Fri May 17 00:34:01 UTC 2019
1: Fri May 17 00:34:02 UTC 2019
2: Fri May 17 00:34:03 UTC 2019
3: Fri May 17 00:34:04 UTC 2019
4: Fri May 17 00:34:05 UTC 2019
5: Fri May 17 00:34:06 UTC 2019
6: Fri May 17 00:34:07 UTC 2019
7: Fri May 17 00:34:08 UTC 2019
8: Fri May 17 00:34:09 UTC 2019
9: Fri May 17 00:34:10 UTC 2019
10: Fri May 17 00:34:11 UTC 2019
11: Fri May 17 00:34:12 UTC 2019
12: Fri May 17 00:34:13 UTC 2019

这样就完成了一个比较简单的日志信息的收集。

发表评论

电子邮件地址不会被公开。 必填项已用*标注