日志排查不用慌!从采集到 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"

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

相关推荐
石小石Orz19 分钟前
效率提升一倍!谈谈我的高效开发工具链
前端·后端·trae
孟永峰_Java1 小时前
凌晨线上崩盘:NoClassDefFoundError血案纪实!日志里这行「小字」才是救世主
后端·代码规范
whitepure1 小时前
万字详解Java中的IO及序列化
java·后端
掘金安东尼2 小时前
字节前端三面复盘:基础不花哨,代码要扎实(含高频题解)
前端·面试·github
大得3692 小时前
django生成迁移文件,执行生成到数据库
后端·python·django
寻月隐君2 小时前
Rust Web 开发实战:使用 SQLx 连接 PostgreSQL 数据库
后端·rust·github
RainbowSea2 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 06
java·spring boot·后端
Keya2 小时前
MacOS端口被占用的解决方法
前端·后端·设计模式
用户9096783069432 小时前
Python 判断一个字符串中是否含有数字
后端
jakeswang2 小时前
应用缓存不止是Redis!——亿级流量系统架构设计系列
redis·分布式·后端·缓存