iT邦幫忙

2025 iThome 鐵人賽

DAY 21
1
Modern Web

Line Bot × NestJS:30 天開發日記系列 第 21

Day 21:Nest Pino 整合 Grafana Loki 日誌

  • 分享至 

  • xImage
  •  

2025 鐵人賽背景圖

前言

Loki 環境變數可參考 Day 20 文章的 Grafana Data Source settings 設定

本文將介紹如何將 Nest.js Pino 整合 Grafana Loki 進行日誌收集。原本我們僅在開發環境中啟用 pino-pretty 來美化控制台的日誌輸出,現在將進一步設定生產環境的日誌系統。首先需要在 .env 中配置 LOKI_URLLOKI_USERLOKI_PASSWORD 等環境變數。

本日程式碼的範例連結

Step 1:設定 Loki 環境變數驗證規則

透過 nodeEnv 環境變數進行條件判斷,在生產環境強制要求完整配置 Loki 參數,開發環境則可選填。

config/configuration.ts

const configSchema = Joi.object({
  // Loki 日誌系統相關設定
  loki: Joi.object({
    url: Joi.string().uri().when(Joi.ref('/nodeEnv'), {
      is: 'production',
      then: Joi.required(), // 生產環境:必填
      otherwise: Joi.optional(), // 開發環境:選填
    }),
    user: Joi.string().when(Joi.ref('/nodeEnv'), {
      is: 'production',
      then: Joi.required(),
      otherwise: Joi.optional(),
    }),
    password: Joi.string().when(Joi.ref('/nodeEnv'), {
      is: 'production',
      then: Joi.required(),
      otherwise: Joi.optional(),
    }),
  }).optional(),
});


export default () => {
  const config = {
        // Loki 日誌系統相關設定
        loki: {
          url: process.env.LOKI_URL,
          user: process.env.LOKI_USER,
          password: process.env.LOKI_PASSWORD,
        },
    };
    
  const { error, value } = configSchema.validate(config, {
    abortEarly: false, // 顯示所有錯誤,而不是第一個錯誤就停止檢查
  });

  if (error) throw new Error(`環境變數驗證錯誤: ${error.message}`);

  return value;
};

Step 2:安裝 pino-loki 套件

執行以下指令安裝套件:

pnpm i pino-loki

Step 3:整合 Pino 與 Grafana Loki

透過 Pino 的 transport 機制將日誌傳輸至 Grafana Loki。在生產環境使用 pino-loki 透過 HTTP 將日誌傳送至 Grafana Cloud Loki,同時搭配 pino/file 輸出至控制台,確保本地使用生產環境時,也能即時查看日誌記錄。

針對 Loki 配置了以下參數:

  • interval:設定批次傳送間隔為 10 秒
  • labels:設定查詢標籤 app: nestjs-test,方便在 Grafana 中篩選日誌
  • host & basicAuth:配置 Loki 伺服器位址與認證資訊

config/logger.config.ts

/// 略
  transport:
    nodeEnv !== 'production'
      ? {
          // 開發環境專用 pino-pretty 美化 log 輸出
          target: 'pino-pretty',
          options: {
            colorize: true, // 顏色輸出
            singleLine: true, // 單行日誌
            messageFormat:
              '{if context}【{context}】- {end}{if msg}{msg}{end} {if responseTime}(took {responseTime}ms){end}', // 日誌顯示格式
            ignore: 'context,pid,hostname,responseTime,req,res', // 忽略屬性
            translateTime: 'yyyy-mm-dd HH:MM:ss', //時間格式
            levelFirst: true, // 日誌等級在最前面
          },
        }
      : {
          targets: [
            {
              target: 'pino/file', // 生產環境下載控制台也顯示紀錄
              options: {
                destination: 1,
              },
            },
            {
              target: 'pino-loki', 
              options: {
                interval: 10, // 批次傳送紀錄的時間,單位是秒。
                labels: { app: 'nestjs-test' }, // Grafana Loki 查詢標籤
                host: lokiUrl,
                basicAuth: {
                  username: lokiUser,
                  password: lokiPassword,
                },
              },
            },
          ],
        }

Step 4:驗證 Grafana Loki 日誌記錄

啟動前需先執行 pnpm run build 進行專案打包

啟動後端伺服器後,可在 Grafana Loki 觀察到伺服器啟動訊息已成功記錄,確認 Nest Pino 與 Grafana Loki 已正確整合。

Grafana 紀錄 Nest 啟動資訊

接著透過 LineBot 進行對話測試,驗證請求過程是否完整記錄。

Grafana Loki 查看 LINE 對話紀錄

【 Grafana Loki Line Format 小技巧 】

Grafana 使用 LogQL語法進行日誌查詢。目前顯示的訊息資訊較多,可透過 LogQL 語法調整顯示內容。

建議使用 Builder 模式進行操作,同時觀察 Code 部分的對應語法,有助於理解 pipeline 的執行流程:

  • Builder 模式:透過圖形化介面建立查詢
  • Code 模式:顯示對應的 LogQL 語法

以 JSON parser 為例
Grafana 查詢模式

Step 1:解析 JSON 日誌格式

透過 JSON parser 將日誌解析後,各個欄位(如 level、method、url、statusCode)會轉換為可查詢的標籤,方便後續篩選與處理。

JSON Parser 設定
Grafana 標籤篩選器

解析後的欄位結構
Grafana 日誌解析

Step 2:使用 Line format 自訂顯示格式

搭配 printf 模板函數自訂顯示內容。將前面 JSON 解析出的標籤直接套用,並加上換行符號,讓每則日誌顯示更好閱讀。

LINE Format 規則:
{{ printf "method: %s\npath: %s\nstatus: %v\nduration: %vms" .req_method .req_url .res_statusCode .responseTime }}

Line Format 設定
Grafana Loki PipeLine 格式化日誌訊息設定

格式化後的顯示結果
Grafana Loki 格式化訊息顯示結果

本日結語

今日完成 Nest.js Pino 與 Grafana Loki 的整合,從環境變數驗證、套件安裝到 transport 配置,完成生產環境的日誌監控。並且透過 LogQL 搭配 JSON parser 與 printf 模板函數,把原本難讀的日誌整理成結構化格式,多加練習就能體會標籤查詢日誌的便利性。


上一篇
Day 20:Grafana Loki 日誌服務 - 從申請到 API 串接測試
系列文
Line Bot × NestJS:30 天開發日記21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言