日志排查不用慌!从采集到 ELK 实战,手把手教你搞定线上问题

查看日志信息对于运维开发人员来说是非常必要的,常见的查看日志情况如下:

  • 当应用程序或服务出现故障时,查看日志可帮助快速定位问题,了解故障前后的系统状态。
  • 通过分析日志,可以监控应用程序性能,识别性能瓶颈或资源消耗异常。
  • 在开发和测试过程中,查看日志有助于开发人员调试代码、定位并修复bug,同时也是验证应用程序功能是否正常的重要依据。

线上项目问题的排查思路和解决办法

线上项目一旦出问题,那可是牵一发而动全身 ------ 用户投诉、业务中断、数据风险,分分钟让人头大。但老手都知道,再棘手的问题也不是无迹可寻,而日志就是咱们最靠谱的 "破案线索库"。从服务器突然卡顿到接口频繁报错,从数据异常到用户操作失败,顺着日志这条线摸下去,总能找到问题的源头。接下来,咱们就结合前面讲的日志管理技巧,聊聊线上问题排查的实用思路:怎么快速定位日志中的关键信息?不同场景下该用哪些工具和命令?遇到复杂问题时又该如何串联日志碎片还原真相?掌握了这些,面对线上故障就能从手忙脚乱变成胸有成竹。

日志采集方式

咱们项目里用的是 SpringBoot 自带的 logback 框架来收集日志,步骤超简单,跟着做就行:

  1. 加依赖?不用!

SpringBoot 早就把 logback 的依赖打好包了,咱们直接用就行,省事儿~

  1. 准备 logback 配置文件

得在项目里放个 logback.xml 文件,这里面可讲究了 ------ 日志存哪儿、长啥样、哪些级别要记录,全在这儿定规矩。给你们看个例子,我标了重点注释,一看就懂:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>  
<configuration>  
    <!-- 日志文件放这儿 -->  
    <property name="log.path" value="/home/ruoyi/logs" />  
    <!-- 日志格式:时间 线程 级别 哪个类 哪行代码 具体内容 -->  
    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />  
    <!-- 控制台也得显示日志吧?就靠这个配置 -->  
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">  
        <encoder>  
            <pattern>${log.pattern}</pattern>  
        </encoder>  
    </appender>  
    <!-- 系统正常运行的日志存在这儿 -->  
    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <file>${log.path}/sys-info.log</file>  
        <!-- 每天生成一个新日志文件,老的自动归档 -->  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>  
            <!-- 只保留60天的日志,不然硬盘要炸 -->  
            <maxHistory>60</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>${log.pattern}</pattern>  
        </encoder>  
        <!-- 只记DEBUG及以上级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>DEBUG</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
    </appender>  
    <!-- 专门存错误日志的地方 -->  
    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <file>${log.path}/sys-error.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>  
            <maxHistory>60</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>${log.pattern}</pattern>  
        </encoder>  
        <!-- 只抓ERROR级别的日志,方便排查问题 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>ERROR</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
    </appender>  
    <!-- 用户登录登出这些操作日志单独存 -->  
    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <file>${log.path}/sys-user.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>  
            <maxHistory>60</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>${log.pattern}</pattern>  
        </encoder>  
    </appender>  
    <!-- 咱们自己写的代码,日志级别设为INFO就行 -->  
    <logger name="com.ruoyi" level="info" />  
    <!-- Spring框架的日志别太啰嗦,WARN及以上就行 -->  
    <logger name="org.springframework" level="warn" />  
    <!-- 根日志配置:默认输出到控制台 -->  
    <root level="info">  
        <appender-ref ref="console" />  
    </root>  
    <!-- 系统日志同时输出到文件和控制台 -->  
    <root level="info">  
        <appender-ref ref="file_info" />  
        <appender-ref ref="file_error" />  
    </root>  
    <!-- 用户操作日志专门写到sys-user.log -->  
    <logger name="sys-user" level="info">  
        <appender-ref ref="sys-user"/>  
    </logger>  
</configuration>

