Hugo に OpenTelemetry を追加してみる

Page content

この記事は OpenTelemetry Advent Calendar 2025 11日目の記事です。

背景

このサイトはHugo を利用しており、OpenTelemetry を利用して計装してみたかったので、追加してみました。 トレースは Hoenycomb に送信します。 ただし、フロントエンドに Honeycomb の API Key を設定するわけには行かないため、Cloudflare Workers をバックエンドとして利用してトレースを転送します。

構成

  1. フロントエンド(Hugo)に OpenTelemetry のスクリプトを追加する
  2. バックエンド(Cloudflare Workers)にトレースを送信して Honeycomb に転送する
  3. Honeycomb でトレースを確認する

手順

1. フロントエンド(Hugo)に OpenTelemetry のスクリプトを追加する。

HugoのJS.Buildという機能を利用して、OpenTelemetryの計装スクリプトをフロントエンドに追加します。 バンドラはesbuildが兼ね備えているので、TypeScriptをそのまま記述してもビルドができます。 TypescriptとOpenTelemetryの依存関係を追加します。

npm i -D -E typescript
npm i -E @opentelemetry/api \
    @opentelemetry/context-zone \
    @opentelemetry/exporter-trace-otlp-http \
    @opentelemetry/instrumentation-document-load
    @opentelemetry/instrumentation-user-interaction \
    @opentelemetry/instrumentation-xml-http-request \
    @opentelemetry/resources \
    @opentelemetry/sdk-trace-web \
    @opentelemetry/semantic-conventions

TypeScriptの設定ファイルを作成します。

npx tsc --init

Otel計装用のスクリプト document-load.ts を作成します。

mkdir -p assets/js
touch assets/js/document-load.ts

document-load.ts は以下のようになります。

import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import { ZoneContextManager } from '@opentelemetry/context-zone';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction';
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
import { resourceFromAttributes } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';


const exporter = new OTLPTraceExporter({
  url: 'https://akky-me-honeycomb-worker.akky.workers.dev/v1/traces',
});

const provider = new WebTracerProvider({
  spanProcessors: [new SimpleSpanProcessor(exporter)],
  resource: resourceFromAttributes({
    [ATTR_SERVICE_NAME]: 'blog-akky-me',
  }),
});

provider.register({
  contextManager: new ZoneContextManager(),
});

registerInstrumentations({
  instrumentations: [
    new DocumentLoadInstrumentation(),
    new UserInteractionInstrumentation(),
    new XMLHttpRequestInstrumentation(),
  ],
});

ほぼ雛形そのままです。OpenTelemetryのGetting StartedExampleを参考にして作成しました。

次に、layouts/partials/otel.html を作成します。hugoのJS.Buildを利用して、OpenTelemetryの計装スクリプトをフロントエンドに追加します。

{{ $opts := dict "target" "es2020" "format" "esm" "minify" (not hugo.IsServer) }}
{{ with resources.Get "js/document-load.ts" | js.Build $opts | fingerprint "sha384" }}
<script type="module" src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script>
{{ end }}

layouts/_default/baseof.html に以下を追加します。

{{ partial "otel.html" . }}

これでフロントエンドに OpenTelemetry の計装スクリプトが追加されます。

2. バックエンド(Cloudflare Workers)でトレースを送信して Honeycomb に転送する。

Cloudflare Workers でトレースを Honeycomb に転送するコードを作成します。 LLMに作ってもらいました。 コードはこちら。 フロントエンドとホストが異なる場合はCORSの設定が必要です。 本来はサンプリングやフィルタリングを行うべきですが、今回は過疎サイトなので全て集計します。

3. Honeycomb でトレースを確認する。

Honeycomb でトレースを確認します。 自動的にリクエストのトレースが収集されています。 honeycomb-trace.png

まとめ

OpenTelemetry の計装を Hugo に追加してみました。 Hugo の JS.Build と Cloudflare Workers を利用して、簡単に OpenTelemetry を追加することができました。 プロダクトで使う場合は、料金コストやサンプリングによるデータの損失など考慮すべき点が多そうですが、今回は趣味のサイトなのでシンプルに実装しました。

PR

参考文献