Skip to content

Add Grafana monitoring dashboard for THQ tracking system#26

Open
TinyKitten wants to merge 6 commits intomainfrom
claude/evaluate-grafana-integration-7ZRQz
Open

Add Grafana monitoring dashboard for THQ tracking system#26
TinyKitten wants to merge 6 commits intomainfrom
claude/evaluate-grafana-integration-7ZRQz

Conversation

@TinyKitten
Copy link
Copy Markdown
Member

@TinyKitten TinyKitten commented Mar 5, 2026

Summary

This PR adds comprehensive Grafana monitoring and visualization capabilities to the THQ tracking system. It includes a new Grafana service in the Docker Compose setup, a pre-configured PostgreSQL datasource, and a detailed overview dashboard displaying location logs, log events, device metrics, and system statistics.

Key Changes

  • Docker Compose Integration: Added Grafana 11.6.0 service with PostgreSQL database dependency, environment configuration for admin credentials, and persistent volume mounting for dashboards and provisioning files
  • Datasource Configuration: Created PostgreSQL datasource provisioning file (postgres.yml) that automatically connects Grafana to the THQ database with proper SSL and version settings
  • Dashboard Provisioning: Added dashboard provider configuration (default.yml) to enable automatic dashboard loading from the filesystem
  • THQ Overview Dashboard: Created comprehensive thq-overview.json dashboard with 12 panels including:
    • Time series visualizations for location logs, log events, accuracy, battery level, and speed
    • Stat panels showing total counts and active devices in the last 24 hours
    • Bar gauge for average accuracy by device
    • Pie chart for log event distribution by level
    • Data tables for recent location logs and log events with detailed metrics
    • All panels configured with PostgreSQL queries using Grafana time range variables

Implementation Details

  • Dashboard uses 24-hour default time range with 30-second refresh interval
  • All time-series queries aggregate data by hour for better performance
  • Accuracy and battery metrics include proper unit formatting (meters and percent)
  • Recent data tables limited to 100 rows for performance
  • Timezone set to Asia/Tokyo to match deployment region
  • Grafana admin password configurable via environment variable with secure default

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce

Summary by CodeRabbit

  • 新機能

    • Grafana を追加し、Web UI(ポート3000)で統合監視ダッシュボードを提供(永続化された grafana-data ボリューム、プロビジョニングとダッシュボードのマウント含む)。
    • 「THQ Overview」ダッシュボードを追加(24時間表示・30秒自動更新・Asia/Tokyo タイムゾーン)。
    • PostgreSQL データソースをプロビジョニングし、管理者パスワード環境変数を追加。
  • 修正/改善

    • 検索/集計用のデータベースインデックスを追加してクエリ性能を改善。

Introduces Grafana as a new Docker Compose service to visualize data
already stored in PostgreSQL. Includes provisioned datasource config
and a pre-built dashboard with panels for location logs, log events,
accuracy, speed, battery level, and device activity.

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5bee2539-5656-46d4-9b48-8f01f16b86d4

📥 Commits

Reviewing files that changed from the base of the PR and between a64a585 and 240848f.

📒 Files selected for processing (2)
  • grafana/dashboards/thq-overview.json
  • src/storage.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • grafana/dashboards/thq-overview.json

📝 Walkthrough

Walkthrough

docker-compose に Grafana サービスと永続ボリューム、Grafana のプロビジョニング(ダッシュボード・データソース)および THQ 概要ダッシュボード定義を追加し、Grafana を db に依存させてポート3000で公開。さらにストレージ準備に2つのインデックスを追加し、.env.exampleGF_ADMIN_PASSWORD を追加しています。

Changes

