<?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/"><channel><title>Uptime on Tarragon</title><link>https://tarrragon.github.io/blog/tags/uptime/</link><description>Recent content in Uptime on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 26 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/uptime/index.xml" rel="self" type="application/rss+xml"/><item><title>無 SSH 環境的監控與告警</title><link>https://tarrragon.github.io/blog/infra/takeover/legacy-external-monitoring/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/takeover/legacy-external-monitoring/</guid><description>&lt;p>無 SSH 的環境通常不允許安裝監控 agent（Datadog agent、New Relic APM daemon 都需要 daemon 常駐或 root 權限），伺服器的內部指標（CPU、記憶體、磁碟）只能從主機商的控制面板看到靜態數值，沒有告警機制。這種環境的監控策略是從外部觀測——用 HTTP check 確認服務存活、用不需要 agent 的錯誤追蹤服務捕捉例外、用定期量測建立效能基線。每一層都不依賴 server 端安裝任何東西。&lt;/p>
&lt;h2 id="可用性監控外部-http-check">可用性監控（外部 HTTP check）&lt;/h2>
&lt;p>外部 HTTP check 的運作方式是從第三方伺服器定期對目標 URL 發 HTTP 請求，驗證回應狀態碼、回應時間、以及頁面內容是否包含預期的文字。服務掛了或回應異常時觸發告警。&lt;/p>
&lt;h3 id="工具選型">工具選型&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>工具&lt;/th>
 &lt;th>免費方案&lt;/th>
 &lt;th>檢查間隔&lt;/th>
 &lt;th>特色&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>UptimeRobot&lt;/td>
 &lt;td>50 個 monitor&lt;/td>
 &lt;td>5 分鐘&lt;/td>
 &lt;td>設定簡單、API 可整合&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Better Stack&lt;/td>
 &lt;td>10 個 monitor&lt;/td>
 &lt;td>3 分鐘&lt;/td>
 &lt;td>含 incident 管理與 status page&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Pingdom&lt;/td>
 &lt;td>1 個 monitor（試用）&lt;/td>
 &lt;td>1 分鐘&lt;/td>
 &lt;td>Synthetic monitoring、付費功能完整&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>UptimeRobot 的免費方案對多數無 SSH 環境的站台足夠——50 個 monitor 可以覆蓋一個站台的主要入口。&lt;/p>
&lt;h3 id="該監控哪些-url">該監控哪些 URL&lt;/h3>
&lt;p>選監控目標的判準是「這個 URL 掛了代表哪一層出問題」：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>URL&lt;/th>
 &lt;th>驗證的層次&lt;/th>
 &lt;th>掛了代表什麼&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>首頁&lt;/td>
 &lt;td>web server 存活&lt;/td>
 &lt;td>Apache/Nginx 或 PHP 本身掛了&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>登入頁&lt;/td>
 &lt;td>應用框架正常運作&lt;/td>
 &lt;td>PHP session 或框架初始化失敗&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>一個資料庫相依的頁面&lt;/td>
 &lt;td>DB 連線存活&lt;/td>
 &lt;td>MySQL 掛了或連線數滿了&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>金流 callback URL&lt;/td>
 &lt;td>第三方服務可達&lt;/td>
 &lt;td>付款回調會失敗、訂單狀態卡住&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>每個 monitor 設兩層閾值：回應時間 &amp;gt;3 秒為警告（效能劣化的早期訊號）、&amp;gt;10 秒或非 200 狀態碼為嚴重（服務已不可用）。&lt;/p>
