日志收集折腾过程

ELK

之前整合过ELK做日志采集,就是Elasticsearch + Logstash + Kibana:

  • Elasticsearch:存储引擎,存放日志内容,利于全文检索
  • Logstash:数据传输管道,将日志内容传输到Elasticsearch,并且支持过滤内容,将内容格式化后再传输,可以满足绝大部分的应用场景
  • Kibana:开源的分析和可视化平台,在这里查看Elasticsearch中的数据

对我来说ELK有点重,服务占用资源高,并且部署和维护有些复杂,我的个人服务器玩这个有点力不从心,所以一直有在寻找替代方案。

EFK

Elasticsearch + Filebeat + Kibana,用Filebeat替代Logstash做日志的收集,它是由Golang开发,够轻量,占用资源少,如果没有过滤日志内容进行格式化的需求,用这个替代Logstash是很不错的选择。

ELFK

四个框架全用,网上看到有大佬这样用,应该是企业级别的部署,看着我就敬而远之,不敢玩。

自己撸一个

我对EFK的服务占用感到不满,于是自己用Golang写了一个轻量级工具,没有做采集、过滤,仅仅是从日志文件夹中grep出想要的内容,其实和手动grep没区别,不过可以用接口的方式查出想要的内容,而且极其轻量,这个工具我还用过好一段时间。

我把EFK的搭建过程和手撸工具的过程写在了这里,感兴趣可以去看看。

Spring Boot日志收集以及链路追踪

Graylog

最近我在折腾另一个日志收集方案,并且感觉不错,就是Graylog,它需要整合Mongo + Elasticsearch,它比较简单易用,提供网页端可视化页面,相当于Kibana,还支持日志报警。

值得说明的是,它支持处理多行日志,而在ELK中,多行日志需要用Logstash做一些格式化配置,这一点来说Graylog就做的很棒。

至于为什么需要整合Mongo,是因为需要借助Mongo来保存一些Graylog的配置信息。

环境搭建

我喜欢用Docker来搭建环境,所以如果你通过其他方式,可以到官网寻求答案

首先拉取一下镜像:

docker pull elasticsearch:7.12.0
​
docker pull graylog/graylog:4.3.6
​
docker pull mongo:4.2
复制代码

docker-compose.yml:

version: '3'
services:mongo:image: mongo:4.2container_name: mongo # graylog内默认连接名为mongo,所以这个不建议改restart: alwaysvolumes:- /home/mycontainers/mongo/data:/data/db # 路径映射ports:- 27017:27017network_mode: mynetwork # 设置网段elasticsearch:image: elasticsearch:7.12.0container_name: elasticsearch # graylog内默认连接名为elasticsearch,所以不建议改environment:- "TAKE_FILE_OWNERSHIP=true" # 挂载目录需要这个,不然没有权限- "discovery.type=single-node"    # 设置为单节点,集群就等进阶再说了- "ES_JAVA_OPTS=-Xms512m -Xmx512m"    # 分配堆大小volumes:- /home/mycontainers/es/data:/usr/share/elasticsearch/data- /home/mycontainers/es/logs:/usr/share/elasticsearch/logsulimits: # 调整 ulimits 以及 nproceditmemlock:soft: -1hard: -1deploy:resources:limits:memory: 1g # 限制使用内存ports:- 9200:9200- 9300:9300network_mode: mynetworkgraylog:image: graylog/graylog:4.3.6container_name: graylogenvironment:# echo -n "Enter Password: " && head -1 < /dev/stdin | tr -d '\n' | sha256sum | cut -d " " -f1- GRAYLOG_PASSWORD_SECRET=somepasswordpepper  # 用于密码加密加盐- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 # 密码,默认是admin,可以用上面的echo命令生成自己的密码- GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9009/    # 对外开放的链接,注意端口,我改成了9009# volumes:# - /home/mycontainers/graylog/config/graylog.conf:/usr/share/graylog/data/config/graylog.confnetwork_mode: mynetworkrestart: alwaysdepends_on:- mongo # 依赖于mongo和es两个环境- elasticsearchports:- 9009:9000 # 端口映射# Syslog TCP- 1514:1514# Syslog UDP- 1514:1514/udp# GELF TCP- 12201:12201# GELF UDP- 12201:12201/udp
复制代码

执行运行命令:

docker-compose -f docker-compose.yml up
复制代码

但有时候,我们在之前就已经部署好了Mongo和ES环境,所以不会在一个docker-compose文件中配置三个环境,我们把内容拆开如下:

es.yml:

version: '3'
services:elasticsearch:image: elasticsearch:7.12.0container_name: elasticsearch # graylog内默认连接名为elasticsearch,所以不建议改environment:- "TAKE_FILE_OWNERSHIP=true"- "discovery.type=single-node"- "ES_JAVA_OPTS=-Xms512m -Xmx512m"volumes:- /etc/localtime:/etc/localtime- /home/mycontainers/es/data:/usr/share/elasticsearch/data- /home/mycontainers/es/logs:/usr/share/elasticsearch/logsulimits: # 调整 ulimits 以及 nproceditmemlock:soft: -1hard: -1deploy:resources:limits:memory: 1g # 限制使用内存ports:- 9200:9200- 9300:9300network_mode: mynetwork
复制代码

mongo.yml:

version: '3'
services:mongo:image: mongo:4.2container_name: mongo # graylog内默认连接名为mongo,所以这个不建议改restart: alwaysvolumes:- /etc/localtime:/etc/localtime- /home/mycontainers/mongo/data:/data/dbports:- 27017:27017network_mode: mynetwork
复制代码

graylog.yml:

version: '3'
services:graylog:image: graylog/graylog:4.3.6container_name: graylogenvironment:# echo -n "Enter Password: " && head -1 < /dev/stdin | tr -d '\n' | sha256sum | cut -d " " -f1- GRAYLOG_PASSWORD_SECRET=somepasswordpepper- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918- GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9009/- GARYLOG_ELASTICSEARCH_HOSTS=http://elasticsearch:9200 # 链接es,这里是容器间通讯,所以写容器名- GRAYLOG_MONGODB_URI=mongodb://mongo:27017/graylog # 同上volumes:- /home/mycontainers/graylog/config/graylog.conf:/usr/share/graylog/data/config/graylog.conf # 指定配置文件,用于修改时区network_mode: mynetworkrestart: alwaysports:- 9009:9000# Syslog TCP- 1514:1514# Syslog UDP- 1514:1514/udp# GELF TCP- 12201:12201# GELF UDP- 12201:12201/udp
复制代码

不同点在于手动配置mongo和es,还有多了一个配置文件映射,因为graylog默认UTC时区,我们的日志文件会相差8小时,所以在第一次启动成功graylog后,我们把它的配置文件拷贝出来,修改里面的root_timezone参数,再映射回去即可。

创建输入

现在我们可以访问Graylog了:http://xxx:9009

来创建一个输入:

勾选Global,Title随便写一个,其他不用改,保存即可,就能得到:

回到Search标签页,等日志文件输入即可。

Spring Boot整合Graylog

Maven依赖:

<!--graylog日志依赖-->
<dependency><groupId>de.siegmar</groupId><artifactId>logback-gelf</artifactId><version>3.0.0</version>
</dependency>
复制代码

然后是logback的配置,这个根据需要使用就好,在resource中:

logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--解决在项目目录中生成LOG_PATH_IS_UNDEFINED文件--><property name="LOG_PATH" value="${LOG_PATH:-${java.io.tmpdir:-/logs}}"/><!-- 引入SpringBoot的默认配置文件defaults.xml --><include resource="org/springframework/boot/logging/logback/defaults.xml"/><!-- 引入SpringBoot中内置的控制台输出配置文件console-appender.xml --><include resource="org/springframework/boot/logging/logback/console-appender.xml"/><!-- 引入自定义的文件输出配置文件logback-spring-file-level.xml --><include resource="logback-spring-file-level.xml"/>
​<!-- 设置root logger的级别为INFO,并将控制台输出和文件输出中的appender都添加到root logger下 --><root level="INFO"><!--没有这行,控制台将不会有输出,完全由日志进行输出--><appender-ref ref="CONSOLE"/><appender-ref ref="INFO_FILE"/><appender-ref ref="WARN_FILE"/><appender-ref ref="ERROR_FILE"/><appender-ref ref="GELF"/></root>
​<!-- jmx可以动态管理logback配置--><jmxConfigurator/>
</configuration>
复制代码

logback-spring-file-level.xml:

<?xml version="1.0" encoding="UTF-8"?>
<included><!-- 从配置文件中读取--><springProperty scope="context" name="APP_NAME" source="graylog.appName"/><springProperty scope="context" name="GRAYLOG_HOST" source="graylog.host"/><springProperty scope="context" name="GRAYLOG_PORT" source="graylog.port"/>
​<!--INFO Level的日志--><appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- %i用来标记分割日志的序号 --><fileNamePattern>${LOG_PATH}.INFO.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- 单个日志文件最大maxFileSizeMB, 保存maxHistory天的历史日志, 所有日志文件最大totalSizeCapMB --><!-- 经过试验,maxHistory是指指定天数内,而不是多少天--><maxFileSize>50MB</maxFileSize><maxHistory>15</maxHistory><totalSizeCap>50MB</totalSizeCap></rollingPolicy><!-- 配置日志的级别过滤器,只保留INFO Level的日志--><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><!-- 格式化输出--><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level -[%X{traceId}] - %msg%n</pattern></encoder></appender>
​<!--WARN Level的日志--><appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- %i用来标记分割日志的序号 --><fileNamePattern>${LOG_PATH}.WARN.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- 单个日志文件最大maxFileSizeMB, 保存maxHistory天的历史日志, 所有日志文件最大totalSizeCapMB --><maxFileSize>50MB</maxFileSize><maxHistory>15</maxHistory><totalSizeCap>50MB</totalSizeCap></rollingPolicy><filter class="ch.qos.logback.classic.filter.LevelFilter"><!--过滤级别--><level>WARN</level><!--onMatch:符合过滤级别的日志。ACCEPT:立即处理--><onMatch>ACCEPT</onMatch><!--onMismatch:不符合过滤级别的日志。DENY:立即抛弃--><onMismatch>DENY</onMismatch></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level -[%X{traceId}] - %msg%n</pattern></encoder></appender>
​<!--ERROR Level的日志--><appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- %i用来标记分割日志的序号 --><fileNamePattern>${LOG_PATH}.ERROR.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- 单个日志文件最大maxFileSizeMB, 保存maxHistory天的历史日志, 所有日志文件最大totalSizeCapMB --><maxFileSize>50MB</maxFileSize><maxHistory>15</maxHistory><totalSizeCap>50MB</totalSizeCap><!--<cleanHistoryOnStart>true</cleanHistoryOnStart>--></rollingPolicy><!--对指定级别的日志进行过滤--><filter class="ch.qos.logback.classic.filter.LevelFilter"><!--过滤级别--><level>ERROR</level><!--onMatch:符合过滤级别的日志。ACCEPT:立即处理--><onMatch>ACCEPT</onMatch><!--onMismatch:不符合过滤级别的日志。DENY:立即抛弃--><onMismatch>DENY</onMismatch></filter><!--日志输出格式--><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"} %-5level - [%X{traceId}] - %msg%n</pattern></encoder></appender>
​<!--自定义日志--><appender name="CUSTOM_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- %i用来标记分割日志的序号 --><fileNamePattern>${LOG_PATH}.MYLOGGER.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!-- 单个日志文件最大maxFileSizeMB, 保存maxHistory天的历史日志, 所有日志文件最大totalSizeCapMB --><!-- 经过试验,maxHistory是指指定天数内,而不是多少天--><maxFileSize>300MB</maxFileSize><maxHistory>15</maxHistory><totalSizeCap>300MB</totalSizeCap></rollingPolicy><!-- 配置日志的级别过滤器,只保留INFO Level的日志--><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><!-- 格式化输出--><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{"yyyy-MM-dd HH:mm:ss.SSS"}\t%X{traceId}\t%msg%n</pattern></encoder></appender><!--自定义日志日志不用绑定在root下,只记录指定输出--><logger name="my_logger" additivity="false"><appender-ref ref= "CUSTOM_FILE"/></logger>
​<appender name="GELF" class="de.siegmar.logbackgelf.GelfUdpAppender"><!--graylog服务地址--><graylogHost>${GRAYLOG_HOST}</graylogHost><!--连接端口--><graylogPort>${GRAYLOG_PORT}</graylogPort>
​<encoder class="de.siegmar.logbackgelf.GelfEncoder"><originHost>${APP_NAME:-demo}</originHost><!--发送日志级别名称,默认以数字代表日志级别--><includeLevelName>true</includeLevelName></encoder></appender>
</included>
复制代码

我们在logback中引用了配置文件的系统变量,所以在application.yml中要添加这一段,当然硬写进xml也可以:

application.yml

logging:file:path: _mylogs/${server.port}.logs # 日志保存路径graylog:host: mylocalhost # graylog服务hostport: 12201   # graylog服务端口appName: graylogDemo  # 应用名,可填
复制代码

启动Spring应用,打印几条日志:

@RestController
public class TestController {private static final Logger log = LoggerFactory.getLogger(TestController.class);
​@GetMapping("/i")public void info() {log.info("info...................");}
​@GetMapping("/w")public void warn() {log.warn("warn...................");}
​@GetMapping("/e")public void error() {
//        log.error("error...................");int i = 1/0;
//        LogUtil.error("自定义异常");}
}
复制代码

稍等片刻,顺利的话我们就能在Graylog中查看到刚刚输出的日志了,至此大功告成。

总结

本篇文章只是说明了Graylog的一个入门使用,进阶的玩法可能要后面才有时间整理了。

不管用什么方案做日志收集,我认为只要简单易用,稳定靠谱就好,ELK作为当前主流的日志收集框架,除了部署麻烦些,耗费资源高些之外并没有明显短板,所以ELK也好,Graylog也罢,只要适合自己就可以。

SpringBoot整合Graylog做日志收集相关推荐

  1. SpringBoot入门建站全系列(二十八)整合Kafka做日志监控

