Slide 1

Slide 1 text

TypeScript バックエンドの オブザーバビリティ戦略 | Datadog × NestJS の実践 2026. 05. 23 TSKaigi 2026 ⼭本 ⼤星 ∕ any 株式会社

Slide 2

Slide 2 text

⾃⼰紹介 2 ● エンジニア歴 9 年⽬, TypeScript 歴 5 年⽬ ● Java/PHP/Vue.js 4 年 → React/NestJS 5 年 ● ⼤⼿通信事業者でWebアプリ&バーチャルオフィスSaaS → any (現職 2 年半前) ● 機能開発の傍ら 約 2 年前に Datadog 導⼊PJを推進 ● 直近: 技術的負債解消/パフォーマンス, DX改善の専任チーム ⼭本 ⼤星 any 株式会社

Slide 3

Slide 3 text

3 ユーザー数 80,000 ⼈突破 BOXIL SaaS AWARD 2021 ⼤企業賞 IVS Launchpad 5位 ⼊賞 社内に埋もれている情報や⼈のノウハウを蓄積し、 RAGを使っていつでも引き出せるようにすることで、 組織全体の⽣産性向上と組織の壁を超えるサービス。 ナレッジの資産化が、 企業の未来をつくり出す。 AIナレッジプラットフォーム

Slide 4

Slide 4 text

技術スタックの紹介 4

Slide 5

Slide 5 text

オブザーバビリティとは 5

Slide 6

Slide 6 text

(私の考える)オブザーバビリティとは 6 運⽤トラブルの原因特定をスムーズに⾏うための “仕込み” よくあるトラブル ‧「あれ、なんかシステムがうまく動かないぞ」 ‧「お客さんから問い合わせ、クレームがきちゃった」 ‧「なんかエラーログ、アラートが上がってるな」 こういう時に「原因に辿り着きやすい状態」を作ること

Slide 7

Slide 7 text

オブザーバビリティ > 例えばこんなことができる状態1 7 DBの調査 どのレコードが悪さしてるのかな 外部システムの影響 レイテンシ増加が原因なのかな アクセス急増の要因分析 単にユーザー増? それともバグでリダイレクトが⼤量発⽣? はたまたDoS 攻撃? → 「もうちょっと調べてみよう」ができる状態

Slide 8

Slide 8 text

オブザーバビリティ > 例えばこんなことができる状態2 8 ベテランならできること → 誰でも判断しやすい状態にする ベテラン 新顔 不慣れな⼈ ベテランの判断 新顔や普段運⽤に慣れてない⼈

Slide 9

Slide 9 text

Datadog導⼊以前(〜2024)の構成 9 ログ集約‧エラー検知 CloudWatch Logs AWSベースの 最⼩限の構成 コンテナ停⽌の通知 EventBridge → Lambda → Slack

Slide 10

Slide 10 text

現在(2026)の構成 10 👏👏

Slide 11

Slide 11 text

現在(2026)の構成 11 APM: アプリケーションのトレース 👏👏

Slide 12

Slide 12 text

現在(2026)の構成 12 Error Tracking: エラーの集約‧分析 👏👏

Slide 13

Slide 13 text

現在(2026)の構成 13 Dashboard: 各種メトリクス‧監視データを集中管理 👏👏

Slide 14

Slide 14 text

現在(2026)の構成 14 👏👏

Slide 15

Slide 15 text

現在(2026)の構成 15 👏👏 ツールを⼊れるだけ ではオブザーバビリティは向上しない 🙅 アプリケーションも⼀緒に “進化” させる必要がある

Slide 16

Slide 16 text

TypeScript バックエンドの オブザーバビリティ戦略   Datadog × NestJS を2年かけて整備し⾒えてきた   “気負わない運⽤”のためのアプリケーション設計

Slide 17

Slide 17 text