&lt;h3 id="告警通道">告警通道&lt;/h3>
&lt;p>免費方案通常支援 email 與 webhook（可串 Slack）。付費方案加 SMS 和電話。接手初期用 email + Slack 即可，等確認告警不會誤報後再決定要不要升級到 SMS。頻繁誤報會讓團隊學會忽略通知——閾值要設在「真的有問題才響」的水位。&lt;/p>
&lt;h2 id="錯誤追蹤不需要-server-agent">錯誤追蹤（不需要 server agent）&lt;/h2>
&lt;p>PHP 的錯誤追蹤在無 SSH 環境有兩條路徑：server 端用 PHP 內建的 error_log、client 端用不需要安裝的 SaaS 服務。&lt;/p>
&lt;h3 id="php-error_logserver-端不需-ssh">PHP error_log（server 端、不需 SSH）&lt;/h3>
&lt;p>PHP 可以把錯誤寫進檔案，設定方式是在 &lt;code>.htaccess&lt;/code> 或 &lt;code>php.ini&lt;/code>（如果主機允許）加入：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-apache" data-lang="apache">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c"># .htaccess — 啟用錯誤記錄、關閉畫面顯示&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="nb">php_flag&lt;/span> display_errors &lt;span class="k">off&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nb">php_flag&lt;/span> log_errors &lt;span class="k">on&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="nb">php_value&lt;/span> error_log &lt;span class="sx">/home/user/logs/php_errors.log&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>error_log&lt;/code> 的路徑要指向 web root 之外的目錄，避免錯誤訊息被外部存取。設定後透過 FTP 定期下載這個檔案、用 grep 篩選嚴重等級：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 篩選 Fatal 和 Warning（過濾掉 Notice / Deprecated）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">grep -E &lt;span class="s2">&amp;#34;Fatal|Warning&amp;#34;&lt;/span> php_errors.log &lt;span class="p">|&lt;/span> tail -50&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="sentryphp--javascript不需-server-agent">Sentry（PHP + JavaScript、不需 server agent）&lt;/h3>
&lt;p>Sentry 的 PHP SDK 不需要系統層 agent，只需要在應用程式碼裡初始化：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">composer require sentry/sentry&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-php" data-lang="php">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1">// 在應用程式進入點（如 index.php 最前面）加入
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">\Sentry\init&lt;/span>&lt;span class="p">([&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> &lt;span class="s1">&amp;#39;dsn&amp;#39;&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="s1">&amp;#39;https://examplekey@o0.ingest.sentry.io/0&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> &lt;span class="s1">&amp;#39;traces_sample_rate&amp;#39;&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="mf">0.1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="p">]);&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這段程式碼會在 PHP 拋出未捕捉的例外或觸發 error 時，把錯誤資訊（stack trace、request context、使用者資訊）透過 HTTP 送到 Sentry 的 SaaS 平台。免費方案每月 5,000 個事件，對流量不大的流量不大的站台通常足夠。&lt;/p></description><content:encoded><![CDATA[<p>無 SSH 的環境通常不允許安裝監控 agent（Datadog agent、New Relic APM daemon 都需要 daemon 常駐或 root 權限），伺服器的內部指標（CPU、記憶體、磁碟）只能從主機商的控制面板看到靜態數值，沒有告警機制。這種環境的監控策略是從外部觀測——用 HTTP check 確認服務存活、用不需要 agent 的錯誤追蹤服務捕捉例外、用定期量測建立效能基線。每一層都不依賴 server 端安裝任何東西。</p>
<h2 id="可用性監控外部-http-check">可用性監控（外部 HTTP check）</h2>
<p>外部 HTTP check 的運作方式是從第三方伺服器定期對目標 URL 發 HTTP 請求，驗證回應狀態碼、回應時間、以及頁面內容是否包含預期的文字。服務掛了或回應異常時觸發告警。</p>
<h3 id="工具選型">工具選型</h3>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>免費方案</th>
          <th>檢查間隔</th>
          <th>特色</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>UptimeRobot</td>
          <td>50 個 monitor</td>
          <td>5 分鐘</td>
          <td>設定簡單、API 可整合</td>
      </tr>
      <tr>
          <td>Better Stack</td>
          <td>10 個 monitor</td>
          <td>3 分鐘</td>
          <td>含 incident 管理與 status page</td>
      </tr>
      <tr>
          <td>Pingdom</td>
          <td>1 個 monitor（試用）</td>
          <td>1 分鐘</td>
          <td>Synthetic monitoring、付費功能完整</td>
      </tr>
  </tbody>
</table>
<p>UptimeRobot 的免費方案對多數無 SSH 環境的站台足夠——50 個 monitor 可以覆蓋一個站台的主要入口。</p>
<h3 id="該監控哪些-url">該監控哪些 URL</h3>
<p>選監控目標的判準是「這個 URL 掛了代表哪一層出問題」：</p>
<table>
  <thead>
      <tr>
          <th>URL</th>
          <th>驗證的層次</th>
          <th>掛了代表什麼</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>首頁</td>
          <td>web server 存活</td>
          <td>Apache/Nginx 或 PHP 本身掛了</td>
      </tr>
      <tr>
          <td>登入頁</td>
          <td>應用框架正常運作</td>
          <td>PHP session 或框架初始化失敗</td>
      </tr>
      <tr>
          <td>一個資料庫相依的頁面</td>
          <td>DB 連線存活</td>
          <td>MySQL 掛了或連線數滿了</td>
      </tr>
      <tr>
          <td>金流 callback URL</td>
          <td>第三方服務可達</td>
          <td>付款回調會失敗、訂單狀態卡住</td>
      </tr>
  </tbody>
