Deno で OpenTelemetry を使って New Relic にデータを送出する

Deno 2.1.8 が、2025年1月末にリリースされた。
このリリースの中に、feat(unstable): support https otlp endpoints という PR が含まれている。
そして 2月19日に公開された Deno 2.2 の公開で改めてリリースノートでも掲載された。

Deno 2.1.0 くらいからOTELがreleasesに載るようになっていた、
初期では、[OpenTelemetry Collector] といったデータを受信・処理・送出するサーバー/サービスを要していた。
先のプルリクで、https エンドポイントに対応した。
httpsエンドポイントに対応したことで、経験した範囲ではNew Relic に対して、データを送出できるようになったはずである。

今回は、それを試し共有する。

参考

OTELでデータ送出

仕様確認

Deno の OTEL に関する仕様は、Deno Manual に記載されている。
しかし、https エンドポイントについては記述が無いので、PRの記述内容も加味して用意する。

console.* の出力画送信対象になるので、deno init --serve で用意されるものをなるべくシンプルにする。

new Relic でキーを取得

キーは、API Keys 画面で発行できる。
Key-typeは、INGEST - LICENSE で発行するのがポイント。

アプリケーションの作成

main.ts
1
2
3
4
5
6
7
export default {
fetch(req) {
console.log(`access: ${req.url}`);

return new Response("Hello World");
},
} satisfies Deno.ServeDefaultExport;

実行

以下の様に、コマンドで環境変数を渡す形を取った。

1
$ OTEL_DENO=true OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.nr-data.net:4317/ OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_HEADERS="api-key=[管理画面で取得したキー]"  deno serve --unstable-otel --watch main.ts

起動し適当なリクエストを送ってから、New RelicのLogs の画面で見ると、以下のようにデータが送出されていることが確認できる。

すばらしい。データが送出されている。
すばらしいのが、ランタイム自体が出力しているdeno serve: Listening on http://0.0.0.0:8000/ なども取れているという点。

注意事項

試す中で、以下のことが確認できた。そのうち修正されることを見込む。

  • --env-file で環境変数を渡すと想定動作をしない。
    Deno.env.read で設定自体は読み込めたがどうやら設定がされない様子。

拡張

公式のドキュメントで@opentelemetry/api の使用について言及がある。
これを例に先のmain.ts を拡張する。

main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { trace } from "npm:@opentelemetry/api@1.9.0";

export default {
fetch(req) {
const span = trace.getActiveSpan()!;
span.addEvent("fetching", { url: req.url });
span.setAttribute("url", req.url);
span.updateName(`${req.method} ${req.url}`);

console.log(`access: ${req.url}`);

return new Response("Hello World");
},
} satisfies Deno.ServeDefaultExport;

この状態で同様にアクセスを行い、適当にURLも変えていくと、以下のようにデータが送出されていることが確認できる。
この場合、logではなくtraces でデータを確認できる。

logよりもtracesの方が、若干反映画遅く感じたがサービスによる可能性がある。

unknown_service の部分は、OTEL_SERVICE_NAME で設定できる。
OTEL_SERVICE_NAME=deno-otel とすると、deno-otel と記載される。

ドキュメントには、他のcontextについての記述もあるが、現時点でどのように使うのかが見えなかったので、一旦保留とした。

trace.id

先のログをもう少し確認していくと表示項目にtrace.idを増やすことができた。
これは1処理について関連づいたIDの発行が行われていた。
例えば以下のような、実装があるとする。
リクエストへの応答に対してdelayを入れ、複数のリクエストが滞留するようにする。

main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { delay } from "jsr:@std/async/delay";

export default {
async fetch(req) {
console.log("fetching");
console.log(`access: ${req.url}`);
await delay(1000);
console.log("message 1");
await delay(1000);
console.log("message 2");

return new Response("Hello World");
},
} satisfies Deno.ServeDefaultExport;

new Relic の画面で確認すると、以下のようにtrace.id がリクエストの単位で共通の値を割り当てられている。

自前でトレース用のIDなど発行が不要になり、非常に助かる。


Deno の OpenTelemetry について、https エンドポイントに対応したので、New Relic で動作確認した。
unstable なのもありこれからも変更の想定や、今回確認された –env-file の対応具合にも変更があるだろう。

では。