2つのセクションに分けて話します 17 1. ⼊⾨者向け オブザーバビリティこれからやっていき 2. Datadog初級者向けTIPS 💪 👀 Datadog を導⼊検討中、運⽤はじめた ばかりの⼈ プラグイン有効化の罠 ちょうど良い dd-trace 依存のすゝめ ログを構造化する エラーの情報量を増やす ❶ ❷ ❶ ❷

Slide 18

Slide 18 text

2つのセクションに分けて話します 18 1. ⼊⾨者向け オブザーバビリティこれからやっていき ログを構造化する エラーの情報量を増やす ❶ ❷ 💪 Datadog を導⼊検討中、運⽤はじめた ばかりの⼈ プラグイン有効化の罠 ちょうど良い dd-trace 依存のすゝめ ❶ ❷ 👀 2. Datadog初級者向けTIPS

Slide 19

Slide 19 text

1. ログの “構造化” とは 19 Before: ⾮構造化(⼈間向け) After: JSON 構造化(機械向け) なぜ嬉しいか ● フィールド単位で検索‧集計やアラート構築できる⼟台 ● 後の trace_id 連携‧プロパティ付与の⼟台

Slide 20

Slide 20 text

1. ログの “構造化” > Datadog での⾒え⽅ 20

Slide 21

Slide 21 text

1. ログの “構造化” > 設定コード例 — NestJS の場合 21 NestJS docs: Logger # json-logging のサンプルを参考に ● 本番では JSON、ローカルでは⾊付き text ● これだけでログの フィールド検索‧集計 がしやすくなる

Slide 22

Slide 22 text

2. エラーのプロパティを増やす 22 Before: スタックトレースとメッセージだけ After: エラークラス名 / context / cause を追加 ● エラークラスにこれらのプロパティを適切に保持、Loggerで出⼒されるようにする ● エラー発⽣時の状況 が⾒えやすくなる

Slide 23

Slide 23 text

2. エラーのプロパティを増やす > コード例 23 ● cause チェーンで発⽣源クラスを特定, context にエラー発⽣時の状況を保持 ● ログ出⼒時に toJSON が呼び出されると各種エラー情報がログで確認できるように

Slide 24

Slide 24 text

次にいきましょう 24 オブザーバビリティこれからやっていき ログを構造化する エラーの情報量を増やす ❶ ❷ 💪 2. Datadog初級者向けTIPS 👀 Datadog を導⼊検討中、運⽤はじめた ばかりの⼈ プラグイン有効化の罠 ちょうど良い dd-trace 依存のすゝめ ❶ ❷ 1. ⼊⾨者向け

Slide 25

Slide 25 text

TIPS1: Datadogライブラリに巻き込まれてアプリが落ちた話 25 1.ドキドキのリリース完了 2.鳴り⽌まないアラート 3. リバートするしか... 事前検証もOKだったし、 ライブラリ⼊れて APM 動かすぞ! えっ落ちるはずない… 事前にちゃんと調べたし… 他に原因なさそうだし仕⽅ない …あれ、アラート⽌まったぞ

Slide 26

Slide 26 text

TIPS1: APMプラグインが悪さをしていた模様 26 ● 後⽇調べたら Maximum call stack size exceededエラー が直接的な原因であることが判明 ● SQLクエリなどを確認できる APMのDBプラグインを無効化することで事象を抑⽌ できた ● APMのプラグインは⾃動で全て有効化される仕様 ● 根本原因ははっきり特定できなかったが、おそらく GraphQL の Field Resolver による深いネスト再帰処理 とアプリのDBライブラリが関係してそう ※APMプラグイン=各種ミドルウェア/ライブラリの詳細をトレーシングできる機能

Slide 27

Slide 27 text

TIPS1: APMプラグインが悪さをしていた模様 27 ● 後⽇調べたら Maximum call stack size exceededエラー が直接的な原因であることが判明 ● SQLクエリなどを確認できる APMのDBプラグインを無効化することで事象を抑⽌ できた ● APMのプラグインは⾃動で全て有効化される仕様 ● 根本原因ははっきり特定できなかったが、おそらく GraphQL の Field Resolver による深いネスト再帰処理 とアプリのDBライブラリが関係してそう ※APMプラグイン=各種ミドルウェア/ライブラリの詳細をトレーシングできる機能 APMプラグインの有効化は慎重に!