</table>
<p>每個 monitor 設兩層閾值：回應時間 &gt;3 秒為警告（效能劣化的早期訊號）、&gt;10 秒或非 200 狀態碼為嚴重（服務已不可用）。</p>
<h3 id="告警通道">告警通道</h3>
<p>免費方案通常支援 email 與 webhook（可串 Slack）。付費方案加 SMS 和電話。接手初期用 email + Slack 即可，等確認告警不會誤報後再決定要不要升級到 SMS。頻繁誤報會讓團隊學會忽略通知——閾值要設在「真的有問題才響」的水位。</p>
<h2 id="錯誤追蹤不需要-server-agent">錯誤追蹤（不需要 server agent）</h2>
<p>PHP 的錯誤追蹤在無 SSH 環境有兩條路徑：server 端用 PHP 內建的 error_log、client 端用不需要安裝的 SaaS 服務。</p>
<h3 id="php-error_logserver-端不需-ssh">PHP error_log（server 端、不需 SSH）</h3>
<p>PHP 可以把錯誤寫進檔案，設定方式是在 <code>.htaccess</code> 或 <code>php.ini</code>（如果主機允許）加入：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-apache" data-lang="apache"><span class="line"><span class="ln">1</span><span class="cl"><span class="c"># .htaccess — 啟用錯誤記錄、關閉畫面顯示</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">php_flag</span> display_errors <span class="k">off</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">php_flag</span> log_errors <span class="k">on</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="nb">php_value</span> error_log <span class="sx">/home/user/logs/php_errors.log</span></span></span></code></pre></div><p><code>error_log</code> 的路徑要指向 web root 之外的目錄，避免錯誤訊息被外部存取。設定後透過 FTP 定期下載這個檔案、用 grep 篩選嚴重等級：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 篩選 Fatal 和 Warning（過濾掉 Notice / Deprecated）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">grep -E <span class="s2">&#34;Fatal|Warning&#34;</span> php_errors.log <span class="p">|</span> tail -50</span></span></code></pre></div><h3 id="sentryphp--javascript不需-server-agent">Sentry（PHP + JavaScript、不需 server agent）</h3>
<p>Sentry 的 PHP SDK 不需要系統層 agent，只需要在應用程式碼裡初始化：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">composer require sentry/sentry</span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 在應用程式進入點（如 index.php 最前面）加入
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nx">\Sentry\init</span><span class="p">([</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="s1">&#39;dsn&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;https://examplekey@o0.ingest.sentry.io/0&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="s1">&#39;traces_sample_rate&#39;</span> <span class="o">=&gt;</span> <span class="mf">0.1</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">]);</span></span></span></code></pre></div><p>這段程式碼會在 PHP 拋出未捕捉的例外或觸發 error 時，把錯誤資訊（stack trace、request context、使用者資訊）透過 HTTP 送到 Sentry 的 SaaS 平台。免費方案每月 5,000 個事件，對流量不大的流量不大的站台通常足夠。</p>
<p>前端的 JavaScript 錯誤追蹤更簡單——在 HTML 的 <code>&lt;head&gt;</code> 加一行 Sentry 的 CDN script，不需要修改 server 設定：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="ln">1</span><span class="cl"><span class="p">&lt;</span><span class="nt">script</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://browser.sentry-cdn.com/8.x/bundle.tracing.min.js&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="na">crossorigin</span><span class="o">=</span><span class="s">&#34;anonymous&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="nx">Sentry</span><span class="p">.</span><span class="nx">init</span><span class="p">({</span> <span class="nx">dsn</span><span class="o">:</span> <span class="s2">&#34;https://examplekey@o0.ingest.sentry.io/0&#34;</span> <span class="p">});</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div><p>JavaScript SDK 捕捉的是瀏覽器端的錯誤——DOM 操作失敗、AJAX 請求異常、未處理的 Promise rejection。跟 PHP 端的 SDK 各抓不同層的問題。</p>
<h3 id="error_log-vs-sentry-的分工">error_log vs Sentry 的分工</h3>
<p>error_log 是 server 端的文字紀錄，需要手動下載和篩選；Sentry 有搜尋、聚合、告警和 stack trace 視覺化。兩者互補：error_log 保留完整紀錄作為備份、Sentry 提供可操作的告警和分析介面。error_log 在 PHP 嚴重到 Sentry SDK 自己也掛掉的情況下仍然有紀錄。</p>
<h2 id="效能基線">效能基線</h2>
<p>效能基線的責任是回答「正常狀態下回應時間是多少」，讓異常浮現時有比對的參考。沒有基線時，回應時間從 200ms 劣化到 2 秒、但因為「好像一直都這麼慢」而沒人察覺。</p>
<h3 id="量測方式">量測方式</h3>
<p>最簡單的量測是從本機或 CI 環境定期 curl：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 量測回應時間（秒），只看 time_total</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">curl -o /dev/null -s -w <span class="s2">&#34;%{time_total}\n&#34;</span> https://example.com</span></span></code></pre></div><p>把這段做成 GitHub Actions 的 scheduled workflow，每小時跑一次、把結果追加到 repo 的 CSV 檔案，就有了一條回應時間的趨勢線：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="w">  </span><span class="nt">schedule</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;0 * * * *&#39;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="nt">perf-check</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="sd">          TIME=$(curl -o /dev/null -s -w &#34;%{time_total}&#34; https://example.com)
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="sd">          echo &#34;$(date -u +%Y-%m-%dT%H:%M:%SZ),$TIME&#34; &gt;&gt; perf-log.csv</span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">git add perf-log.csv &amp;&amp; git commit -m &#34;perf check&#34; &amp;&amp; git push</span></span></span></code></pre></div><p>這條趨勢線本身就是監控：回應時間連續幾個小時上升，代表某個東西在劣化（DB 查詢變慢、磁碟快滿、PHP process 卡住）。</p>
<h3 id="頁面效能">頁面效能</h3>
<p>Google PageSpeed Insights（免費、不需安裝）分析前端載入效能，包含 LCP、CLS、FID 等 Core Web Vitals。對 legacy PHP 站台有用的是它會指出渲染阻塞的 CSS/JS、未壓縮的圖片、缺少快取 header 這類不需要動後端就能改善的問題。</p>
<h3 id="資料庫效能需改-code">資料庫效能（需改 code）</h3>
<p>如果能修改 PHP 程式碼，在資料庫查詢前後加計時、超過閾值就寫 error_log：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="ln">1</span><span class="cl"><span class="nv">$start</span> <span class="o">=</span> <span class="nx">microtime</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nv">$result</span> <span class="o">=</span> <span class="nv">$pdo</span><span class="o">-&gt;</span><span class="na">query</span><span class="p">(</span><span class="nv">$sql</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nv">$elapsed</span> <span class="o">=</span> <span class="nx">microtime</span><span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="o">-</span> <span class="nv">$start</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nv">$elapsed</span> <span class="o">&gt;</span> <span class="mf">1.0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nx">error_log</span><span class="p">(</span><span class="nx">sprintf</span><span class="p">(</span><span class="s2">&#34;Slow query (%.2fs): %s&#34;</span><span class="p">,</span> <span class="nv">$elapsed</span><span class="p">,</span> <span class="nx">substr</span><span class="p">(</span><span class="nv">$sql</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">)));</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>累積一段時間後，從 error_log 裡 grep <code>Slow query</code> 就能看出哪些查詢是效能瓶頸。這不是完整的 APM，但在沒有 agent 的環境裡是最接近 slow query log 的替代方案。</p>
<h2 id="帳單與流量異常偵測">帳單與流量異常偵測</h2>
<p>這類主機通常按流量或磁碟空間計費，異常流量（bot 掃描、DDoS、爬蟲）會讓帳單飆高或觸發主機商的流量限制。</p>
<h3 id="流量監控">流量監控</h3>
<p>主機控制面板（cPanel 的 AWStats 或 Webalizer）提供基本的流量分析——top referrer、top page、bot 流量佔比。每月檢查一次，重點看：</p>
<ul>
<li>bot 流量佔比是否異常高（&gt;50% 通常代表有爬蟲）</li>
<li>單一 IP 的請求量是否異常集中</li>
<li>帶寬使用量的趨勢（月增超過 20% 且沒有對應的業務成長要查原因）</li>
</ul>
<h3 id="客戶端分析不需-server-安裝">客戶端分析（不需 server 安裝）</h3>
<p>Google Analytics 或 Plausible（隱私友善替代品）只需要在頁面加一段 JavaScript。它們追蹤的是真實使用者的瀏覽行為（page view、session、referrer），跟 server 端的 access log 互補：server log 看所有請求（含 bot），GA/Plausible 只看真實瀏覽器。</p>
<h3 id="cloudflare-免費方案">Cloudflare 免費方案</h3>
<p>如果 DNS 可以切換，把 domain 接上 Cloudflare（免費方案）提供三個能力而不需要動 server：</p>
<ul>
<li><strong>流量分析</strong>：比 AWStats 更即時、有地理分佈和 bot 過濾</li>
<li><strong>DDoS 保護</strong>：基本的 Layer 3/4 防護免費</li>
<li><strong>CDN 快取</strong>：靜態資源（CSS/JS/圖片）由 Cloudflare 快取、減輕 origin 負擔</li>
</ul>
<p>設定只需要把 domain 的 nameserver 改成 Cloudflare 提供的 NS、原始 DNS record 在 Cloudflare 重建。對無 SSH 環境的站台來說這是投資報酬率最高的單一改善動作——不動 server、不改 code、但同時拿到流量可見性和基本防護。</p>
<h2 id="整合成最低成本監控方案">整合成最低成本監控方案</h2>
<p>按投入程度分三層，每一層都包含上一層：</p>
<table>
  <thead>
      <tr>
          <th>層級</th>
          <th>組成</th>
          <th>月費</th>
          <th>覆蓋</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Tier 1（零成本）</td>
          <td>UptimeRobot free + Sentry free + Google Analytics</td>
          <td>$0</td>
          <td>可用性 + 錯誤追蹤 + 流量</td>
      </tr>
      <tr>
          <td>Tier 2（最低付費）</td>
          <td>+Better Stack ($19/mo) + Cloudflare free</td>
          <td>~$19</td>
          <td>+incident 管理 + 流量分析 + CDN</td>
      </tr>
      <tr>
          <td>Tier 3（升級路徑）</td>
          <td>遷移到 VPS → 安裝 APM agent → 對齊模組六的 IaC 監控</td>
          <td>依 VPS</td>
          <td>完整 server 端可觀測性</td>
      </tr>
  </tbody>
</table>
<p>Tier 1 在接手當天就能建好（30 分鐘設定 UptimeRobot + Sentry + GA），零成本提供基本的「服務掛了會知道、程式碼出錯會收到、流量異常看得到」的覆蓋。Tier 2 適合站台有營收或合約 SLA 要求時。Tier 3 是離開無 SSH 環境後的正規化路徑，監控從外部觀測升級為 server 端全面可觀測性，見<a href="/blog/infra/06-observability-logging/" data-link-title="模組六：可觀測性與 log 一併寫進 code" data-link-desc="log group、metric、alarm 跟基礎設施同生命週期管理，出事時追得到查得到">模組六：可觀測性與 log</a>。</p>
<h2 id="跨分類引用">跨分類引用</h2>
<ul>
<li>→ <a href="/blog/infra/takeover/legacy-ftp-no-ssh/" data-link-title="無 SSH 的 FTP / 面板管理環境接管" data-link-desc="接手一個只有 FTP 和 phpMyAdmin（或 cPanel / Plesk）存取的 PHP 專案：沒有 SSH、沒有 CLI 時，怎麼盤點現況、建立本地開發環境、制定部署與資料庫變更紀律，以及找到升級路徑的切入點">無 SSH 的 FTP / 面板管理環境接管</a>：本篇的母篇，監控建立在盤點與本地環境之後</li>
<li>→ <a href="/blog/infra/takeover/legacy-code-versioning-deployment/" data-link-title="程式碼版控與 FTP 部署紀律" data-link-desc="無 SSH 環境的 PHP 專案的程式碼怎麼從 FTP 拉回來建 Git repo、設定檔怎麼分離、FTP 部署怎麼建立可追蹤的流程、以及怎麼用 CI 取代手動上傳">程式碼版控與 FTP 部署紀律</a>：部署後的驗證用監控確認服務正常</li>
<li>→ <a href="/blog/infra/takeover/legacy-php-security-audit/" data-link-title="Legacy PHP 的安全盤點" data-link-desc="接手 legacy PHP 專案後的系統性安全審查：credential 掃描、PHP 版本風險、常見漏洞模式的 grep 偵測、.htaccess 防線、檔案權限、外部依賴與掃描工具">Legacy PHP 的安全盤點</a>：錯誤追蹤可能暴露安全問題（未捕捉的 SQL error、路徑洩漏）</li>
<li>→ <a href="/blog/infra/06-observability-logging/" data-link-title="模組六：可觀測性與 log 一併寫進 code" data-link-desc="log group、metric、alarm 跟基礎設施同生命週期管理，出事時追得到查得到">模組六：可觀測性與 log</a>：Tier 3 升級路徑的目標——有 server 存取後的 IaC 監控</li>
<li>→ <a href="/blog/monitoring/" data-link-title="監控實務指南" data-link-desc="整理非伺服器端運行時的監控體系 — 行為蒐集、錯誤回報、效能指標、生命週期追蹤，從自架方案到商業方案的完整知識路線">Monitoring 監控體系</a>：客戶端行為訊號（SDK / Collector）的完整討論</li>
</ul>
]]></content:encoded></item></channel></rss>