2026年5月28日

保守サブスク向けSLAレポート自動化ガイド|手動集計をゼロにする実務手順

SLA 保守契約 自動化 制作会社 API

月次レポートに何時間かけていますか?

保守サブスクを10社以上抱えている制作会社では、月末になると決まって「レポート作業週間」が来ます。各サイトのダッシュボードを開いて数字をコピーし、Excelに貼り付けてグラフを整え、メールで送る——この繰り返しに月あたり数時間を費やしているケースは珍しくありません。

レポート自動化は、この工数をゼロに近づけながら、クライアントへの報告品質を上げられる施策です。Miterl のAPIを組み合わせれば、データ収集から PDF 生成・メール送信まで一本のスクリプトで回せます。本記事では、その実務手順をステップで解説します。

なぜ「手動レポート」は続かないのか

量が増えるほど破綻する

保守クライアントが5社のうちは手作業でも回ります。しかし20社を超えると、レポート作業だけで丸2日かかることも珍しくありません。さらに月末に障害が発生すると、復旧対応とレポート作業が重なりパンクします。

数字がずれるリスク

ダッシュボードを目視でコピーする手作業では、コピーミスや集計期間のズレが起きがちです。「先月送ったレポートの数字が違う」とクライアントに指摘されると、信頼の回復に余計なコストがかかります。

自動化で得られること

項目 手動 自動化後
1社あたりの集計時間 20〜40分 1分以内
コピーミスのリスク あり ゼロ
送付タイミング 担当者依存 毎月1日・自動送信
クライアント数が倍になると 作業量も倍 ほぼ変わらず

ステップ1:APIキーの準備と稼働率データの取得

まず Miterl の API キーをダッシュボードの「設定 → API キー」から発行します。次に、レポート対象のモニター ID を確認します。

# 全モニターの一覧を取得(name, id, uptime_30d を抜き出す)
curl -s "https://miterl.com/api/v1/monitors?per_page=100" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  | jq -r '.data[] | "\(.id)\t\(.name)\t\(.uptime_30d)%"'

出力例:

1    株式会社A - コーポレート    99.97%
2    株式会社A - 採用サイト      100.00%
3    株式会社B - ECサイト        99.83%

uptime_30d は直近30日間の稼働率です。カレンダー月(1日〜末日)の数値が必要な場合は、次のステップで障害履歴から算出します。

SLA目標値(99.9% / 99.95% など)に対して月間許容ダウンタイムを素早く確認するには「稼働率の計算方法と目安早見表」の早見表が便利です。クライアントへの提案書作成時にも役立ちます。

ステップ2:月次ダウンタイムを障害履歴から算出する

カレンダー月のSLAを正確に計算するには、その月に発生・解決した障害のダウンタイム合計を取得します。

# 例: 2026年4月のモニターID=1の解決済み障害を取得し、ダウンタイム合計(分)を算出
MONITOR_ID=1
YEAR=2026
MONTH=04

