欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 使用 Loki、Loki4j、Grafana 和 Spring Boot 搭建一个轻量级、简单、易用的 Java 日志系统

使用 Loki、Loki4j、Grafana 和 Spring Boot 搭建一个轻量级、简单、易用的 Java 日志系统

2024/10/25 14:30:26 来源:https://blog.csdn.net/a13407142317/article/details/142465125  浏览:    关键词:使用 Loki、Loki4j、Grafana 和 Spring Boot 搭建一个轻量级、简单、易用的 Java 日志系统

要使用 LokiLoki4jGrafanaSpring Boot 搭建一个轻量级、简单、易用的 Java 日志系统,您可以按以下步骤进行。这个系统将利用 Loki 作为日志存储和聚合系统,Loki4j 作为 Java 的日志插件,Grafana 用于日志的可视化。

1.工具介绍:

  1. Loki:类似于 Prometheus 的日志系统,但 Loki 并不索引日志的内容,而是通过标签(label)进行索引,使用 PromQL 进行查询,轻量级且高效。
  2. Loki4j:一个适用于 Java 项目的日志库,可以将 Spring Boot 项目的日志直接推送到 Loki。
  3. Grafana:用于可视化 Loki 中存储的日志,并提供查询、分析和展示日志的功能。
  4. Spring Boot:作为 Java 应用框架,用于生成日志并集成 Loki4j 进行日志传输。

2.系统架构:

  • Spring Boot 应用程序通过 Loki4j 生成和发送日志。
  • Loki 作为日志聚合和存储系统接收日志。
  • Grafana 用于展示和可视化 Loki 中存储的日志。

3. 使用步骤

3.1.步骤 1:搭建 Loki 和 Grafana

可以通过 Docker 容器运行 Loki 和 Grafana,以便简化配置。

3.1.1.准备Loki和Grafanan的镜像

配置docker-compose.yml信息

version: '3.0'
services:loki:image: loki:latestcontainer_name: base_software_lokiports:- "3100:3100"networks:- monitoringgrafana:image: grafana:latestcontainer_name: base_software_grafanaports:- "3200:3000"networks:- monitoringdepends_on:- loki
volumes:es_data:driver: localnetworks:monitoring:driver: bridge

3.1.2 创建两个容器

docker-compose up -d

启动后,可以通过浏览器访问 http://localhost:3000,默认的用户名和密码均为 admin

3.1.3 配置 Grafana 数据源

  1. 登录 Grafana。
  2. 添加 Loki 作为数据源:
    • 进入 Configuration > Data Sources
    • 点击 Add data source,选择 Loki
    • 在 URL 中填写 http://127.0.0.1:3100
    • 保存并测试连接。

在这里插入图片描述

3.2.步骤 2:配置 Spring Boot 项目

在 Spring Boot 项目中使用 Loki4j 来将日志发送到 Loki。

3.2.1 添加依赖

在 Spring Boot 的 pom.xml 文件中添加 Loki4j 依赖:

<dependency>  <groupId>com.github.loki4j</groupId>  <artifactId>loki-logback-appender-jdk8</artifactId>  <version>1.4.2</version>  
</dependency>

3.2.2 配置 logback-spring.xml

Loki4j 使用 Logback 作为日志框架。你需要配置 src/main/resources/logback-spring.xml 文件来使用 Loki4j 将日志发送到 Loki:

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- 彩色控制台控制 --><substitutionProperty name="log.pattern" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) ${PID:-} %clr(---){faint} %clr(%-80.80logger{79}){cyan} %clr(:){faint} %m%n%wEx"/><substitutionProperty name="log.pattern.no" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) ${PID:-} %clr(---){faint} %clr(%-80.80logger{79}){cyan} %clr(:){faint} %m%n%wEx"/><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/><springProperty scope="context" name="LOG_FILE_DIR" source="loki.log-file-dir" defaultValue="log"/><!-- 控制台输出 --><appender name="Console" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${log.pattern}</pattern></encoder></appender><springProperty name="lokiEnabled" source="loki.enabled" defaultValue="false"/><springProperty scope="context" name="url" source="loki.url" defaultValue="http://localhost:3100/loki/api/v1/push"/><springProperty scope="context" name="env" source="loki.label.env" defaultValue="dev"/><springProperty scope="context" name="jobName" source="loki.label.job-name" defaultValue="xiaocai"/><springProperty scope="context" name="hostIp" source="loki.label.host-ip" defaultValue="localhost"/><springProperty scope="context" name="orgId" source="loki.org-id" defaultValue="xiaocai"/><appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender"><http class="com.github.loki4j.logback.ApacheHttpSender"><url>${url}</url><tenantId>${orgId}</tenantId></http><format><label><pattern>application=${jobName},env=${env},host=${hostIp},level=%level,traceid=%X{traceid:-0},urlPath=%X{urlPath:-0}</pattern></label><message><pattern>{"timestamp": "%d{yyyy-MM-dd HH:mm:ss.SSS}", "level": "%level", "logger": "%logger{36}", "thread": "%thread","traceid": "%X{traceid:-0}", "message": "%msg%n"}</pattern></message><sortByTime>true</sortByTime></format></appender><!-- 使用异步方式将日志推送至Loki --><appender name="ASYNC_LOKI" class="ch.qos.logback.classic.AsyncAppender"><!-- 队列大小设置,根据实际需要调整 --><queueSize>512</queueSize><!-- 丢弃策略,当队列满时采取的操作 --><discardingThreshold>0</discardingThreshold><neverBlock>true</neverBlock><!-- 实际的Loki Appender --><appender-ref ref="LOKI" /></appender><appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>DENY</onMatch><onMismatch>ACCEPT</onMismatch></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${log.pattern.no}</pattern></encoder><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--路径--><fileNamePattern>${LOG_FILE_DIR}/${jobName}info.%d.log</fileNamePattern><!--保留30天日志--><maxHistory>30</maxHistory></rollingPolicy></appender><appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${log.pattern.no}</pattern></encoder><!--滚动策略--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--路径--><fileNamePattern>${LOG_FILE_DIR}/${jobName}error.%d.log</fileNamePattern><!--保留30天日志--><maxHistory>30</maxHistory></rollingPolicy></appender><root level="info"><appender-ref ref="Console" /><appender-ref ref="fileInfoLog" /><appender-ref ref="fileErrorLog" /><if condition='${lokiEnabled} == true'><then><appender-ref ref="ASYNC_LOKI" /></then></if></root>
</configuration>