    SpringBoot入门建站全系列(二十八)整合Kafka做日志监控 一.概述 Apache Kafka是一个分布式发布 - 订阅消息系统和一个强大的队列,可以处理大量的数据,并使您能够将消息从一个端 ...

  2. kafka maven 依赖_SpringBoot入门建站全系列(二十八)整合Kafka做日志监控

    SpringBoot入门建站全系列(二十八)整合Kafka做日志监控 一.概述 Apache Kafka是一个分布式发布 - 订阅消息系统和一个强大的队列,可以处理大量的数据,并使您能够将消息从一个端 ...

  3. springboot整合redis做缓存

    之前的项目中,用到过redis,主要是使用redis做缓存,redis在web开发中使用的场景很多,其中缓存是其中一个很重要的使用场景,之所以用作缓存,得益于redis的读写数据,尤其是在读取数据的时 ...

  4. #yyds干货盘点# 如何在 Kubernete 中做日志收集与管理(14)

    说到日志,你应该不陌生.日志中不仅记录了代码运行的实时轨迹,往往还包含着一些关键的数据.错误信息,等等.日志方便我们进行分析统计及监控告警,尤其是在后期问题排查的时候,我们通过日志可以很方便地定位问题 ...

  5. kafka 可视化工具_两小时带你轻松实战SpringBoot+kafka+ELK分布式日志收集

    一.背景 随着业务复杂度的提升以及微服务的兴起,传统单一项目会被按照业务规则进行垂直拆分,另外为了防止单点故障我们也会将重要的服务模块进行集群部署,通过负载均衡进行服务的调用.那么随着节点的增多,各个 ...

  6. SpringBoot继承LogStash实现日志收集

    一.环境准备 安装Elasticsearch.kibana.logstash,教程链接 安装教程 二.配置SpringBoot 依赖 在springBoot 项目下pom文件增加logStash 依赖 ...

  7. 项目实战|史上最简单的springboot 整合elk教程,实现日志收集(带视频哦)

    配套视频教程已经上传 整合ELK-实现日志收集(知乎) 整合ELK-实现日志收集(CSDN) 项目源码已上传至 https://gitee.com/yangleliu/learning.git,免费索 ...

  8. 你居然还去服务器上捞日志,搭个日志收集系统难道不香么!

    摘要 ELK日志收集系统进阶使用,本文主要讲解如何打造一个线上环境真实可用的日志收集系统.有了它,你就可以和去服务器上捞日志说再见了! ELK环境安装 ELK是指Elasticsearch.Kiban ...

  9. java 如何去掉http debug日志_你居然还去服务器上捞日志,搭个日志收集系统难道不香吗?...

    作者:MacroZheng 链接:https://juejin.im/post/5eef217d51882565d74fb4eb 来源:掘金 SpringBoot实战电商项目mall(35k+star ...

最新文章

  1. 用netstat查看网络状态详解
  2. linux命令行tcp连接,linux下2个检查tcp连接的命令
  3. 在centos7中如何搭建局域网yum源仓库
  4. python绘制3d图-python中Matplotlib实现绘制3D图的示例代码
  5. Unix高级编程之文件权限
  6. 低级程序员和高级程序员的区别在哪?学会像高级程序员一样思考!
  7. MySQL的安装及使用教程
  8. git Please move or remove them before you can merge. 错误解决方案
  9. 矩阵经典题目六:poj 3070 Fibonacci
  10. python百题百练 二级题目_计算机二级选择题(公共基础新大纲)
  11. 还原真实的 cache recovery
  12. Daily Scrum 12.13
  13. Pisa-Proxy SQL 解析之 Lex Yacc
  14. css div居中对齐
  15. 教你轻松快速学会用Calibre TXT转MOBI
  16. linux虚拟内存设置为多少合适,虚拟内存怎么设置最好_虚拟内存设置多少合适
  17. Mongodb模式设计
  18. 数字内容产业的产业链结构
  19. 缺陷报告.定义,报告,核心要素
  20. python等于号怎么输入_python 中不等于怎么表示

热门文章

  1. 数据源SqlDataSource,DetailView,ObjectDataSource控件的配置使用
  2. apache 开启php fpm,apache php fpm安装方法详解
  3. Qt::Q_DECLARE_METATYPE
  4. 提升网站流量和排名的方法,SEO优化要这样做
  5. busybox的实现原理分析(C语言实现简易版的busybox)
  6. 分享一个简单的抢购华为商城手机的js脚本,仅供学习交流
  7. Bladed 时序风况配置方法
  8. vs2012 visual studio 2012安装失败管道正在关闭解决方法
  9. cat3速度 rj45_技术词语:4G网CAT.4和CAT.3那个快?
  10. 什么是HTTPDNS?HTTPDNS有哪些作用?