Ubuntu26.04下Loki与Spring Boot集成实战指南
本文基于实际踩坑经历,详细记录在Ubuntu系统上部署Loki+Grafana,并通过Spring Boot应用将日志直接推送至Loki的全过程。文中包含完整的配置示例、常见错误及解决方案,以及如何在Grafana中利用上下文功能快速定位问题。
1. 为什么选择Loki?
相比传统的ELK(Elasticsearch+Logstash+Kibana)栈,Loki采用标签索引而非全文索引,存储成本更低,查询速度更快,尤其适合Kubernetes环境和微服务架构。配合Grafana的可视化能力,可以轻松实现日志的聚合、检索和监控。
本文方案特点:
使用Loki4j作为Logback Appender,Spring Boot应用直接推送日志,无需额外部署Promtail。
所有组件(Loki、Grafana)通过Docker Compose一键启动。
覆盖从部署到排错的全流程,尤其针对权限、配置文件等常见坑点给出明确解决办法。
2. 环境准备
操作系统:Ubuntu 26.04(其他版本同理)
Docker及Docker Compose(已安装)
Spring Boot项目(推荐3.x, 2/3/4均可)
JDK 8+
检查Docker版本:
docker --version docker compose version
若未安装,可参考官方文档安装Docker Engine和Compose。
3. 部署Loki和Grafana
3.1 创建项目目录
mkdir -p ~/loki-stack cd ~/loki-stack
3.2 编写docker-compose.yml
经过多次调整,最终使用不含配置文件挂载的简洁版本,避免因配置文件缺失或权限问题导致容器无法启动。关键点:数据目录权限必须正确。
创建docker-compose.yml:
nano
docker-compose.yml(ctrl+o save, press enter comfirm , ctrl+x exit)
networks: loki-network: services: loki: image: grafana/loki:latest container_name: loki ports: - "3100:3100" volumes: - ./loki/data:/loki # 数据持久化目录 networks: - loki-network # 不指定command,使用镜像默认配置 grafana: image: grafana/grafana:latest container_name: grafana ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin - GF_AUTH_ANONYMOUS_ENABLED=false volumes: - ./grafana/data:/var/lib/grafana networks: - loki-network depends_on: - loki注意:此处去掉了
version字段(避免警告),并未挂载loki/conf,让Loki使用内置默认配置。数据目录./loki/data和./grafana/data需提前创建并赋予正确权限。
3.3 准备数据目录并解决权限问题
Loki和Grafana容器内均以非root用户运行(Loki用户uid约为10001,Grafana用户uid为472),需要宿主机目录具有写权限。
快速解决(测试环境):
# 创建目录 mkdir -p ./loki/data ./grafana/data # 赋予所有用户读写执行权限(777) chmod 777 ./loki/data ./grafana/data
更安全的做法(生产推荐):
# 为Loki目录设置uid 10001(可通过docker run --rm grafana/loki id -u确认) sudo chown -R 10001:10001 ./loki/data # 为Grafana目录设置uid 472 sudo chown -R 472:472 ./grafana/data
3.4 启动服务
docker compose up -d
检查容器状态:
docker ps
验证Loki是否就绪:
curl http://localhost:3100/ready
返回ready表示成功。也可查看日志:
docker logs loki docker logs grafana
若遇到权限错误(如mkdir /loki/rules: permission denied或GF_PATHS_DATA is not writable),请按上述权限调整步骤重新执行。
4. Spring Boot集成Loki4j
4.1 添加Maven依赖
在pom.xml中加入:
<dependency> <groupId>com.github.loki4j</groupId> <artifactId>loki-logback-appender</artifactId> <version>1.4.1</version> </dependency><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.5.0</version> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>springboot-loki</artifactId> <version>1.0.0</version> <name>Spring Boot Loki Integration</name> <description>Spring Boot 3.5 project with Loki4j integration</description> <properties> <java.version>17</java.version> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- Spring Boot Web Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Loki4j Logback Appender --> <dependency> <groupId>com.github.loki4j</groupId> <artifactId>loki-logback-appender</artifactId> <version>2.0.3</version> <scope>compile</scope> </dependency> <!-- Lombok (可选,简化代码) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
4.2 配置Logback
在src/main/resources下创建或修改logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 控制台输出配置 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <!-- Loki4j Appender 配置 --> <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender"> <http> <url>http://localhost:3100/loki/api/v1/push</url> <connectionTimeoutMs>5000</connectionTimeoutMs> <requestTimeoutMs>10000</requestTimeoutMs> </http> <format> <label> <pattern>app=springboot-loki,env=local</pattern> <readMarkers>true</readMarkers> </label> <message> <pattern>${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n}</pattern> </message> <sortByTime>true</sortByTime> </format> <batch> <maxItems>1000</maxItems> <maxWaitMs>5000</maxWaitMs> <maxBytes>10485760</maxBytes> </batch> <send> <minLevel>INFO</minLevel> <retry> <maxRetries>3</maxRetries> <backoffMs>1000</backoffMs> </retry> </send> </appender> <!-- 异步Loki Appender --> <appender name="ASYNC_LOKI" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="LOKI"/> <queueSize>512</queueSize> <discardingThreshold>0</discardingThreshold> <neverBlock>true</neverBlock> </appender> <!-- 根日志配置 --> <root level="INFO"> <appender-ref ref="CONSOLE"/> <appender-ref ref="ASYNC_LOKI"/> </root> <!-- 应用特定日志配置 --> <logger name="com.example.springbootloki" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE"/> <appender-ref ref="ASYNC_LOKI"/> </logger> </configuration>配置要点:
<url>指向Loki的推送端点,若Loki不在本机,替换为实际IP。标签(
application和level)是查询的核心,建议包含应用名、环境等。消息体可包含自定义字段,便于后续解析。
在application.properties中定义应用名:
spring: application: name: springboot-loki
4.3 编写测试接口
创建测试Controller,验证日志推送:
package com.example.springbootloki.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController @RequestMapping("/api/logs") public class LogTestController { //https://zhengkai.blog.csdn.net/ private static final Logger logger = LoggerFactory.getLogger(LogTestController.class); /** * 基本日志测试接口 */ @GetMapping("/test") public Map<String, String> testLogs() { logger.info("这是一条INFO级别日志 - 测试Loki集成"); logger.debug("这是一条DEBUG级别日志 - 调试信息"); logger.warn("这是一条WARN级别日志 - 警告信息"); logger.error("这是一条ERROR级别日志 - 错误信息"); return Map.of( "status", "success", "message", "日志已写入Loki", "timestamp", String.valueOf(System.currentTimeMillis()) ); } }启动Spring Boot应用,访问/test,日志便会推送至Loki。
http://localhost:8080/api/logs/test
5. 在Grafana中配置Loki数据源
浏览器访问
http://<你的Ubuntu IP>:3000,登录(admin/admin)。点击左侧齿轮图标(Configuration)→Data Sources→Add data source。
选择Loki。
URL 填写
http://loki:3100(因为Grafana与Loki在同一Docker网络,可使用服务名)。点击Save & Test,显示成功即可。
6. 查询日志与查看上下文
6.1 基本查询
进入Explore页面,选择Loki数据源。使用标签过滤器,例如:
{app="default"}查看该应用所有日志。加上
level="WARN"过滤警告级别。使用
|= "警告信息"进行文本搜索。
6.2 查看某条日志的上下文(关键功能)
当你在日志列表中发现一条感兴趣的日志(如WARN),想查看它之前和之后的日志以了解触发背景时,可以使用Grafana的上下文功能:
鼠标悬停在目标日志行上,右侧会出现操作图标。
点击“显示上下文”按钮(两条横线带箭头,英文版是Content)。
默认会展示该条日志前后各10行日志,你可以调整行数(例如20行),点击加载。
这样就能快速分析出WARN发生前的DEBUG或INFO日志,从而定位问题根源。
原理:上下文查询基于相同标签流和时间顺序,因此务必确保标签组合能唯一标识一个日志流(例如包含
application、host、container等)。
7. 常见问题与排错
7.1 Loki容器启动失败,日志显示config file not found
原因:未正确挂载配置文件或镜像默认路径不存在。
解决:移除
volumes中挂载配置目录的行,让容器使用内置默认配置。
7.2 权限错误permission denied
原因:宿主机数据目录权限不足。
解决:
chmod 777或chown为容器内用户uid(Loki uid≈10001,Grafana uid=472)。
7.3 Spring Boot日志未出现在Loki
检查Loki URL是否正确,确保网络可达。
查看Spring Boot日志中是否有连接异常。
检查Loki容器是否正常运行(
docker logs loki)。
7.4 Grafana无法连接Loki数据源
确保Grafana和Loki在同一网络,URL使用服务名
http://loki:3100。检查Loki端口是否暴露,可用
curl http://localhost:3100/ready测试。
8. 总结
通过本文的实战步骤,你已成功在Ubuntu上部署Loki+Grafana,并让Spring Boot应用通过Loki4j直接将结构化日志推送至Loki。整个过程解决了配置文件缺失、权限不足等典型问题,并掌握了利用Grafana上下文功能快速回溯日志的技巧。
这套轻量级日志方案适合开发和测试环境,也可平滑迁移至生产(配合Promtail收集文件日志、使用对象存储等)。希望本文能帮助你高效构建日志系统,提升问题排查效率。
附录:清理所有容器和数据
cd ~/loki-stack docker compose down #只是shutdown docker compose down -v # -v 会删除数据卷,谨慎使用
扩展阅读:
Loki官方文档
Loki4j GitHub
# ----------------------------------------------------- # - 🚀 Powered by Moshow郑锴 # - 🌟 Might the holy code be with you! # ----------------------------------------------------- # 🔍 公众号 👉 软件开发大百科 # 💻 CSDN 👉 https://zhengkai.blog.csdn.net # 📂 Github 👉 https://github.com/moshowgame
本文基于Ubuntu 26.04实践,其他Linux发行版类似。如有问题,欢迎留言交流。