在这个配置中,日志会同时输出到控制台和 Loki。Loki4j 的 Loki4jHttpSender 会将日志推送到 Loki 的 API(在此例中是 http://localhost:3100)。

3.2.3. 配置application.yml设置开关以及配置项目相关信息

# Loki 日志配置  
loki:  # Loki 服务的 URL,用于推送日志数据  url: http://127.0.0.1:3100/loki/api/v1/push  log-file-dir: E:\xiaocaiDemo\log\1  enabled: true  # 标签配置,用于标识日志来源的额外信息  label:  # 环境标签,标识当前运行的环境,例如开发环境  env: dev  # 服务名称标签,标识日志来源的服务名称  job-name: xiaocaiDemo  # 主机 IP 标签,标识日志来源的主机 IP 地址  host-ip: localhost  # 组织 ID,用于多租户环境中标识日志所属的组织  org-id: Demo

3.2.4. 写一个Filter将所有的请求均生成一个唯一id

import org.apache.logging.log4j.ThreadContext;  
import org.springframework.stereotype.Component;  import javax.servlet.Filter;  
import javax.servlet.FilterChain;  
import javax.servlet.FilterConfig;  
import javax.servlet.ServletException;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletRequest;  
import java.io.IOException;  
import java.util.UUID;  @Component  
public class LogTraceIdFilter implements Filter {  public static final String LogTrace_ID = "traceid";  public static final String UrlPath_Key = "urlPath";  @Override  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  try {  // 生成唯一的日志ID  String logId = UUID.randomUUID().toString().replace("-","");  // 将日志ID放入MDC  ThreadContext.put(LogTrace_ID, logId);  ThreadContext.put(UrlPath_Key, ((HttpServletRequest) request).getRequestURI());  // 打印日志信息  HttpServletRequest httpRequest = (HttpServletRequest) request;  // 继续处理请求  chain.doFilter(request, response);  } finally {  // 清除MDC中的日志ID  ThreadContext.clearMap();  }  }  @Override  public void init(FilterConfig filterConfig) {  }  @Override  public void destroy() {  }  
}
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.web.servlet.FilterRegistrationBean;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  import javax.servlet.Filter;  */@Configuration  
public class Xiaocai_FilterConfig {  @Autowired  private LogTraceIdFilter logTraceIdFilter;  @Bean  public FilterRegistrationBean<Filter> logTraceIdFilterRegistrationBean() {  FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();  registrationBean.setFilter(logTraceIdFilter);  registrationBean.addUrlPatterns("*");  // 设置顺序,数值越小优先级越高  registrationBean.setOrder(1);  return registrationBean;  }  
}

3.2.5. 代码中使用

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;private final static Logger logger = LoggerFactory.getLogger(XiaocaiClass.class);logger.info(String.format("接口请求信息为:%s", strBuilder.toString()));

3.3.步骤 3:启动应用程序并生成日志

现在,您可以运行 Spring Boot 应用程序。应用程序启动后,生成的日志将通过 Loki4j 发送到 Loki。

使用以下命令启动 Spring Boot 应用:

mvn spring-boot:run

Spring Boot 应用程序运行后,日志会自动推送到 Loki,并通过 Grafana 可视化查看。

3.4.步骤 4:在 Grafana 中可视化日志

  1. 登录 Grafana。

  2. 进入 Explore 页面。

  3. 选择数据源为 Loki,然后在查询框中输入查询语句:

    {urlPath="/login/loginToken2LoginUserInfo"}
    

    你可以根据 Loki 的查询语法筛选和查看日志。

在这里插入图片描述

4.总结

  • Loki 提供日志的存储和索引,轻量高效。
  • Loki4j 使得 Java 应用可以轻松将日志推送到 Loki。
  • Grafana 用于查询和展示日志。
  • Spring Boot 作为 Java 应用框架,生成并发送日志。

通过这些步骤,您就搭建了一个轻量级且易于使用的 Java 日志系统。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com