<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Observability · 仁才徳</title>
    <link>https://jared.lynskey.co.nz/ja/tags/observability/</link>
    <description>ソフトウェアエンジニアリングと開発組織のリーダーシップについて。評価、採用とチームの拡大、CI/CD、DevOps モニタリング、エージェンティック AI。ソウルより。</description>
    <generator>Hugo</generator>
    <language>ja</language>
    <copyright>© 2026 仁才徳</copyright>
    <lastBuildDate>Sat, 07 Nov 2026 00:00:00 +1300</lastBuildDate>
    <atom:link href="https://jared.lynskey.co.nz/ja/tags/observability/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Fly.io上のDjangoをモニタリングする：残したDevOpsツールと、やめたもの</title>
      <link>https://jared.lynskey.co.nz/ja/posts/2026/2026-10-22-monitoring-tools-two-products/</link>
      <guid isPermaLink="true">https://jared.lynskey.co.nz/ja/posts/2026/2026-10-22-monitoring-tools-two-products/</guid>
      <pubDate>Thu, 22 Oct 2026 00:00:00 +1300</pubDate>
      <dc:creator>Jared Lynskey</dc:creator>
      <category>DevOps</category>
      <category>Monitoring</category>
      <category>Observability</category>
      <category>Site Reliability</category>
      <category>Fly.io</category>
      <category>Django</category>
      <category>Cloudflare</category>
      <category>Sentry</category>
      <category>Crash Reporting</category>
      <category>Small Teams</category>
      <category>Tech Stack</category>
      <description>Fly.io上の小さなDjangoアプリ2つを月2ドルほどで監視する方法。エラーはチャットへ、ログはS3に置いてDuckDBで検索、Flyのメトリクス、クラッシュレポート、そしてやめたもの。</description>
      <content:encoded><![CDATA[<p>私が作っているマーケットプレイス兼コミュニティアプリと、現場で見積もりを出す職人向けの見積もりアプリ。どちらも小さなプロダクトで、どちらもFly.ioのいちばん安いマシンで動いています。私のDevOpsモニタリングは、突き詰めると5つです。ERRORログを流すチャットチャンネル、オブジェクトストレージに全部ためてDuckDBで問い合わせるログ、Flyに標準で付いてくるPrometheusメトリクス、SentryのオープンソースSDKで拾って自前のAPIに送るアプリのクラッシュレポート、そして毎朝1本のサマリー投稿です。</p>
<p>ホスティング型のAPMも、本番のトレーシングも、わざわざ思い出して開くダッシュボードもありません。追加でお金がかかっているのはログアーカイブだけで、月2ドルほどです。以下が全リストと、やめたもの・信じなくなったものです。そのうちのひとつのせいで、私はユーザーが誰ひとり体験していない障害を何日も追いかけていました。</p>

<h2 class="relative group">ここで言うモニタリングと、どれだけ小さな規模の話か
    <div id="ここで言うモニタリングとどれだけ小さな規模の話か" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%81%93%e3%81%93%e3%81%a7%e8%a8%80%e3%81%86%e3%83%a2%e3%83%8b%e3%82%bf%e3%83%aa%e3%83%b3%e3%82%b0%e3%81%a8%e3%81%a9%e3%82%8c%e3%81%a0%e3%81%91%e5%b0%8f%e3%81%95%e3%81%aa%e8%a6%8f%e6%a8%a1%e3%81%ae%e8%a9%b1%e3%81%8b" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>私がDevOpsモニタリングと言うときは、2つのことを指しています。誰かに言われる前に何かが壊れていると気づけること、そして当て推量なしに原因を突き止められることです。以下のツールはすべて、この2点で評価しています。</p>
<p>昨年、<a href="https://jared.lynskey.co.nz/ja/posts/2025/2025-10-13-devops-monitoring/" >開発者が本当に使ってくれるモニタリングの作り方</a>という記事を書きましたが、そのときはおもにチームを想定していました。小さなチームならクラウド事業者に組み込みのモニタリング、サービスが何百もあるならホスティング型のAPM、という具合です。今回はその同じ考え方の、いちばん小さい側の端です。2つのプロダクトはどちらも<a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-07-22-my-current-stack/" >いまの技術スタック</a>で書いたとおりFlyのshared-cpu-1xマシン上のDjangoで、開発者はどちらも私ひとりです。モニタリングがプロダクトで開発者がそのユーザーだとすれば、私のモニタリングのユーザーは1人だけということになります。9月にFlyのメトリクスからベースラインを取ったところ、マーケットプレイスのAPIのCPU使用率は平均1%でした。エンタープライズのスタックではありませんし、そう見せるつもりもありません。</p>
<p>メトリクス、ログ、トレースの3本柱のうち、私が持っているのは2本です。どちらのプロダクトにも分散トレーシングはありません。それぞれDjangoのコードベースひとつとデータベースひとつで、トレースがまたぐべきサービス境界がないからです。私が見ているトレースは、<a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-10-01-cloudflare-warp-dev-network/" >自分のワークステーション</a>で動かしているリバースプロキシのものだけです。</p>

<h2 class="relative group">一覧
    <div id="一覧" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%80%e8%a6%a7" aria-label="アンカー">#</a>
    </span>
    
</h2>
<table>
	<thead>
			<tr>
					<th>ツール</th>
					<th>何を見ているか</th>
					<th>残したか、やめたか、その理由</th>
					<th>費用</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Djangoのロギングハンドラーから流すチームのチャットチャンネル</td>
					<td>API・WebSocketサーバー・ワーカーのERROR、デプロイ、間違ったサインインコードの集中</td>
					<td>残した。言われなくても見に行く唯一の場所</td>
					<td>無料</td>
			</tr>
			<tr>
					<td>FlyのログシッパーからS3互換のバケットへ、DuckDBで問い合わせ</td>
					<td>マーケットプレイスのアプリのログ全行</td>
					<td>残した。Fly自身のバッファは数分、こちらは全部、しかもSQLで</td>
					<td>月約2ドル+ストレージ</td>
			</tr>
			<tr>
					<td>Fly標準のメトリクス(Prometheus API)</td>
					<td>CPU、メモリ、バーストクレジット、レスポンス、マネージドPostgresのエクスポーター</td>
					<td>残した。DBの停止が自分のコードのせいではないと示してくれた</td>
					<td>Flyに含まれる</td>
			</tr>
			<tr>
					<td><code>/api/health/</code> のFlyヘルスチェック(両アプリ)</td>
					<td>マシンにトラフィックを送ってよいか</td>
					<td>ルーティング用には残した。ユーザーが無事な証拠としてはやめた</td>
					<td>Flyに含まれる</td>
			</tr>
			<tr>
					<td>DSNを自前APIに向けたSentryのSDK</td>
					<td>スマホで起きるアプリのクラッシュ</td>
					<td>SDKは残した。sentry.ioには登録していない</td>
					<td>API以外の追加なし</td>
			</tr>
			<tr>
					<td>チームのチャットへの朝のサマリー</td>
					<td>前日のエラー、利用状況、検索、チャット、ボード</td>
					<td>残した。CIのcronジョブから自分のMacへ移した</td>
					<td>無料</td>
			</tr>
			<tr>
					<td>アプリ用のアナリティクスSDK(両アプリ)と、検索エンジンのウェブマスター向けコンソール</td>
					<td>Web・iOS・Androidの利用状況、検索からのサイトの見え方</td>
					<td>残した。APIで読んでいる</td>
					<td>無料</td>
			</tr>
			<tr>
					<td>CloudflareのGraphQLアナリティクス</td>
					<td>ステータスコードやパスの裏に誰がいるか</td>
					<td>残した。ただし信じる前にユーザーエージェントでまとめる</td>
					<td>無料プラン、1クエリ1日分</td>
			</tr>
			<tr>
					<td>ホスティング型OTAアップデートサービスのダッシュボード</td>
					<td>端末がどのOTAリリースを動かしているか、クラッシュロールバック</td>
					<td>何も教えてくれなかった管理画面の一覧から移った</td>
					<td>アップデートサービスの一部</td>
			</tr>
			<tr>
					<td>小さなプローブ用スクリプト</td>
					<td>デプロイや再起動の最中に失敗したリクエスト</td>
					<td>残した。オリジンを直接叩くので、キャッシュが空白を隠せない</td>
					<td>無料</td>
			</tr>
			<tr>
					<td><code>flyctl logs</code></td>
					<td>アプリ出力の直近数分</td>
					<td>ライブ表示用には残した。記録としてはやめた</td>
					<td>Flyに含まれる</td>
			</tr>
			<tr>
					<td>Cloudflare Early Hints</td>
					<td>何も見ていない。高速化の機能</td>
					<td>オリジンが <code>Link</code> ヘッダーを送るようにしてからは使っている。そのキャッシュミスがゾーンの504のすべてだった</td>
					<td>無料</td>
			</tr>
	</tbody>
</table>
<p>「両アプリ」と書いていないものは、すべてマーケットプレイスの話です。見積もりアプリはもっと少なく、Flyのヘルスチェック・ログ・メトリクス、iOSのアプリ解析、そしてデータベースを毎日Parquetに書き出してDuckDBで問い合わせる仕組みくらいです。クラッシュレポートもアラートのチャンネルもなく、この記事でいちばん大きな穴はここです。(アップデートサービスの行について開示しておくと、このサービスを提供している会社は、同社のブログに書く記事に対して私に報酬を払っています。)</p>

<h2 class="relative group">エラー：チャットに投稿するロギングハンドラー
    <div id="エラーチャットに投稿するロギングハンドラー" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%82%a8%e3%83%a9%e3%83%bc%e3%83%81%e3%83%a3%e3%83%83%e3%83%88%e3%81%ab%e6%8a%95%e7%a8%bf%e3%81%99%e3%82%8b%e3%83%ad%e3%82%ae%e3%83%b3%e3%82%b0%e3%83%8f%e3%83%b3%e3%83%89%e3%83%a9%e3%83%bc" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>9月までは、処理されなかった500も、失敗したプッシュ通知も、壊れたWebSocketフレームも、出てくる場所は <code>flyctl logs</code> だけでした。そしてあのストリームを自分から読みに行く人はいません。いまはロギングハンドラーが、API・WebSocketサーバー・バックグラウンドワーカーのどこで起きたものでも、ERROR以上のレコードをすべてチャットチャンネルに送ります。WARNINGはあえて通知しません。</p>
<p>ハンドラーはバックグラウンドのスレッドで送信するので、リクエストを遅くしません。ハンドラーの中では何もログに書かないので、再帰しません。そして同じエラーは10分に1回まで、1時間に最大30件までしか送らないので、障害が起きても千件のメッセージではなく1件として読めます。</p>
<p>このチャンネルには、エラーと突き合わせて読みたいものも流れてきます。デプロイは開始時、立ち上がったとき、失敗した箇所でコミットと実行者付きで投稿し、OTAアップデートや<a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-09-14-web-releases-without-redeploying/" >Webリリース</a>も同じです。ひとつのアカウントに間違ったサインインコードが集中したときもERRORで記録するので、誰かが当てずっぽうに試していれば障害と同じ場所に現れます。</p>
<p>10月、どのログにも対応する行がないアラートがひとつ届きました。それ以来、アラートには短いランダムなid、ホスト名、プロセスの起動コマンドを付け、同じ行をそのプロセスのログにも書くようにしています。idがどこにも見つからなければ、そのアラートはそこにログを書かないプロセス、たとえばSSHのシェルから来たということです。チャンネルに届くものはすべて、私が一緒に作業しているコーディングエージェントが読めるフィードにも入ります。コードを触っているエージェントも、私と同じタイミングでエラーを目にするわけです。</p>

<h2 class="relative group">ログ：FlyのシッパーでS3へ、DuckDBで検索
    <div id="ログflyのシッパーでs3へduckdbで検索" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%ad%e3%82%b0fly%e3%81%ae%e3%82%b7%e3%83%83%e3%83%91%e3%83%bc%e3%81%a7s3%e3%81%b8duckdb%e3%81%a7%e6%a4%9c%e7%b4%a2" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>Fly自身のバッファが持っているのは数分ぶんの出力、だいたい直近100行ほどです。デプロイを見守るには十分ですが、昨日のことには役に立ちません。そこで3つめのFlyアプリでFlyのログシッパーを動かしています。組織のログストリームを購読するVectorで、変えたのはS3シンクひとつだけです。</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">sinks</span><span class="p">.</span><span class="nx">aws_s3</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">type</span> <span class="p">=</span> <span class="s2">&#34;aws_s3&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">bucket</span> <span class="p">=</span> <span class="s2">&#34;myapp-logs&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">compression</span> <span class="p">=</span> <span class="s2">&#34;gzip&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">key_prefix</span> <span class="p">=</span> <span class="s2">&#34;logs/{{fly.app.name}}/%F/&#34;</span>   <span class="c"># one folder per app per day</span>
</span></span><span class="line"><span class="cl">  <span class="nx">batch</span><span class="p">.</span><span class="nx">timeout_secs</span> <span class="p">=</span> <span class="mi">300</span>                  <span class="c"># a quiet app still lands its lines</span></span></span></code></pre></div></div>
<p>マーケットプレイスのアプリのログは1行残らず、gzipしたJSONとしてS3互換のバケットにたまります。シッパーは256MBのshared-cpu-1xマシン1台で、月2ドルほど、ストレージ代は小銭程度です。DuckDBはマクロひとつでファイルをその場で読み、1日分ならおよそ1秒で返ってきます。</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">CREATE</span><span class="w"> </span><span class="n">MACRO</span><span class="w"> </span><span class="n">logs</span><span class="p">(</span><span class="n">app</span><span class="p">,</span><span class="w"> </span><span class="k">day</span><span class="w"> </span><span class="p">:</span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;*&#39;</span><span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="k">TABLE</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">read_json_auto</span><span class="p">(</span><span class="s1">&#39;s3://myapp-logs/logs/&#39;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">app</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">&#39;/&#39;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="k">day</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">&#39;/*.log.gz&#39;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                               </span><span class="n">union_by_name</span><span class="w"> </span><span class="p">:</span><span class="o">=</span><span class="w"> </span><span class="k">true</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="k">timestamp</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">logs</span><span class="p">(</span><span class="s1">&#39;myapp-api&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;2026-09-06&#39;</span><span class="p">)</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">message</span><span class="w"> </span><span class="k">LIKE</span><span class="w"> </span><span class="s1">&#39;% 500 %&#39;</span><span class="p">;</span></span></span></code></pre></div></div>
<p><a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-09-09-scale-to-zero-504s/" >ゼロスケールの記事</a>でコールドスタートを測ったのも、このマクロでした。起動スクリプトがフェーズごとに名乗り、どの行にもマシンのidが付いているので、あとは <code>GROUP BY</code> だけです。</p>
<p>つまり、ひとつのストリームを読む人ごとに3段階に分けているわけです。アーカイブはINFO以上をすべて保持し(本番のアプリがINFOでログを出しているのはこのためです)、ライブ表示のスクリプトはWARNINGとERRORだけを見せ、チャットチャンネルはERRORを受け取ります。ただ、どれも呼び出し元はわかりません。アクセスログにはクライアントのIPもユーザーエージェントもないので、それはCloudflareで調べます。</p>

<h2 class="relative group">メトリクス：Flyに標準で付いてくるPrometheus
    <div id="メトリクスflyに標準で付いてくるprometheus" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%a1%e3%83%88%e3%83%aa%e3%82%af%e3%82%b9fly%e3%81%ab%e6%a8%99%e6%ba%96%e3%81%a7%e4%bb%98%e3%81%84%e3%81%a6%e3%81%8f%e3%82%8bprometheus" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>Flyは組織ごとにマネージドのPrometheusを動かしてくれるので、自前のメトリクス基盤は持っていません。知りたいことがあるときにAPIを叩きます。マシンごとのメモリ、CPU、バーストクレジット(共有CPUでは <code>fly_instance_cpu_balance</code> が効いてきます)、アプリごとのレスポンス数や同時実行数などです。最初に知っておきたかったことが2つあります。<code>fly tokens create</code> で作ったトークンは <code>Authorization: FlyV1 &lt;token&gt;</code> として渡します。<code>Bearer</code> が使えるのは <code>flyctl auth token</code> の個人トークンだけで、読み取り専用トークンだと &ldquo;something went wrong resolving organization&rdquo; が返ってきます。そして保持期間はおよそ2週間です(Flyの説明では15日ほど)。</p>
<p>これが本領を発揮したのは9月でした。ログに &ldquo;Could not open a database connection&rdquo; が1日に何度も出ていて、どう見てもアプリのバグに見えました。マネージドPostgresのクラスタも同じPrometheusに入っていて、そのエラーが出た分にはいつも、プライマリのスクレイプ時間が80ミリ秒ほどから1〜10秒に跳ね上がっていました。レプリカは平常で、Postgresの起動時刻は動いていません。Postgresが再起動したのではなく、その下のホストが止まっていたのです。タイムスタンプを添えてFlyのサポートに送り、10月初めのメンテナンス再起動でプライマリが別のホストに移ってからは、毎日の停止はなくなりました。</p>

<h2 class="relative group">クラッシュレポート：自前のAPIに向けたSentryのSDK
    <div id="クラッシュレポート自前のapiに向けたsentryのsdk" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%82%af%e3%83%a9%e3%83%83%e3%82%b7%e3%83%a5%e3%83%ac%e3%83%9d%e3%83%bc%e3%83%88%e8%87%aa%e5%89%8d%e3%81%aeapi%e3%81%ab%e5%90%91%e3%81%91%e3%81%9fsentry%e3%81%aesdk" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>以前は、スマホでアプリが落ちても、私に見える場所のどこにも痕跡が残りませんでした。当然の答えはSentryで、私はその半分だけを取り入れました。アプリにはSentryのオープンソースSDKが入っていますが、DSNは私のDjango APIのエンドポイントを指しています。そのエンドポイントがSentryのenvelope形式を受け取り、クラッシュをまとめ、同じチャット用のハンドラーで通知します。トレーシング、セッション、リプレイはオフにしていて、受け取るのはエラーだけです。</p>
<p>sentry.ioに登録しなかったのは、1日に数件のレポートのために、ユーザーデータを預ける業者をひとつ、プライバシーポリシーの記述を1行、請求書を1枚増やしたくなかったからです。代わりに払っている代償はシンボリケーションで、これはまだ置き換えられていません。スタックはminifyされたJavaScriptか生のネイティブアドレスなので、イシューを見れば何がどのリリースと端末で落ちたのか、直前にユーザーが何をしていたのかはわかっても、ソースのどこなのかはわかりません。</p>

<h2 class="relative group">ダッシュボードはメッセージ1本
    <div id="ダッシュボードはメッセージ1本" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%80%e3%83%83%e3%82%b7%e3%83%a5%e3%83%9c%e3%83%bc%e3%83%89%e3%81%af%e3%83%a1%e3%83%83%e3%82%bb%e3%83%bc%e3%82%b81%e6%9c%ac" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>どちらのアプリにもダッシュボードは作っていません。昨年の記事にダッシュボードの判定基準を書きました。誰にも自発的に開かれないダッシュボードは存在価値を証明できていない、というものです。勝手に届くメッセージなら開く必要がないので、私にとっていちばんダッシュボードに近いのは、毎朝チームのチャットに届く1本の投稿です。</p>
<p>最初は直近24時間の本番エラーです。チャットチャンネルではなくログアーカイブから読みます。アラートは件数を絞っているので、何かが何回起きたのかを教えてくれないからです。数字、id、アドレスを伏せてからまとめるので、同じ失敗が100件あっても件数付きの1行になり、メールアドレスがチャンネルに流れることもありません。</p>
<p>続いて失敗したヘルスチェック、前日の利用状況を1週間前の同じ曜日と比べたもの(日曜日が月曜日と同じになることはありません)、直近1週間の検索流入、返信待ちのチャット、タスクボード、そして支出です。読み込めなかったセクションはそう書かれ、投稿自体は届きます。</p>
<p>アプリ解析の数字をAPIで読んでいると、少し疑ってかかるようになります。8月にはアゼルバイジャンからAndroidの初回起動が121件あり、その後アンインストールが119件続きました。その月のAndroidの合計は、これを除いて読んでいます。</p>
<p>リリースには専用の画面があります。OTAアップデートを自前のサーバーから配っていたころ、リリースを見る手段は &ldquo;is active&rdquo; のチェックボックスが付いた管理画面の一覧だけで、何台がアップデートを受け取ったのかまったくわかりませんでした。いまのサービスのダッシュボードは、端末が実際にどのリリースを動かしているか、インストールがどうだったか、そして壊れたバンドルが落ちてSDKが前のものに戻したときにはそのクラッシュロールバックまで見せてくれます。<a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-09-13-moving-to-codemagic-patch/" >ホスティング型のアップデートサービスへの移行</a>については別の記事にまとめています。</p>

<h2 class="relative group">やめたもの、信じなくなったもの
    <div id="やめたもの信じなくなったもの" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%82%84%e3%82%81%e3%81%9f%e3%82%82%e3%81%ae%e4%bf%a1%e3%81%98%e3%81%aa%e3%81%8f%e3%81%aa%e3%81%a3%e3%81%9f%e3%82%82%e3%81%ae" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>この中に有料のツールはひとつもありません。ほとんどはシグナルだと思っていたのに実はそうではなかったもので、あとひとつは置き場所を間違えていたジョブです。</p>

<h3 class="relative group">ユーザーエージェントでまとめるまでの、Cloudflareの504率
    <div id="ユーザーエージェントでまとめるまでのcloudflareの504率" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%a6%e3%83%bc%e3%82%b6%e3%83%bc%e3%82%a8%e3%83%bc%e3%82%b8%e3%82%a7%e3%83%b3%e3%83%88%e3%81%a7%e3%81%be%e3%81%a8%e3%82%81%e3%82%8b%e3%81%be%e3%81%a7%e3%81%aecloudflare%e3%81%ae504%e7%8e%87" aria-label="アンカー">#</a>
    </span>
    
</h3>
<p>9月、Cloudflareのダッシュボードには、1日のリクエストの22%が504で失敗しているように見える数字が出ていました。アプリが30秒ごとにポーリングするエンドポイントに集中していて、ヘルスチェックはすべて緑、アプリ自身のログではそのリクエストは速く返っていました。何日もかけました。マシンのコールドスタートに25〜33秒かかり、それが1日92回起きていることを突き止めて直し、<a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-09-09-scale-to-zero-504s/" >ゼロスケールの記事</a>にそれが原因だと書きました。</p>
<p>翌朝、同じ504をユーザーエージェントでまとめてみました。9月5日から9日までの7,344件は、すべてCloudflare自身のEarly Hintsのキャッシュ参照(ユーザーエージェントは <code>bastion early hints</code> と <code>nginx-ssl early hints</code>)でした。この参照はオリジンには一切届きません。その行の504はタイムアウトではなく、キャッシュミスを記録したものです。実際のリクエストのパスをなぞるので、いちばん忙しいエンドポイントに集まり、本当にユーザーが失敗しているように見えました。アプリ、ブラウザ、curl、検索エンジンのクローラーには1件もありません。オリジンが <code>Link</code> ヘッダーを送っていなかったので、Early Hintsは何の役にも立っておらず、いったんオフにしました。その後、<a href="https://jared.lynskey.co.nz/ja/posts/2026/cloudflare-504-early-hints/" >ちゃんと動くようにしました</a>。</p>
<p>コールドスタートの対応自体は無駄になりませんでした。デプロイもスリープからの復帰も速くなっています。ただ、直しているつもりだった障害は、一度もユーザーに届いていませんでした。</p>
<p>だからこそ、いちばん伝えたいルールはこれです。CDNのエラー率を信じる前に、ユーザーエージェントでまとめて、CDN自身の仕組みから出たものではないか確かめてください。Cloudflareの無料プランなら <code>httpRequestsAdaptiveGroups</code> へのGraphQLクエリで、1日ずつ見られます。次の騒ぎも同じクエリで片付きました。ポーリング用のエンドポイントのひとつが1日70〜260件から2,880件に跳ね上がったのですが、スクレイパーではありませんでした。テストのあとiOSシミュレーターでアプリを起動したままにしていた、私自身のMacでした。</p>

<h3 class="relative group">緑のヘルスチェック
    <div id="緑のヘルスチェック" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%b7%91%e3%81%ae%e3%83%98%e3%83%ab%e3%82%b9%e3%83%81%e3%82%a7%e3%83%83%e3%82%af" aria-label="アンカー">#</a>
    </span>
    
</h3>
<p>Flyは両アプリの <code>/api/health/</code> を30秒ごとに確認し、その結果でどのマシンにトラフィックを送るかを決めます。その仕事は得意です。ただ、ヘルスチェックはすでに起動しているマシンに対して動くので、マシンが起動する前に起きることは見えません。コールドスタート、プロキシの前の待ち行列、ついに届かないリクエストなどです。いまはルーティング以外のことは期待していません。</p>
<p>デプロイにはかわりにプローブのスクリプトを使います。デプロイのあいだずっとオリジンを叩き、ひとつでも失敗すれば終了コード1で終わります。このスクリプトが素の <code>flyctl deploy</code> で7.3秒の空白を捉え、先に予備のマシンを起こすデプロイスクリプトに切り替えてからは、2,514件中の失敗はゼロでした。</p>
<p>ヘルスチェックは、それ自体が原因の障害も2回起こしています。7月には、Djangoの <code>SECURE_SSL_REDIRECT</code> がFlyの平文HTTPのプローブに301で応え、すべてのマシンがチェックに失敗して、全員に503が返りました。8月には、ヘルス用ビューの <code>except Exception</code> を絞り込んだせいで &ldquo;connection already closed&rdquo; のエラーが500として漏れ、ビューのリトライがまさにそのケースのためにあったのに、Flyがマシンを外してしまいました。いまのチェックは、このプロセスがリクエストを処理できるかだけを問い、データベースが止まっても両アプリがルーティングから外れることはありません。</p>
<p>朝のサマリーも、数え方で同じ教訓を学びました。マーケットプレイスはアイドルのマシンをサスペンドするので、リクエストで起こされたマシンは起動後数百ミリ秒で最初のチェックに失敗し、次のチェックで通ります。それを数えていたせいで毎朝が障害のように読めたので、1分以内に再び通った失敗は、いまはマシンの復帰とデプロイとして別に表示しています。</p>

<h3 class="relative group">CIの定期実行ジョブ
    <div id="ciの定期実行ジョブ" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ci%e3%81%ae%e5%ae%9a%e6%9c%9f%e5%ae%9f%e8%a1%8c%e3%82%b8%e3%83%a7%e3%83%96" aria-label="アンカー">#</a>
    </span>
    
</h3>
<p>朝のサマリーは、cronで動くCIのワークフローとして始まり、1日で引っ越しました。アプリ解析と検索のデータを読むようになると、必要な鍵がアナリティクスのプロジェクトのサービスアカウントキーになったからです。そのプロジェクトで何でもできる鍵なので、CIのシークレットには置きたくありませんでした。いまは私のMacのスケジューラーが20分ごとに動かし、オークランド時間の朝8時を過ぎていて、その日の投稿がまだのときだけ投稿します。8時に眠っていたMacは、目を覚ましたときに投稿するわけです。ワークフローは、アプリ解析と検索のセクションを抜いた手動用の予備として残しています。</p>

<h2 class="relative group">もう一度始めるなら
    <div id="もう一度始めるなら" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%82%82%e3%81%86%e4%b8%80%e5%ba%a6%e5%a7%8b%e3%82%81%e3%82%8b%e3%81%aa%e3%82%89" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>最初の障害のあとではなく、最初のユーザーが来る前に3つを用意します。チームがすでに読んでいるチャットチャンネルへのエラー通知(件数制限付き)、SQLで問い合わせられるオブジェクトストレージのログアーカイブ、そしてプラットフォームがすでに集めているメトリクス。月に数ドルで済みます。クラッシュレポートは、アプリがスマホに載る週に入れます。そうしないと、スマホで起きたクラッシュは誰にも何も伝えないからです。朝のサマリーは、確認する場所が増えすぎて、結局どこも確認しなくなりそうになったころに足せば十分です。</p>
<p>トレーシングは、リクエストがまたぐ2つめのサービスができるまで、ホスティング型のAPMは、共有ダッシュボードとオンコールの当番表、そして他社の請求書を払う予算が必要なチームができるまで待ちます。昨年の記事で紹介したツールが元を取り始めるのはそこからです。それまでのいちばん役に立つ習慣はタダです。数字が怖く見えたら、何が壊れたかを決める前に、その数字を何が生み出したのかを確かめること。この記事に出てきた騒ぎのいくつかは、プロダクトではなくモニタリングそのものから生まれていました。</p>
]]></content:encoded>
      <media:content url="https://jared.lynskey.co.nz/en/posts/2026/2026-10-22-monitoring-tools-two-products/featured.jpg" medium="image" type="image/jpeg" />
    </item>
    <item>
      <title>開発者のためのモニタリング（監視）の作り方：メトリクス・ログ・トレースとCloudWatch vs Datadog</title>
      <link>https://jared.lynskey.co.nz/ja/posts/2025/2025-10-13-devops-monitoring/</link>
      <guid isPermaLink="true">https://jared.lynskey.co.nz/ja/posts/2025/2025-10-13-devops-monitoring/</guid>
      <pubDate>Sun, 12 Oct 2025 00:00:00 +0000</pubDate>
      <dc:creator>Jared Lynskey</dc:creator>
      <category>DevOps</category>
      <category>Monitoring</category>
      <category>Observability</category>
      <category>CloudWatch</category>
      <category>Datadog</category>
      <category>Developer Experience</category>
      <category>Site Reliability</category>
      <description>開発者が本当に使うモニタリング（監視）の作り方です。メトリクス・ログ・トレースのつなげ方、どこから調べればいいか分かるアラート、そして監視ツールとしてCloudWatchとDatadogのどちらを選ぶかをまとめました。</description>
      <content:encoded><![CDATA[<p>開発者のためのモニタリング（監視）がやるべきことは、突き詰めればひとつです。何かが壊れたらすぐに知らせ、何がどこで壊れたのかをその場で見せること。そのためには、メトリクス・ログ・トレースが互いにリンクされていて、アラートが調べ始める場所を指し示し、ダッシュボードが言われなくても開かれるものになっている必要があります。監視ツール選びはその次の話で、AWSなら小さなチームはCloudWatchで十分、規模が大きくなればDatadogが値段に見合ってきます。</p>
<p>「手元では動く」と「本番で動く」の間にはギャップがあって、モニタリングはそれを埋めるためにあるはずです。ところが大抵は埋まりません。開発者が障害時に手を伸ばすツールとしてではなく、運用チーム向けのツールとして作られてしまうからです。</p>
<p>最近フリーランスとしてDevOpsやインフラの仕事を始めたのですが、新しい現場に入ってまず見るもののひとつがモニタリングの構成です。READMEよりよほどチームの実態が分かります。そして失敗パターンはほぼ毎回同じです。ツールは揃っているのに、開発者の実際の仕事の流れとつながっていない。本番ログが見られれば5分で片付くバグに誰かが3時間溶かす。障害はアラートではなくサポートチケットで発覚する。あるいは逆に、1日200件のアラートのほとんどがノイズで、全員がすべてを無視するようになり、インシデントのたびに最初の30分を「直す」のではなく「何が壊れたのか」の特定に費やす、という具合です。</p>
<p>この記事は一般論です。2つのプロダクトで<a href="https://jared.lynskey.co.nz/ja/posts/2026/2026-10-22-monitoring-tools-two-products/" >私がいま実際に使っているツール</a>は、別の記事にまとめました。</p>

<h2 class="relative group">メトリクス・ログ・トレースはつながってこそ
    <div id="メトリクスログトレースはつながってこそ" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%a1%e3%83%88%e3%83%aa%e3%82%af%e3%82%b9%e3%83%ad%e3%82%b0%e3%83%88%e3%83%ac%e3%83%bc%e3%82%b9%e3%81%af%e3%81%a4%e3%81%aa%e3%81%8c%e3%81%a3%e3%81%a6%e3%81%93%e3%81%9d" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>メトリクスは「何かがおかしい」ことを教えてくれます（エラー率の急上昇、レイテンシの跳ね上がり）。ログは「何が起きたか」（スタックトレース、リクエストペイロード、エラーメッセージ）。トレースは「どこで起きたか」（どのサービス、どのエンドポイント、どのDBコール）。ここまでは常識です。重要なのは、この3つがリンクされているかどうか。アラートが鳴ったら、メトリクスから該当ログ、そしてトレースへとクリックだけでたどれるべきです。開発者が3つのツールを行き来してタイムスタンプを手作業で突き合わせているなら、個々のツールがどれだけ立派でも、その構成は失敗しています。</p>
<p>ダッシュボードにも同じテストが使えます。CPU、メモリ、ディスクI/Oはキャパシティプランニングには大事ですが、500エラーのデバッグには役立ちません。開発者が自発的に開くダッシュボードには、技術メトリクスの隣にビジネスメトリクス（エラー率の横に毎時サインアップ数）、タイムラインに重ねた直近のデプロイ、直近1時間のエラートップ5（ログへのリンク付き）、そして平均値ではなくレイテンシのパーセンタイル（p50、p95、p99）が並んでいます。誰にも自発的に開かれないダッシュボードは、存在価値を証明できていません。</p>
<p>アラートも同じ発想です。すべてのアラートは「何が壊れたのか」「どこから調べればいいのか」の2つに答えるべきです。</p>
<p>ダメなアラート：「web-server-3のCPUが高い」</p>
<p>良いアラート：「14:32以降、/api/paymentsのエラー率が5%超。最終デプロイ：14:15、@sarah。[ログを見る] [トレースを見る]」</p>
<p>後者に近づけるコツはいくつかあります。恣意的な閾値ではなくベースラインからの逸脱で発報する。オーナーシップでルーティングする（決済のエラーは組織全体ではなく決済チームへ）。関連エラーは50件の個別通知ではなく1つのSlackメッセージにまとめる。そしてフィードバックループは短く。「何かが壊れた」から「開発者が知る」までは1分以内が目安で、そのためには5分ごとのバッチではなくリアルタイムのログストリーミング、全ダッシュボードへのデプロイマーカー、サービス境界をまたいでも切れない分散トレーシングが必要です。</p>

<h2 class="relative group">使う人のために作る
    <div id="使う人のために作る" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bd%bf%e3%81%86%e4%ba%ba%e3%81%ae%e3%81%9f%e3%82%81%e3%81%ab%e4%bd%9c%e3%82%8b" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>運用チームがやりがちな最大の失敗は、自分たちのためにモニタリングを作ってしまうことです。対策は別に高度なものではありません。デバッグ中の開発者の隣に座って、どこで詰まるかを観察する。インシデント中にどんな質問が飛び交うかを聞く。「どのサービス？」「何が変わった？」「リクエストの中身は？」。プロダクトにとって本当に重要なメトリクスを突き止める。それはまずCPUではなく、チェックアウト完了率やアップロード成功率のようなものです。</p>
<p>次に摩擦を取り除きます。新しいサービスの計装に丸1日かかるなら、誰もやりません。使っているフレームワーク（Django、Express、Spring）を自動計装するライブラリ、コピペで使えるダッシュボードとアラートのテンプレート、チケットを切らずに自分でメトリクスを追加できるセルフサービスの仕組みを用意しましょう。そして全体をコードとして扱うこと。設定はバージョン管理に入れ、アラートルールは「鳴るべきときに鳴る」ことをテストし、マルチリージョンに向かうつもりなら早めに織り込んでおきます。</p>
<p>作ったあとは、同じ習慣で生かし続けます。計装はほかの本番コードと同じようにコードレビューを通し、独自メトリクスにはテストを付ける。ポストモーテムでは毎回「どんなモニタリングがあればもっと早く気づけたか」を問い、その答えは報告書ではなく、その週のうちにダッシュボードとアラートに反映する。そして年に数回は中身を見直して、誰も開かないものを消します。誰も動かないアラートは、次のアラートも無視するように人を慣らしてしまうからです。</p>

<h2 class="relative group">AWSの小規模チームならまずCloudWatch
    <div id="awsの小規模チームならまずcloudwatch" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#aws%e3%81%ae%e5%b0%8f%e8%a6%8f%e6%a8%a1%e3%83%81%e3%83%bc%e3%83%a0%e3%81%aa%e3%82%89%e3%81%be%e3%81%9acloudwatch" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>エンジニア50人以下でAWSに乗っているなら、CloudWatchが正しい出発点です。初日から高級なツールを買いたくなる気持ちは抑えたほうがいい。EC2、Lambda、RDS、ECSは自動でCloudWatchにレポートするので、計装コードを書かなくても可視性が手に入ります。小規模チームなら月額10〜50ドル程度で固定のプラットフォーム料金はなし。メトリクス、ログ、トレース（X-Ray経由）、アラームが一箇所に揃います。意味のあるアラートとダッシュボードなら、数週間ではなく午後のうちに作れます。</p>
<p>過小評価されがちなのがCloudWatch Logs Insightsです。Elasticsearchを立てなくてもログにクエリを投げられます：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">fields @timestamp, @message
</span></span><span class="line"><span class="cl">| filter @message like /ERROR/
</span></span><span class="line"><span class="cl">| stats count() by bin(5m)</span></span></code></pre></div></div>
<p>そのほかのポイント：</p>
<ul>
<li>複合アラームでノイズを減らす。エラー率が高く「かつ」レスポンスタイムが劣化しているときに発報する。条件ごとに個別ではなく。</li>
<li>本当の価値はカスタムメトリクスにあります。CloudWatch SDKでビジネスメトリクス（サインアップ、トランザクション、機能の利用状況）をインフラメトリクスと並べて送りましょう。</li>
<li>CloudWatch Syntheticsは、ユーザージャーニーをなぞるカナリアテストをスケジュール実行してくれます。チェックアウトが壊れていることに、ユーザーより先に気づけます。</li>
<li>X-Rayなら最小限のセットアップで分散トレーシングが手に入ります。大半のマイクロサービス構成にはこれで十分です。</li>
</ul>
<p>卒業のタイミングも分かりやすいです。マルチクラウドになったとき、本格的な異常検出が欲しくなったとき、ダッシュボードのカスタマイズがつらくなったとき、あるいはチームが50人を超えて本格的なコラボレーション機能が必要になったときです。</p>

<h2 class="relative group">大きめのチームならDatadog
    <div id="大きめのチームならdatadog" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%a7%e3%81%8d%e3%82%81%e3%81%ae%e3%83%81%e3%83%bc%e3%83%a0%e3%81%aa%e3%82%89datadog" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>Datadogは高いです。大きな組織なら年間2万〜10万ドル超は普通ですが、スケールすれば元は取れます。AWS、Azure、GCP、オンプレ、コンテナ、サーバーレス、データベース、フロントエンドを1つのビューで監視できます。Watchdogが手動の閾値設定なしで異常パターンを検出してくれるのも大きい。数千のサービスを人間が目視で見張ることはできませんから。さらにCloudWatchにはないコラボレーションの層が揃っています。チーム別ダッシュボード、RBAC、共有の調査ノートブック、PagerDuty/Opsgenie連携、複数条件アラート、閾値突破の予測、メンテナンスウィンドウ、そしてコードレベルのプロファイリングまで潜れるAPMと自動生成のサービスマップです。</p>
<p>導入はだいたいこの順番でやります。まず重要なサービスから計装し、初日からチームと環境でタグ付けを徹底する。命名規則、ダッシュボードのテンプレート、アラートの重要度レベル、SLOの定義は早い段階で合意しておく（標準の後付けは本当に苦行です）。CI/CDのデプロイマーカー、インシデント管理、Slackと連携させる。トレーニングの時間も確保すること。Datadogは強力ですが、直感だけでは使いこなせません。そして請求額には目を光らせる。ノイズの多いメトリクスをフィルタし、大量トラフィックのサービスではトレースをサンプリングし、実際に使っている機能を定期的に棚卸ししましょう。</p>
<p>契約前に見ておく価値があるのは、New Relic（似た構成で、大量トレーシングなら安いことも）、Dynatrace（AIOpsが強く金融系で人気）、Splunk（ログ分析は最強クラス、セキュリティ部門がすでに使っているならなおさら）、Grafana Cloud（すでにPrometheus/Lokiなら自然な選択）あたりです。</p>
<p>実際のところ、多くのチームはハイブリッドに落ち着きます。AWSネイティブなサービスは自動で安いCloudWatch、アプリケーション層はDatadog、そしてCloudWatchのメトリクスをDatadogに取り込んで統一ビューにする。地味ですが、ちゃんと機能します。</p>

<h2 class="relative group">CloudWatchとDatadogの比較
    <div id="cloudwatchとdatadogの比較" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#cloudwatch%e3%81%a8datadog%e3%81%ae%e6%af%94%e8%bc%83" aria-label="アンカー">#</a>
    </span>
    
</h2>
<table>
	<thead>
			<tr>
					<th></th>
					<th>CloudWatch</th>
					<th>Datadog</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>向いているチーム</td>
					<td>エンジニア50人以下、AWSだけのチーム</td>
					<td>サービスが多く、複数のクラウドを使う大きめの組織</td>
			</tr>
			<tr>
					<td>コストの形</td>
					<td>従量課金で固定のプラットフォーム料金なし。小規模チームなら月10〜50ドル程度</td>
					<td>大きな組織なら年間2万〜10万ドル超が普通。請求額から目を離せない</td>
			</tr>
			<tr>
					<td>導入の手間</td>
					<td>EC2・Lambda・RDS・ECSは自動でレポート。意味のあるアラートなら午後のうちに</td>
					<td>重要なサービスから計装、タグと命名規則を早めに合意、トレーニングの時間も必要</td>
			</tr>
			<tr>
					<td>マルチクラウド</td>
					<td>AWS中心。マルチクラウドになったら卒業のサイン</td>
					<td>AWS・Azure・GCP・オンプレ・コンテナ・サーバーレスを1つのビューで</td>
			</tr>
			<tr>
					<td>異常検出</td>
					<td>基本は自分で調整するアラーム。それ以上が欲しくなったらこれも卒業のサイン</td>
					<td>Watchdogが手動の閾値設定なしで異常を検出</td>
			</tr>
			<tr>
					<td>コラボレーション</td>
					<td>手薄。50人を超えると物足りなくなる</td>
					<td>チーム別ダッシュボード、RBAC、共有ノートブック、PagerDuty/Opsgenie連携</td>
			</tr>
			<tr>
					<td>トレーシング</td>
					<td>X-Ray、最小限のセットアップ</td>
					<td>コードレベルのプロファイリングまで潜れるAPM、自動生成のサービスマップ</td>
			</tr>
	</tbody>
</table>

<h2 class="relative group">ゼロから始めるなら：モニタリング構築の手順
    <div id="ゼロから始めるならモニタリング構築の手順" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%82%bc%e3%83%ad%e3%81%8b%e3%82%89%e5%a7%8b%e3%82%81%e3%82%8b%e3%81%aa%e3%82%89%e3%83%a2%e3%83%8b%e3%82%bf%e3%83%aa%e3%83%b3%e3%82%b0%e6%a7%8b%e7%af%89%e3%81%ae%e6%89%8b%e9%a0%86" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>私ならこの順番でやります。</p>
<ol>
<li>まず開発者に、インシデント中に何がつらいかを聞く。</li>
<li>重要なフローのSLOを定義する。ログイン、チェックアウト、検索にとって「動いている」とは何か。</li>
<li>そのクリティカルパスから計装する。</li>
<li>次に分散トレーシングを入れる（マイクロサービス構成ではデバッグ効率への投資対効果が一番高い）。</li>
<li>アラートはCPUではなくそのフローに設定し、それぞれ担当チームに届くようにする。</li>
<li>すべてのアラートにランブックを書き、午前3時の自分が何を確認すべきか分かるようにする。</li>
<li>四半期ごとのレビューをカレンダーに入れ、古いアラートを消し、ずれた閾値を直し、ダッシュボードが今のアーキテクチャを反映しているか確認する。</li>
</ol>
<p>私がこれまで何度もチームを救い出してきた落とし穴も挙げておきます。ツールの入れすぎ（連携する3つは連携しない6つに勝る）。ベースラインのないグラフ（500 rpsは平常なのか10倍のスパイクなのか？）。ユーザーに関係ないものの監視（ステートレスなコンテナのディスクI/Oなど）。そしてモニタリング自体の冗長性の欠如。インシデントの最中にアラート基盤が落ちたら、一番見えなくてはいけない瞬間に何も見えなくなります。</p>
<p>どれも最高級のツールは必要ありません。必要なのは、開発者が必要な情報を、実際に見る場所で、素早く手にできることです。</p>
]]></content:encoded>
      <media:content url="https://jared.lynskey.co.nz/en/posts/2025/2025-10-13-devops-monitoring/featured.jpeg" medium="image" type="image/jpeg" />
    </item>
  </channel>
</rss>
