知識庫 / Spring / Spring Boot RSS 訂閱

使用 Loki 記錄 Spring Boot 應用

Logging,Spring Boot
HongKong
4
11:16 AM · Dec 06 ,2025

1. 簡介

Grafana Labs 開發了 Loki,這是一個基於 Prometheus 的開源日誌聚合系統。它的目的是存儲和索引日誌數據,從而實現對來自各種應用程序和系統產生的日誌的有效查詢和分析。

在本文中,我們將為 Spring Boot 應用程序設置 Grafana Loki 的日誌記錄。Loki 將收集和聚合應用程序日誌,而 Grafana 則會顯示這些日誌。

2. 運行 Loki 和 Grafana 服務

我們將首先啓動 Loki 和 Grafana 服務,以便我們能夠收集和觀察日誌。Docker 容器將幫助我們更輕鬆地配置和運行它們。

首先,讓我們在 docker-compose 文件中組合 Loki 和 Grafana 服務:

version: "3"
networks:
  loki:
services:
  loki:
    image: grafana/loki:2.9.0
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - loki
  grafana:
    environment:
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
    entrypoint:
      - sh
      - -euc
      - |
        mkdir -p /etc/grafana/provisioning/datasources
        cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
        apiVersion: 1
        datasources:
        - name: Loki
          type: loki
          access: proxy
          orgId: 1
          url: http://loki:3100
          basicAuth: false
          isDefault: true
          version: 1
          editable: false
        EOF
        /run.sh
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    networks:
      - loki

接下來,我們需要使用 docker-compose 命令啓動服務:

docker-compose up

最後,讓我們確認這兩個服務是否正常運行:

docker ps

211c526ea384        grafana/loki:2.9.0       "/usr/bin/loki -conf…"   4 days ago          Up 56 seconds       0.0.0.0:3100->3100/tcp   surajmishra_loki_1
a1b3b4a4995f        grafana/grafana:latest   "sh -euc 'mkdir -p /…"   4 days ago          Up 56 seconds       0.0.0.0:3000->3000/tcp   surajmishra_grafana_1

3. 使用 Spring Boot 配置 Loki

在啓動 Grafana 和 Loki 服務後,我們需要配置應用程序將日誌發送到其中。 我們將使用 loki-logback-appender,它將負責將日誌發送到 Loki 聚合器以進行存儲和索引。

首先,我們需要在 pom.xml 文件中添加 loki-logback-appender

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

第二,我們需要在 src/main/resources 文件夾下創建一個 logback-spring.xml 文件。該文件將控制日誌行為,例如日誌格式、我們 Loki 服務端點以及其他內容,用於我們的 Spring Boot 應用程序:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>        
   <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
        <http>
            <url>http://localhost:3100/loki/api/v1/push</url>
        </http>
        <format>
            <label>
                <pattern>app=${name},host=${HOSTNAME},level=%level</pattern>
                <readMarkers>true</readMarkers>
            </label>
            <message>
                <pattern>
                    {
                    "level":"%level",
                    "class":"%logger{36}",
                    "thread":"%thread",
                    "message": "%message",
                    "requestId": "%X{X-Request-ID}"
                    }
                </pattern>
            </message>
         </format>
     </appender>
     
     <root level="INFO">
        <appender-ref ref="LOKI" />
     </root>
</configuration>

一旦設置完成,我們來編寫一個簡單的服務,用於以 INFO 級別記錄數據:

@Service
class DemoService{

    private final Logger LOG = LoggerFactory.getLogger(DemoService.class);

    public void log(){
        LOG.info("DemoService.log invoked");
    }
}

4. 測試驗證

讓我們通過啓動 Grafana 和 Loki 容器,並執行服務方法將日誌推送到 Loki 進行實時測試。之後,我們將使用 HTTP API 查詢 Loki,以確認日誌是否已成功推送。有關啓動 Grafana 和 Loki 容器的信息,請參閲之前的章節。

首先,讓我們執行 DemoService.log() 方法,這將調用 Logger.info()。 這將使用 loki-logback-appender 發送一條消息,Loki 將收集該消息。

DemoService service = new DemoService();
service.log();

其次,我們將創建一個請求,用於調用 Loki HTTP API 提供的 REST 端點。這個 GET API 接受 query 參數、start 時間和 end 時間,用於表示查詢、起始時間和結束時間。我們將這些參數作為請求對象的一部分添加:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

String query = "{level=\"INFO\"} |= `DemoService.log invoked`";

// Get time in UTC
LocalDateTime currentDateTime = LocalDateTime.now(ZoneOffset.UTC);
String current_time_utc = currentDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));

LocalDateTime tenMinsAgo = currentDateTime.minusMinutes(10);
String start_time_utc = tenMinsAgo.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));

URI uri = UriComponentsBuilder.fromUriString(baseUrl)
  .queryParam("query", query)
  .queryParam("start", start_time_utc)
  .queryParam("end", current_time_utc)
  .build()
  .toUri();

接下來,我們使用請求對象來執行 REST 請求:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(headers), String.class);

現在我們需要處理響應並提取我們感興趣的日誌消息。我們將使用一個 ObjectMapper 來讀取 JSON 響應並提取日誌消息:

ObjectMapper objectMapper = new ObjectMapper();
List<String> messages = new ArrayList<>();
String responseBody = response.getBody();
JsonNode jsonNode = objectMapper.readTree(responseBody);
JsonNode result = jsonNode.get("data")
  .get("result")
  .get(0)
  .get("values");

result.iterator()
  .forEachRemaining(e -> {
      Iterator<JsonNode> elements = e.elements();
      elements.forEachRemaining(f -> messages.add(f.toString()));
  });

最後,讓我們斷言我們收到的響應消息包含由 DemoService 記錄的消息:

assertThat(messages).anyMatch(e -> e.contains(expected));

5. 日誌聚合與可視化

我們的服務日誌通過配置 Loki 服務(使用 loki-logback-appender 配置)推送的。 您可以通過訪問 http://localhost:3000(Grafana 服務部署位置)在瀏覽器中進行可視化。

要查看已存儲和索引在 Loki 中的日誌,我們需要使用 Grafana。 Grafana 數據源提供用於 Loki 的可配置連接參數,其中需要輸入 Loki 端點、身份驗證機制等。

首先,讓我們配置日誌推送到的 Loki 端點:

在成功配置數據源後,讓我們轉到數據頁面以查詢我們的日誌:

我們可以編寫 查詢 以將應用程序日誌導入 Grafana 以進行可視化。 在我們的演示服務中,我們正在推送 INFO 日誌,因此我們需要將其添加到我們的過濾器並運行查詢:

在運行查詢後,您將看到所有匹配搜索的 INFO 日誌:

6. 結論

本文檔介紹瞭如何為 Spring Boot 應用程序設置日誌記錄,並使用 Grafana Loki。我們還通過單元測試和可視化驗證了配置,使用了簡單的邏輯,用於記錄 INFO 級別的日誌,並在 Grafana 中設置 Loki 數據源。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.