Cohort / File(s) Summary
Docker Compose 設定
docker-compose.yml
Grafana サービスを追加(grafana/grafana:11.6.0)。depends_ondb のヘルス依存、管理者認証設定、匿名無効、grafana-data 永続ボリューム、プロビジョニングとダッシュボードのマウント、ポート3000、再起動ポリシーを追加。
Grafana プロビジョニング & ダッシュボード
grafana/provisioning/dashboards/default.yml, grafana/provisioning/datasources/postgres.yml, grafana/dashboards/thq-overview.json
ダッシュボードプロバイダ(file ベース)と PostgreSQL データソース(uid: thq-postgres, url: db:5432, DB: thq, 認証は環境変数)、および THQ Overview ダッシュボード(12パネル、データソース: thq-postgres)を追加。
永続ボリューム定義
docker-compose.yml (volumes section)
grafana-data ボリュームを追加して Grafana データの永続化を確保。
環境ファイルサンプル
.env.example
GF_ADMIN_PASSWORD=change-me を追加(既存の行の小修正あり)。
ストレージ初期化
src/storage.rs
prepare() にインデックス作成を2件追加:idx_location_logs_recorded_atlocation_logs(recorded_at, device))と idx_log_events_recorded_atlog_events(recorded_at, log_level))。

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant Grafana
    participant FS as "Filesystem (provisioning & dashboards)"
    participant Postgres as "PostgreSQL (db)"
    Browser->>Grafana: HTTP GET / (dashboard UI)
    Grafana->>FS: Load provisioning (datasources, dashboards)
    Grafana->>Postgres: Connect via datasource `thq-postgres` (SQL queries)
    Postgres-->>Grafana: Query results
    Grafana-->>Browser: Render dashboard (panels)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 ダッシュボードがぴょん、夜明けに立ち、
ポストグレスと手をつなぎ見る景色、
パネルが踊る、数字が歌う、
3000番で呼んでるよ、来てごらん、
ぴょんと祝うよ、監視の朝!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed プルリクエストのタイトル「Add Grafana monitoring dashboard for THQ tracking system」は、変更内容の主要な目的を明確に要約しており、Grafanaダッシュボードの追加と、THQトラッキングシステムへの統合という主要な変更を正確に反映しています。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/evaluate-grafana-integration-7ZRQz

Comment @coderabbitai help to get the list of available commands and usage tips.

@TinyKitten TinyKitten self-assigned this Mar 5, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
grafana/dashboards/thq-overview.json (1)

13-13: データソース UID が空に設定されています。

すべてのパネルで "uid": "" が設定されています。これは postgres.ymlisDefault: true が設定されているため動作しますが、将来複数のデータソースが追加された場合に明確性が低下する可能性があります。