curl -s "https://miterl.com/api/v1/incidents?monitor_id=${MONITOR_ID}&status=resolved&per_page=100" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  | jq --arg ym "${YEAR}-${MONTH}" '
    [
      .data[]
      | select(.resolved_at | startswith($ym))
      | .duration_seconds
    ]
    | (add // 0) / 60
    | "ダウンタイム合計: \(round) 分"
  '

合計ダウンタイム(分)から稼働率を計算するには次の式を使います。

# 月間4月(30日)の稼働率を計算(ダウンタイム22分の場合)
python3 -c "
downtime_min = 22
total_min = 30 * 24 * 60
uptime = (1 - downtime_min / total_min) * 100
print(f'稼働率: {uptime:.4f}%')
"

ステップ3:レポートデータを一括収集するシェルスクリプト

クライアントのモニター ID リストを配列で持ち、ループで全データを収集します。

#!/bin/bash
# monthly_report_collect.sh
# 使い方: MONTH=2026-04 ./monthly_report_collect.sh

API_KEY="YOUR_API_KEY"
BASE_URL="https://miterl.com/api/v1"
MONTH="${MONTH:-$(date +%Y-%m)}"

# 監視対象モニターIDとクライアント名のマッピング
declare -A MONITORS=(
  [1]="株式会社A コーポレート"
  [2]="株式会社A 採用サイト"
  [3]="株式会社B ECサイト"
)

echo "# ${MONTH} 月次SLAレポート(自動集計)"
echo ""

for MONITOR_ID in "${!MONITORS[@]}"; do
  CLIENT_NAME="${MONITORS[$MONITOR_ID]}"

  # 稼働率(直近30日)
  UPTIME=$(curl -s "${BASE_URL}/monitors/${MONITOR_ID}" \
    -H "Authorization: Bearer ${API_KEY}" \
    | jq -r '.data.uptime_30d // "N/A"')

  # 解決済み障害件数とダウンタイム合計
  INCIDENT_DATA=$(curl -s "${BASE_URL}/incidents?monitor_id=${MONITOR_ID}&status=resolved&per_page=100" \
    -H "Authorization: Bearer ${API_KEY}" \
    | jq --arg ym "${MONTH}" '
      [.data[] | select(.resolved_at | startswith($ym))]
      | {count: length, total_min: (map(.duration_seconds) | (add // 0) / 60 | round)}
    ')

  INCIDENT_COUNT=$(echo "$INCIDENT_DATA" | jq -r '.count')
  DOWNTIME_MIN=$(echo "$INCIDENT_DATA" | jq -r '.total_min')

  echo "## ${CLIENT_NAME}"
  echo "- 稼働率(直近30日): ${UPTIME}%"
  echo "- 障害件数: ${INCIDENT_COUNT} 件"
  echo "- ダウンタイム合計: ${DOWNTIME_MIN} 分"
  echo ""
done

このスクリプトを cron で毎月1日の朝に実行し、結果を Markdown ファイルに保存します。

# crontab に追加(毎月1日 09:00 に実行)
0 9 1 * * /path/to/monthly_report_collect.sh > /reports/$(date +\%Y-\%m).md

ステップ4:レポートをメールで自動送信する

集計した Markdown を HTML に変換し、SendGrid・Mailgun などのメール API 経由で送信します。Python で簡潔に書けます。

#!/usr/bin/env python3
# send_sla_report.py

import subprocess
import datetime
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# 対象月のレポートファイルを読み込む
month = datetime.date.today().strftime("%Y-%m")
report_path = f"/reports/{month}.md"

with open(report_path) as f:
    report_md = f.read()

# クライアントごとの送付先設定
CLIENTS = [
    {"name": "株式会社A", "email": "[email protected]"},
    {"name": "株式会社B", "email": "[email protected]"},
]

SMTP_HOST = "smtp.example.com"
SMTP_USER = "[email protected]"
SMTP_PASS = "YOUR_SMTP_PASSWORD"

def send_report(client_name: str, to_email: str, body: str) -> None:
    msg = MIMEMultipart("alternative")
    msg["Subject"] = f"【{month}】サイト監視 月次レポート|{client_name}"
    msg["From"] = SMTP_USER
    msg["To"] = to_email
    msg.attach(MIMEText(body, "plain", "utf-8"))

    with smtplib.SMTP(SMTP_HOST, 587) as server:
        server.starttls()
        server.login(SMTP_USER, SMTP_PASS)
        server.sendmail(SMTP_USER, to_email, msg.as_string())
        print(f"Sent to {to_email}")

for client in CLIENTS:
    # クライアント名に関係する行だけ抽出してもよい(ここでは全文を送信)
    send_report(client["name"], client["email"], report_md)

SendGrid や Postmark を使う場合は、SMTP の代わりにそれぞれの HTTP API(requests ライブラリ)で送信できます。

ステップ5:ステータスページへのリンクをレポートに含める

毎月の数字に加え、クライアントが常時参照できるステータスページのURLをレポートに添えておくと、問い合わせがさらに減ります。

# ステータスページの現在の状態を取得してレポートに付記する
SLUG="client-a-status"

curl -s "https://miterl.com/api/v1/status-pages/${SLUG}" \
  | jq -r '"全体ステータス: \(.data.overall_status) | URL: https://status.client-a.example.com"'

Standard プラン以上では独自ドメインでステータスページを公開できます。status.client-a.example.com のようなURLをレポートに記載しておくと、クライアントは障害発生時も自分で確認でき、問い合わせの電話が来る前に状況を把握してもらえます。

ステップ6:計画メンテナンス期間をSLA計算から除外する

デプロイやサーバーメンテナンスの時間をSLAダウンタイムに含めてしまうと、稼働率が不当に下がります。Miterl の Webhook API でメンテナンス期間を設定すると、その間の障害はレポートに含まれません。

# デプロイ前にメンテナンス期間を開始(1時間後に自動終了)
curl -X POST https://miterl.com/api/v1/webhooks/maintenance/${MITERL_TOKEN}/start \
  -H "Content-Type: application/json" \
  -d '{"duration_hours": 1, "name": "月次メンテナンス — 2026-05"}'

デプロイスクリプトの冒頭にこの1行を追加するだけで、メンテナンス除外が自動化されます。

レポート自動化のメリットまとめ

自動化が完成すると、月末の作業は以下に変わります。

  1. cron が自動でデータを収集し Markdown を生成
  2. Python スクリプトがクライアントにメール送信
  3. 担当者は送信済みメールを確認するだけ

月あたり数時間だった工数が数分になり、その分を障害対応品質の向上やクライアントへの提案に充てられます。クライアントからは「報告が届かなかった」というトラブルも消えます。

まとめ

月次SLAレポートの自動化は、保守サブスクの品質向上と工数削減を同時に実現できる施策です。Miterl の API で稼働率・障害履歴を取得し、シェルスクリプトと cron を組み合わせれば、クライアント数が増えても作業量はほぼ変わりません。

詳しい API の使い方はドキュメントを参照してください。SLAの基本的な考え方と手動レポートのテンプレートについては「稼働率レポートの作り方」、ステータスページの活用法は「クライアント向けステータスページの活用法」、初期設定の全手順は「Web制作会社向け Miterl 初期設定ガイド」で解説しています。まずは無料プランで試すか、ユースケース一覧で具体的な活用シーンを確認してみてください。