Slide 28

Slide 28 text

TIPS2: dd-trace に “ちょうど良く” 依存する 28

Slide 29

Slide 29 text

29 1.書き込み 投稿の作成/更新/削除 投稿データの永続化 変更イベントを キューイング 2.イベント発⾏ 3.メッセージ取得 4.インデックス 更新 インデックス 更新作業 ⾼速な全⽂検索を実現 dd-trace が関知してくれない TIPS2: dd-trace に “ちょうど良く” 依存する SQS編

Slide 30

Slide 30 text

30 1.書き込み 投稿の作成/更新/削除 投稿データの永続化 変更イベントを キューイング 2.イベント発⾏ 3.メッセージ取得 4.インデックス 更新 インデックス 更新作業 ⾼速な全⽂検索を実現 dd-trace が関知してくれない TIPS2: dd-trace に “ちょうど良く” 依存する SQS編 独⾃に APM のトレースを開始するような処理を書かないといけない 書き⽅によっては “dd-trace にがっつり依存するようなコード” に⚠

Slide 31

Slide 31 text

TIPS2: dd-trace に “ちょうど良く” 依存する SQS編 31 アプリ層 ⾃作ライブラリ層 Datadog - ビジネスロジックに集中 - - @qast/sqs-helpers - tracer は import しない × SQS受信/メッセージ処理の抽象化 span の⽣成‧タグづけ Datadog依存をライブラリ内で完結 dd-trace による トレース情報の作成 APM / Trace @EventPattern('updateEntry') async handle(@Payload() msg) { // ビジネスロジック } handler を書くだけ await tracer.trace( `processMessage ${pattern}`, async span => { span.addTags({ 'sqs.body': message.Body }); await handleMessage(); }); ⾃作 SQS Transport内

Slide 32

Slide 32 text

TIPS2: dd-trace に “ちょうど良く” 依存する Logger編 32

Slide 33

Slide 33 text

TIPS2: dd-trace に “ちょうど良く” 依存する Logger編 33 アプリ層 ⾃作ライブラリ層 Datadog - ビジネスロジックに集中 - - @qast/logger - tracer は import しない × trace_id / span_id が⾃動付与 Logs (構造化ログ) APM / Trace this.logger.log( ‘User updated entry’, { entryId, userId } ); logger を呼び出すだけ const span = tracer.scope().active(); if (span) { tracer.inject( span.context(), formats.LOG, output ); } ⾃作 Logger 内 対応するリクエスト‧処理にジャンプ trace_id / span_id で紐付け ..., "dd": { "trace_id": "1234567890...", "span_id": "9876543210..." }

Slide 34

Slide 34 text

まとめ 34 1. ⼊⾨者向け オブザーバビリティこれからやっていき 2. Datadog初級者向けTIPS Datadog を導⼊検討中、運⽤はじめた ばかりの⼈ プラグイン有効化の罠 ちょうど良い dd-trace 依存のすゝめ ログを構造化する エラーの情報量を増やす ❶ ❷ ❶ ❷ 💪 👀

Slide 35

Slide 35 text

35

Slide 36

Slide 36 text

おまけ. ログに共通コンテキストを載せる 36 Before: 「何が起きた」だけ After: 「誰の何の処理か」が全ログ共通でわかる ● 単発ログ → requestId などをベースに一連の 追跡可能なログへ ● 顧客からの問い合わせに対応しやすくなる

Slide 37

Slide 37 text

おまけ. 共通コンテキスト > コード例 37 ● 呼び出し側は何も意識せず logger を呼び出せば適切な context がセットされる ● NestJSでは nestjs-cls ライブラリを使うのが慣⽤だったりする

Slide 38

Slide 38 text

38