現時点ではこの設定で問題ありませんが、明示的な UID(例:"uid": "thq-postgres")を使用し、postgres.yml でも同じ UID を設定することで、より堅牢な構成になります。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grafana/dashboards/thq-overview.json` at line 13, The panels currently set
the datasource uid to an empty string ("datasource": { "type": "postgres",
"uid": "" }), which relies on postgres.yml's isDefault and is fragile; update
each panel's datasource UID to a specific identifier (e.g., "thq-postgres") and
ensure the same UID is defined in your postgres.yml datasource declaration so
Grafana resolves the correct datasource even if multiple postgres datasources
are added later.
docker-compose.yml (1)

41-42: デフォルトの管理者パスワードが弱いです。

GF_ADMIN_PASSWORD のデフォルト値が admin に設定されています。開発環境では許容範囲ですが、本番環境やインターネットに公開された環境では、この弱いデフォルトパスワードはセキュリティリスクとなります。

.env.example ファイルに GF_ADMIN_PASSWORD の設定例を追加し、ドキュメントで強力なパスワードの設定を促すことを検討してください。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 41 - 42, 現在の docker-compose.yml は
GF_ADMIN_PASSWORD に弱いデフォルト値 "admin"
を与えておりセキュリティリスクがあるため、GF_SECURITY_ADMIN_PASSWORD: ${GF_ADMIN_PASSWORD:-admin}
を変更してデフォルトを削除(例: GF_SECURITY_ADMIN_PASSWORD:
${GF_ADMIN_PASSWORD})し、必須の環境変数にするか、安全なランダム値を生成する仕組みを導入してください。合わせて .env.example に
GF_ADMIN_PASSWORD
のエントリを追加し(例として強力なパスワードのフォーマットやパスワード生成推奨を記載)、ドキュメントに本番環境では必ず強力なパスワードを設定する旨を追記してください。
grafana/provisioning/datasources/postgres.yml (1)

8-13: ハードコードされた認証情報をセキュリティの観点から検討してください。

パスワード thq がファイルに直接記述されています。docker-compose.yml の GF_ADMIN_PASSWORD のように環境変数を使用することを検討してください。Grafana は $__env{VAR_NAME} または ${VAR_NAME} 構文で環境変数の参照をサポートしています。

現在の開発環境設定では許容範囲ですが、本番環境では認証情報を外部化することを推奨します。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grafana/provisioning/datasources/postgres.yml` around lines 8 - 13, The
postgres datasource currently hardcodes credentials (user: thq and
secureJsonData.password: thq); replace these with environment-variable
references so secrets aren't stored in the YAML. Update the postgres.yml entries
for user and secureJsonData.password to use Grafana's env var syntax (e.g.
${VAR_NAME} or $__env{VAR_NAME}) and document the new env names (e.g.
GRAFANA_PG_USER, GRAFANA_PG_PASSWORD) so docker-compose or the deployment
injects them instead of the literal "thq".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docker-compose.yml`:
- Around line 41-42: 現在の docker-compose.yml は GF_ADMIN_PASSWORD に弱いデフォルト値
"admin" を与えておりセキュリティリスクがあるため、GF_SECURITY_ADMIN_PASSWORD:
${GF_ADMIN_PASSWORD:-admin} を変更してデフォルトを削除(例: GF_SECURITY_ADMIN_PASSWORD:
${GF_ADMIN_PASSWORD})し、必須の環境変数にするか、安全なランダム値を生成する仕組みを導入してください。合わせて .env.example に
GF_ADMIN_PASSWORD
のエントリを追加し(例として強力なパスワードのフォーマットやパスワード生成推奨を記載)、ドキュメントに本番環境では必ず強力なパスワードを設定する旨を追記してください。

In `@grafana/dashboards/thq-overview.json`:
- Line 13: The panels currently set the datasource uid to an empty string
("datasource": { "type": "postgres", "uid": "" }), which relies on
postgres.yml's isDefault and is fragile; update each panel's datasource UID to a
specific identifier (e.g., "thq-postgres") and ensure the same UID is defined in
your postgres.yml datasource declaration so Grafana resolves the correct
datasource even if multiple postgres datasources are added later.

In `@grafana/provisioning/datasources/postgres.yml`:
- Around line 8-13: The postgres datasource currently hardcodes credentials
(user: thq and secureJsonData.password: thq); replace these with
environment-variable references so secrets aren't stored in the YAML. Update the
postgres.yml entries for user and secureJsonData.password to use Grafana's env
var syntax (e.g. ${VAR_NAME} or $__env{VAR_NAME}) and document the new env names
(e.g. GRAFANA_PG_USER, GRAFANA_PG_PASSWORD) so docker-compose or the deployment
injects them instead of the literal "thq".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ae5c1fa-dfe1-45d9-a184-283e2a005a1e

📥 Commits

Reviewing files that changed from the base of the PR and between fb076a9 and 0466954.

📒 Files selected for processing (4)
  • docker-compose.yml
  • grafana/dashboards/thq-overview.json
  • grafana/provisioning/dashboards/default.yml
  • grafana/provisioning/datasources/postgres.yml

claude added 4 commits March 5, 2026 12:18
…e env vars for PG creds

- GF_ADMIN_PASSWORD is now required (no weak default)
- Datasource provisioning uses $__env{} for PG user/password
- All dashboard panels reference explicit UID "thq-postgres"
- .env.example updated with GF_ADMIN_PASSWORD entry

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce
Grafana's "m" unit maps to minutes; "lengthmeter" is the correct
unit ID for meters.

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce
…abels

Without the transformation, piechart only shows "count" as a single
series instead of breaking it out by log_level.

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce
"lengthmeter" is not a recognized Grafana unit and was displayed
literally. Use "suffix: m" to show e.g. "33.2 m".

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
grafana/dashboards/thq-overview.json (1)

129-133: 「Active Devices (24h)」パネルが時間ピッカーと非連動です。

Line 131 の固定 24 時間窓により、ダッシュボードの時間範囲を変更しても他のパネルと比較条件がずれます。検証結果、このパネルのみが固定窓を使用しており、残り 9 つのパネルはすべて $__timeFrom()$__timeTo() 変数を使用しています。一貫性のため、同じ時間変数に揃えることを推奨します。

修正案
-          "rawSql": "SELECT COUNT(DISTINCT device) AS \"Devices\" FROM location_logs WHERE recorded_at >= NOW() - INTERVAL '24 hours'",
+          "rawSql": "SELECT COUNT(DISTINCT device) AS \"Devices\" FROM location_logs WHERE recorded_at >= $__timeFrom() AND recorded_at <= $__timeTo()",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grafana/dashboards/thq-overview.json` around lines 129 - 133, The "Active
Devices (24h)" panel is hard-coded to a 24-hour window; update its rawSql (the
panel with refId "A" / the rawSql property) to use Grafana time range variables
instead of NOW() - INTERVAL '24 hours' so it follows the dashboard time picker;
replace the WHERE clause with a time-range filter using $__timeFrom() and
$__timeTo() (e.g. recorded_at >= $__timeFrom() AND recorded_at <= $__timeTo() or
BETWEEN) while keeping the same datasource and result formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@grafana/dashboards/thq-overview.json`:
- Around line 26-299: Add time-series indexes for recorded_at to avoid full
table scans: create an index on location_logs(recorded_at) (or composite
location_logs(recorded_at, device)) and on log_events(recorded_at) (or composite
log_events(recorded_at, log_level)); update the schema/migration definitions
where existing indexes are created (currently idx_location_logs_device,
idx_location_logs_segment, idx_log_events_device) to add
idx_location_logs_recorded_at and idx_log_events_recorded_at (or their composite
variants) so all queries using WHERE recorded_at >= $__timeFrom() AND
recorded_at <= $__timeTo() can use the index.

---

Nitpick comments:
In `@grafana/dashboards/thq-overview.json`:
- Around line 129-133: The "Active Devices (24h)" panel is hard-coded to a
24-hour window; update its rawSql (the panel with refId "A" / the rawSql
property) to use Grafana time range variables instead of NOW() - INTERVAL '24
hours' so it follows the dashboard time picker; replace the WHERE clause with a
time-range filter using $__timeFrom() and $__timeTo() (e.g. recorded_at >=
$__timeFrom() AND recorded_at <= $__timeTo() or BETWEEN) while keeping the same
datasource and result formatting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3543c8f-d61a-4aca-acc2-5063fe696d87

📥 Commits

Reviewing files that changed from the base of the PR and between 0466954 and a64a585.

📒 Files selected for processing (4)
  • .env.example
  • docker-compose.yml
  • grafana/dashboards/thq-overview.json
  • grafana/provisioning/datasources/postgres.yml
🚧 Files skipped from review as they are similar to previous changes (2)
  • grafana/provisioning/datasources/postgres.yml
  • docker-compose.yml

All dashboard panels filter on recorded_at with time range macros.
Without an index on recorded_at, every query does a full table scan.

- idx_location_logs_recorded_at (recorded_at, device)
- idx_log_events_recorded_at (recorded_at, log_level)

https://claude.ai/code/session_01RADeEtKpYSQno63R2Cd5Ce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants