DevContainer@VSCode×Go(Gin)×Air×Delveでデバッグ環境構築




コンテナ開発環境(DevContainers@VSCode) × ホットリロード(air) × ステップインデバッグ(delve)の環境構築メモ

DevContainersならコンテナ内のローカルホストのデバッガポートに直接アタッチ出来るのでシンプルに構成可能できる。

アーキ概要



コンテナ

golang:1.22.11-alpine3.21

delve デバッガ

インストール

go install github.com/go-delve/delve/cmd/dlv@latest

コマンドパレットのGo Install/Update ToolsからインストールでもOK ※VSCodeServer@コンテナにGoエクステンションが入っていること



Air ホットリロード

バイナリインストールと環境初期化

go install github.com/air-verse/air@latest \
&& cd path/to/app_root
&& air init #=> ./.air.tomlが生成される

.air.tomlコンフィグをデバッグ向けに編集

[build]
  # ビルド設定
  cmd = "go build -gcflags=\"all=-N -l\" -o ./tmp/main ."
  # 起動設定
  # --logオプションで標準出力に詳細ログを出力
  full_bin = "dlv --headless=true --listen=:2345 --api-version=2 --accept-multiclient exec --continue ./tmp/main"

# その他はデフォルト

ノーマルビルドと比較してデバッグビルドは時間はかかるようになった

-gcflags="all=-N -l"


デバッガ(delve など)を使う場合、Go の最適化が入っていると変数の値が見えなくなったり、 関数がインライン化されてブレークポイントが期待通り動かなくなることがあるので、Go コンパイラの最適化を無効化するためのオプションを指定する

オプションについて

  • -N: 最適化を無効化してデバッグしやすくする
  • -l: インライン展開を無効化して関数のインライン化を防ぐ

full_bin = "dlv --headless=true --listen=:40000 --api-version=2 --accept-multiclient exec --continue ./tmp/main"


dlv execでビルドバイナリ./tmp/mainをデバッグ実行する

オプションについて

  • —headless=true により、CLI(ターミナル)ではなく、エディタや別のデバッガから接続できる
  • --listen=:2345により、ポート2345にデバッガを待機
  • --accept-multiclient により、複数のクライアント(VSCode, GoLand など)から同時に接続できる
  • --continue により、Delve 起動時に自動的にプログラムを実行(手動で continue を打たなくて済む)

VSCode

デバッグ構成はアタッチ式で

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach Server",
            "type": "go",
            "request": "attach",
            "mode": "remote",
            "port": 2345,
            "host": "localhost",
            "showLog": true
        }
    ]
}

デバッグ

  1. アプリケーションディレクトリでairを実行する
cd path/to/app_root && air
  1. VSCodeの実行とデバッグ > Attach Serverでアタッチ開始
  2. ブレークポイントを設定してhttpリクエストを入れたらブレークする

SQLでカレンダーとかインデックスの付番


一定期間のカレンダーを生成したり、結果に論理番号を付番するメモ

カレンダー

起算日(2025-01-01) + オフセット(0..*)でカレンダーを作成する

オフセットの準備

指定レンジでインクリメンタルなオフセット値を持つテーブルを作成する

  • オフセット値は変数に持ち歩かせる
  • information_schema.COLUMNSのクエリ結果でレンジ行を確保しつつ、オフセット値を格納
  • LIMITでレンジを切る
-- 1行目でレンジ変数初期化
SELECT @_index := 0 AS _index -- 0
-- 2行目以降をUNIONで結合
UNION
-- 行確保のため、information_schema.COLUMNSをクエリして、レンジ変数をインクリメント
SELECT @_index := @_index + 1 AS _index FROM information_schema.COLUMNS -- 1..*
-- レンジの上限=7行
LIMIT 7;
+--------+
| _index |
+--------+
|      0 |
|      1 |
|      2 |
|      3 |
|      4 |
|      5 |
|      6 |
+--------+

カレンダーにする


  • 起算日(2025-01-01)にオフセット値を加算する
SELECT '2025-01-01' + INTERVAL _range._index DAY AS DATE FROM (
  -- 1行目でレンジ変数初期化
  SELECT @_index := 0 AS _index
  -- 2行目以降をUNIONで結合
  UNION
  -- 行確保のため、information_schema.COLUMNSをクエリして、レンジ変数をインクリメント
  SELECT @_index := @_index + 1 AS _index FROM information_schema.COLUMNS
  -- レンジの上限=10個
  LIMIT 7
) _range;
+------------+
| DATE       |
+------------+
| 2025-01-01 |
| 2025-01-02 |
| 2025-01-03 |
| 2025-01-04 |
| 2025-01-05 |
| 2025-01-06 |
| 2025-01-07 |
+------------+

論理番号を付番する

クエリ結果に対して、論理番号を付番して意味付けする

こんな科目-点数テーブルがあったとして

+-----------+-------+
| category  | score |
+-----------+-------+
| 国語       |    84 |
| 国語       |    91 |
| 国語       |    77 |
| 数学       |    88 |
| 数学       |    98 |
| 数学       |    81 |
| 理科       |    50 |
| 理科       |    80 |
| 理科       |    68 |
+-----------+-------+

結果に行番号を付番する

  • 行番号を変数に持ち歩かせる
  • FROM句で変数を初期化する

全教科の点数ランキング

SELECT
  -- 結果順に変数を加算
  @_rank := @_rank + 1 AS rank,
  score.category,
  score.score
FROM
  score,
  -- 変数を初期化。テーブルに用はない
  (SELECT @_rank:= 0) AS row_num
-- score降順
ORDER BY score.score DESC;
+------+----------+-------+
| rank | category | score |
+------+----------+-------+
|    1 | 数学      |    98 |
|    2 | 国語      |    91 |
|    3 | 数学      |    88 |
|    4 | 国語      |    84 |
|    5 | 数学      |    81 |
|    6 | 理科      |    80 |
|    7 | 国語      |    77 |
|    8 | 理科      |    68 |
|    9 | 理科      |    50 |
+------+----------+-------+

教科ごの点数ランキング

  • 付番する軸=教科の変わり目で行番号を初期化する
SELECT
  -- 付番する軸=教科の変わり目で行番号を初期化する
  @_rank := IF(@prev_category = score.category, @_rank + 1, 1) AS rank,
  @prev_category := score.category AS category,
  score.score
FROM score
-- カテゴリ×score降順
ORDER BY score.category ASC, score.score DESC
+------+----------+-------+
| rank | category | score |
+------+----------+-------+
|    1 | 国語      |    91 |
|    2 | 国語      |    84 |
|    3 | 国語      |    77 |
|    1 | 数学      |    98 |
|    2 | 数学      |    88 |
|    3 | 数学      |    81 |
|    1 | 理科      |    80 |
|    2 | 理科      |    68 |
|    3 | 理科      |    50 |
+------+----------+-------+