Node.js 檢測範例

本文說明如何修改 Node.js JavaScript 應用程式,以便使用開放原始碼 OpenTelemetry 架構收集追蹤記錄和指標資料,以及如何將結構化 JSON 記錄寫入標準輸出。本文也提供可安裝及執行的 Node.js 應用程式範例。應用程式使用 Fastify 網路架構,並已設定為產生指標、追蹤記錄和記錄。

如要進一步瞭解檢測功能,請參閱下列文件:

關於手動和零程式碼檢測

針對這門語言,OpenTelemetry 將「零程式碼檢測」定義為從程式庫和架構收集遙測資料的做法,且不必變更程式碼。不過,您確實有安裝模組和設定環境變數。

本文不會說明零程式碼檢測功能。如需相關資訊,請參閱「JavaScript 零程式碼檢測」。

如需一般資訊,請參閱「Node 適用的 OpenTelemetry 檢測工具」。

事前準備

Enable the Cloud Logging, Cloud Monitoring, and Cloud Trace APIs.

Enable the APIs

檢測應用程式以收集追蹤記錄、指標和記錄

如要檢測應用程式以收集追蹤記錄和指標資料,並將結構化 JSON 寫入標準輸出,請按照本文件後續章節所述的步驟操作:

  1. 設定 OpenTelemetry
  2. 設定應用程式,以便預先載入 OpenTelemetry 設定
  3. 設定結構化記錄
  4. 寫入結構化記錄檔

設定 OpenTelemetry

OpenTelemetry Node.js SDK 的預設設定會使用 OTLP 通訊協定匯出追蹤記錄。它還會將 OpenTelemetry 設為使用 W3C 追蹤記錄內容格式,用於傳播追蹤記錄內容。這項設定可確保跨度在追蹤記錄中具有正確的父項與子項關係。

以下程式碼範例說明如何設定 OpenTelemetry 的 JavaScript 模組。

如要查看完整範例,請按一下 「更多」,然後選取「前往 GitHub 查看」


diag.setLogger(
  new DiagConsoleLogger(),
  opentelemetry.core.getEnv().OTEL_LOG_LEVEL
);

const sdk = new opentelemetry.NodeSDK({
  instrumentations: getNodeAutoInstrumentations({
    // Disable noisy instrumentations
    '@opentelemetry/instrumentation-fs': {enabled: false},
  }),
  resourceDetectors: getResourceDetectorsFromEnv(),
  metricReader: getMetricReader(),
});

try {
  sdk.start();
  diag.info('OpenTelemetry automatic instrumentation started successfully');
} catch (error) {
  diag.error(
    'Error initializing OpenTelemetry SDK. Your application is not instrumented and will not produce telemetry',
    error
  );
}

// Gracefully shut down the SDK to flush telemetry when the program exits
process.on('SIGTERM', () => {
  sdk
    .shutdown()
    .then(() => diag.debug('OpenTelemetry SDK terminated'))
    .catch(error => diag.error('Error terminating OpenTelemetry SDK', error));
});

前述程式碼範例會將 OpenTelemetry 設為使用 OTLP 通訊協定匯出指標,並使用 @opentelemetry/auto-instrumentations-node 套件設定所有可用的 Node.js 檢測元件。

為確保所有待處理的遙測資料會在應用程式關閉前完成刷新,並且會順利關閉連線,SIGTERM 處理常式會呼叫 shutdown

如需詳細資訊和設定選項,請參閱「零程式檢測元件設定」。

設定應用程式,以便預先載入 OpenTelemetry 設定

如要設定應用程式以使用 OpenTelemetry 寫入結構化記錄檔,並收集指標和追蹤記錄資料,請更新應用程式的叫用作業,以便使用 Node.js --require 標記預先載入檢測模組。使用 --require 標記可確保 OpenTelemetry 在應用程式啟動前完成初始化。詳情請參閱「OpenTelemetry Node.js 入門」一文。

以下程式碼範例說明 Dockerfile 如何傳遞 --require 標記:

CMD node --require ./build/src/instrumentation.js build/src/index.js 2>&1 | tee /var/log/app.log

設定結構化記錄

如要將追蹤資訊納入以 JSON 格式寫入標準輸出的記錄,請將應用程式設為以 JSON 格式輸出結構化記錄。Fastify 會使用 Pino 記錄架構,並在每個要求處理常式中提供記錄器。以下程式碼範例說明 Pino LoggerOptions 物件,該物件會將應用程式設定為輸出 JSON 結構化記錄:


// Expected attributes that OpenTelemetry adds to correlate logs with spans
interface LogRecord {
  trace_id?: string;
  span_id?: string;
  trace_flags?: string;
  [key: string]: unknown;
}

// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity
const PinoLevelToSeverityLookup: Record<string, string | undefined> = {
  trace: 'DEBUG',
  debug: 'DEBUG',
  info: 'INFO',
  warn: 'WARNING',
  error: 'ERROR',
  fatal: 'CRITICAL',
};

export const loggerConfig = {
  messageKey: 'message',
  // Same as pino.stdTimeFunctions.isoTime but uses "timestamp" key instead of "time"
  timestamp(): string {
    return `,"timestamp":"${new Date(Date.now()).toISOString()}"`;
  },
  formatters: {
    log(object: LogRecord): Record<string, unknown> {
      // Add trace context attributes following Cloud Logging structured log format described
      // in https://cloud.google.com/logging/docs/structured-logging#special-payload-fields
      const {trace_id, span_id, trace_flags, ...rest} = object;

      return {
        'logging.googleapis.com/trace': trace_id,
        'logging.googleapis.com/spanId': span_id,
        'logging.googleapis.com/trace_sampled': trace_flags
          ? trace_flags === '01'
          : undefined,
        ...rest,
      };
    },
    // See
    // https://getpino.io/#/docs/help?id=mapping-pino-log-levels-to-google-cloud-logging-stackdriver-severity-levels
    level(label: string) {
      return {
        severity:
          PinoLevelToSeverityLookup[label] ?? PinoLevelToSeverityLookup['info'],
      };
    },
  },
} satisfies LoggerOptions;

先前的設定會從記錄訊息中擷取有效時間間隔的相關資訊,然後將該資訊做為屬性新增至 JSON 結構化記錄。這些屬性可用於將記錄與追蹤記錄建立關聯:

  • logging.googleapis.com/trace:與記錄項目相關聯的追蹤記錄資源名稱。
  • logging.googleapis.com/spanId:與記錄項目相關聯的追蹤記錄中的時距 ID。
  • logging.googleapis.com/trace_sampled:這個欄位的值必須是 truefalse

如要進一步瞭解這些欄位,請參閱 LogEntry 結構。

如要搭配 Fastify 使用 Pino 設定,請在建立 Fastify 應用程式時傳遞記錄器設定物件:

// Create the Fastify app providing the Pino logger config
const fastify = Fastify({
  logger: loggerConfig,
});

寫入結構化記錄檔

如要寫入連結至追蹤記錄的結構化記錄,請使用 Fastify 提供的 Pino 記錄器。例如,以下陳述式說明如何呼叫 Logger.info() 方法:

request.log.info({subRequests}, 'handle /multi request');

OpenTelemetry 會自動在 Pino 記錄項目中填入 OpenTelemetry 情境中目前有效區段的 區段情境。接著,系統會將這個跨度內容納入 JSON 記錄中,如「設定結構化記錄」一文所述。

執行已設定為收集遙測資料的範例應用程式

範例應用程式使用供應商中立格式,包括用於記錄的 JSON,以及用於指標和追蹤的 OTLP,以及 Fastify 架構。為了將遙測資料路由至 Google Cloud,這個範例會使用已設定 Google 匯出工具的 OpenTelemetry Collector。這個應用程式有兩個端點:

  • /multi 端點由 handleMulti 函式處理。應用程式中的負載產生器會向 /multi 端點提出要求。當這個端點收到要求時,會向本機伺服器上的 /single 端點傳送三到七個要求。

    /**
     * handleMulti handles an http request by making 3-7 http requests to the /single endpoint.
     *
     * OpenTelemetry instrumentation requires no changes here. It will automatically generate a
     * span for the handler body.
     */
    fastify.get('/multi', async request => {
      const subRequests = randInt(3, 8);
      request.log.info({subRequests}, 'handle /multi request');
    
      for (let i = 0; i < subRequests; i++) {
        await axios.get(`http://localhost:${port}/single`);
      }
      return 'ok';
    });
  • /single 端點由 handleSingle 函式處理。這個端點收到要求時,會先短暫休眠,然後以字串回應。

    /**
     * handleSingle handles an http request by sleeping for 100-200 ms. It writes the number of
     * milliseconds slept as its response.
     */
    fastify.get('/single', async request => {
      // Sleep between 100-200 milliseconds
      const sleepMillis = randInt(100, 200);
      request.log.info({sleepMillis}, 'Going to sleep');
      await sleep(sleepMillis);
      return `slept ${sleepMillis}\n`;
    });

下載及部署應用程式