具体的生成的日志文件列表如下:

  • 目前有三类文件,分别是sys-error.log、sys-info.log、sys-user.log文件

    文件中不带日期记录的是当天的日志

  • sys-info.log记录的是系统日志,包含了运行日志和错误日志(较全)

  • sys-error.log记录的是错误日志,排查错误一般看这个文件

  • sys-user.log记录的是用户登录相关的日志数据

  1. 在代码里打日志

在类上添个@Slf4j注解,就不用自己写日志对象了,直接用这些方法打日志:

  • 调试的时候用log.debug("用户输入了xxx")
  • 需要注意的情况用log.warn("库存快不够了,当前只剩xxx")
  • 出问题了用log.error("数据库连接失败!", e)(记得把异常传进去)

现在咱们的日志文件主要有三种:

  • sys-info.log:系统大杂烩,啥日志都有,最全面
  • sys-error.log:只记错误,排查问题首选这个
  • sys-user.log:专门记用户登录、退出这些操作

不带日期的是当天的日志,带日期的是以前的归档文件,很好区分~

Linux 里查看日志

查日志是咱们的基本功,线上服务大多用 docker 部署,我教你们几招实用的:

docker logs 命令

用这个命令查容器里的日志超方便,格式是docker logs [参数] 容器名或ID:

  • 想实时看着日志更新?加个-f参数:docker logs -f 容器名,就像看直播一样
  • 只看最后 100 行?docker logs --tail=100 容器名,避免日志太多刷屏

进容器里查日志

如果想细看日志文件,先用docker exec -it 容器名 /bin/bash进容器(如果提示找不到 bash,就换/bin/sh),然后用这些 Linux 命令:

  • 看整个日志文件:cat sys-info.log(文件大的话慎用,会卡死);想慢慢翻就用more sys-info.log或less sys-info.log
  • 实时盯日志:tail -f sys-info.log,新日志会自动出来;只想看最后 100 行的更新?tail -n 100 -f sys-info.log(这个超常用)
  • 按关键词搜日志:比如找所有带 error 的记录,cat sys-info.log | grep 'error';日志太多翻不完?加个| more分页看:cat sys-info.log | grep 'error' | more

ELK 日志管理

小项目用上面的方法够了,但公司大了、服务多了,日志堆成山,光靠命令行就不够用了。这时候就得请出 ELK 这个神器组合了!

啥是 ELK?

ELK是一个开源的日志管理平台,由三个核心组件组成:E lasticsearch、L ogstash 和 Kibana。这三个组件共同协作,提供了对日志从收集、处理、存储到分析、可视化的完整解决方案。

  1. Elasticsearch:这是一个基于Lucene的搜索引擎,用于存储和搜索日志数据。它提供了强大的全文搜索功能,支持复杂的查询和聚合操作,并且能够处理大规模的日志数据。
  2. Logstash:这是一个日志收集和处理工具,用于从各种数据源(如文件、数据库、网络等)中收集日志,并将其转换为Elasticsearch可以理解的格式。Logstash还提供了丰富的过滤功能,可以对日志数据进行清洗、转换和增强。
  3. Kibana:这是一个Web界面,用于可视化Elasticsearch中的日志数据。它提供了直观的图形和工具,使用户能够轻松地搜索、分析和可视化日志数据,从而更好地理解系统的运行状态和性能。

动手搭 ELK

装好了这三个工具,直接启动就行:

启动服务

先运行这三条命令启动服务(注意:这仨很吃内存,用完记得关掉):

sql 复制代码
docker start es
docker start kibana
docker start logstash

不过启动后虚拟机可能会有点卡,咱们调整一下:

  1. 先把虚拟机里的前后端服务停了:
arduino 复制代码
docker stop zzyl-admin
docker stop zzyl-vue
  1. 改在自己电脑上启动服务:
  • 后端:在 application.yml 里把spring.profiles.active改成prod,然后启动

让项目日志发给 ELK

得让咱们的项目把日志传给 Logstash,步骤如下:

  1. 先在 zzyl-admin 模块里加个依赖:
xml 复制代码
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>6.6</version>
</dependency>
  1. 新增个logback-logstash.xml文件(其实就是在原来的配置上加了 Logstash 的配置):
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="log.path" value="/home/ruoyi/logs" />
    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>
    <!-- 重点:这个配置让日志发给Logstash -->
    <appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <!-- 填Logstash的地址和端口,咱们虚拟机里是192.168.100.168:5044 -->
        <destination>192.168.100.168:5044</destination>
        <!-- 日志格式转成JSON,方便Elasticsearch处理 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                        "app": "ruoyi-admin",  // 标记是哪个应用的日志
                        "timestamp": "%d{yyyy-MM-dd HH:mm:ss.SSS}",  // 日志时间
                        "thread": "%thread",  // 哪个线程打的日志
                        "level": "%level",  // 日志级别
                        "logger_name": "%logger",  // 哪个类打的日志
                        "message": "%msg",  // 日志内容
                        "stack_trace": "%exception"  // 异常堆栈
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    <!-- 下面这些和之前的logback.xml一样,省略... -->
    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 内容不变 -->
    </appender>
    
    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 内容不变 -->
    </appender>
    
    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 内容不变 -->
    </appender>
    
    <logger name="com.ruoyi" level="info" />
    <logger name="org.springframework" level="warn" />
    <root level="info">
        <appender-ref ref="console" />
    </root>
    
    <!-- 关键:让日志同时发给Logstash和文件 -->
    <root level="info">
        <appender-ref ref="logstash" />
        <appender-ref ref="file_info" />
        <appender-ref ref="file_error" />
    </root>
    
    <logger name="sys-user" level="info">
        <appender-ref ref="sys-user"/>
    </logger>
</configuration> 
  1. 让正式环境用这个新配置:改application-prod.yml,指定日志配置文件:
yaml 复制代码
logging:
  config: classpath:logback-logstash.xml
  level:
    com.zzyl: debug
    org.springframework: warn

改完重启服务,随便点点页面,多制造点日志(比如故意点些没完成的功能,弄点错误日志出来)。

用 Kibana 查日志

打开 Kibana 的地址:http://192.168.100.168:5601/,第一次用得先设置索引。

加个索引模式

  1. 点左边菜单的Stack Management
  1. 找到索引模式,点创建索引模式
  1. 输入索引名(比如logstash-*,匹配所有日志索引)
  1. 选个时间字段(一般用@timestamp)
  1. 点创建索引模式就搞定了

管理索引

在Stack Management里点索引管理,能看到所有日志索引,都是按日期存的,每天一个,清清楚楚。

搜日志

点左边的Discover,就能搜日志了:

  • 选刚才创建的索引模式
  • 直接在搜索框输关键词,比如error
  • 想按条件搜?比如只看 ERROR 级别的:level:"ERROR"
  • 想限定时间?用@timestamp,比如@timestamp:"2025-08-05"只看 8 月 5 号的日志

高级搜法

给你们几个超实用的技巧:

  • 模糊搜:比如想找所有带nursing开头的日志,用nursing*;找user1或user2,用user?(? 匹配一个字符)
  • 时间范围:@timestamp < "2025-08-05"(8 月 5 号之前),@timestamp > "2025-08-05T08:00:00"(8 月 5 号早上 8 点之后)
  • 多条件组合:比如找今天的 ERROR 日志,level:"ERROR" AND @timestamp:"2025-08-05"

有了这些技巧,再多日志也能轻松搞定啦!

相关推荐
_UMR_12 小时前
springboot集成Jasypt实现配置文件启动时自动解密-ENC
java·spring boot·后端
程序员小假13 小时前
我们来说说 Cookie、Session、Token、JWT
java·后端
短剑重铸之日13 小时前
《SpringBoot4.0初识》第一篇:前瞻与思想
java·开发语言·后端·spring·springboot4.0
it_czz13 小时前
LangSmith vs LangFlow vs LangGraph Studio 可视化配置方案对比
后端
蓝色王者13 小时前
springboot 2.6.13 整合flowable6.8.1
java·spring boot·后端
花哥码天下14 小时前
apifox登录后设置token到环境变量
java·后端
程序员小寒14 小时前
从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序
开发语言·前端·javascript·面试
hashiqimiya15 小时前
springboot事务触发滚动与不滚蛋
java·spring boot·后端
TeamDev15 小时前
基于 Angular UI 的 C# 桌面应用
前端·后端·angular.js