如要執行範例,請按照下列步驟操作:

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. 複製存放區:

    git clone https://github.com/GoogleCloudPlatform/opentelemetry-operations-js
    
  3. 前往範例目錄:

    cd opentelemetry-operations-js/samples/instrumentation-quickstart
    
  4. 建構並執行範例:

    docker compose up --abort-on-container-exit
    

    如果您不是在 Cloud Shell 上執行,請將 GOOGLE_APPLICATION_CREDENTIALS 環境變數指向憑證檔案,然後執行應用程式。應用程式預設憑證會在 $HOME/.config/gcloud/application_default_credentials.json 提供憑證檔案。

    # Set environment variables
    export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
    export GOOGLE_APPLICATION_CREDENTIALS="$HOME/.config/gcloud/application_default_credentials.json"
    export USERID="$(id -u)"
    
    # Run
    docker compose -f docker-compose.yaml -f docker-compose.creds.yaml up --abort-on-container-exit
    

查看指標

範例應用程式中的 OpenTelemetry 檢測工具會產生 Prometheus 指標,您可以使用 Metrics Explorer 查看這些指標:

  • Prometheus/http_server_duration_milliseconds/histogram 會記錄伺服器要求的時間長度,並將結果儲存在直方圖中。

  • Prometheus/http_client_duration_milliseconds/histogram 會記錄用戶端要求的時間長度,並將結果儲存在直方圖中。

如要查看範例應用程式產生的指標,請按照下列步驟操作:
  1. 前往 Google Cloud 控制台的 「Metrics Explorer」頁面:

    前往 Metrics Explorer

    如果您是使用搜尋列尋找這個頁面,請選取子標題為「Monitoring」的結果

  2. 在 Google Cloud 控制台的工具列中,選取 Google Cloud 專案。 如要設定 App Hub,請選取 App Hub 主機專案或已啟用應用程式的資料夾管理專案。
  3. 在「指標」元素中,展開「選取指標」選單,在篩選列中輸入 http_server,然後使用子選單選取特定資源類型和指標:
    1. 在「Active resources」選單中,選取「Prometheus Target」
    2. 在「Active metric categories」(使用中的指標類別) 選單中,選取「Http」
    3. 在「Active metrics」選單中,選取指標。
    4. 點按「套用」
  4. 設定資料的檢視方式。

    當指標的測量值為累積值時,「Metrics Explorer」會自動根據對齊期間將測量資料標準化,因此圖表會顯示速率。詳情請參閱「類型、類型和轉換」。

    當系統測量整數或雙精度值時 (例如兩個 counter 指標),Metrics Explorer 會自動加總所有時間序列。如要查看 /multi/single HTTP 路徑的資料,請將「Aggregation」項目的第一個選單設為「None」

    如要進一步瞭解如何設定圖表,請參閱「在使用 Metrics Explorer 時選取指標」。

查看追蹤記錄

系統可能需要幾分鐘的時間才能提供追蹤資料。舉例來說,當專案收到追蹤記錄資料時,Google Cloud Observability 可能需要建立資料庫來儲存該資料。建立資料庫可能需要幾分鐘的時間,在此期間,您無法查看追蹤記錄資料。

如要查看追蹤記錄資料,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的「Trace Explorer」頁面:

    前往「Trace Explorer」頁面

    您也可以透過搜尋列找到這個頁面。

  2. 在頁面的表格部分,選取標間距名稱為 /multi 的資料列。
  3. 在「Trace details」面板的甘特圖中,選取標示為 /multi 的時距。

    畫面上會開啟一個面板,顯示 HTTP 要求的相關資訊。這些詳細資料包括方法、狀態碼、位元組數量,以及呼叫端的使用者代理程式。

  4. 如要查看與此追蹤記錄相關聯的記錄,請選取「Logs & Events」分頁標籤。

    這個分頁會顯示個別記錄。如要查看記錄項目的詳細資料,請展開記錄項目。您也可以按一下「查看記錄檔」,然後使用記錄檔探索工具查看記錄檔。

如要進一步瞭解如何使用 Cloud Trace 探索工具,請參閱「尋找及探索追蹤記錄」一文。

查看記錄檔

您可以透過「記錄檔探索器」檢查記錄,也可以查看相關的追蹤記錄 (如有)。

  1. 前往 Google Cloud 控制台的「Logs Explorer」頁面:

    前往「Logs Explorer」(記錄檔探索工具)

    如果您是使用搜尋列尋找這個頁面,請選取子標題為「Logging」的結果

  2. 找出說明為 handle /multi request 的記錄。

    如要查看記錄的詳細資料,請展開記錄項目。

  3. 在含有「handle /multi request」訊息的記錄項目上,按一下 「Traces」,然後選取「View trace details」

    「Trace details」面板會隨即開啟,並顯示所選的追蹤記錄。

    記錄資料可能會比追蹤資料早幾分鐘出現。如果您在查看追蹤記錄資料時遇到錯誤,無論是透過搜尋 ID 或按照本任務中的步驟操作,請稍候一兩分鐘,然後再重試該動作。

如要進一步瞭解如何使用記錄檔探索工具,請參閱「使用記錄檔探索工具查看記錄檔」。

後續步驟