【Go/Docker】効率的なバックエンドデバッグ術 - docker logsを活用したAPIトラブルシューティング

こんにちは！フリーランスエンジニアのこたろうです。
今回は、Docker環境で動作するGoバックエンドのデバッグ方法について、実践的な知見を共有します。

## 1. docker logsの基本

### リアルタイムでログを確認
```bash
# コンテナのログをリアルタイムで表示
docker logs -f backend-container

# 直近100行のログを表示
docker logs --tail 100 backend-container

# タイムスタンプ付きでログを表示
docker logs -f --timestamps backend-container
```

### Goコードでのログ出力
```go
// handlers/message.go
func (h *MessageHandler) Create(c *gin.Context) {
    // リクエストの開始をログ出力
    fmt.Printf("Message creation started at: %v\n", time.Now())
    
    var message Message
    if err := c.ShouldBindJSON(&message); err != nil {
        fmt.Printf("Error binding JSON: %v\n", err)
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    
    // 処理の結果をログ出力
    fmt.Printf("Message created: %+v\n", message)
}
```

## 2. grepを使ったログのフィルタリング

### 特定のAPIリクエストの抽出
```bash
# /api/messages/createへのリクエストのみ表示
docker logs -f backend-container | grep "/api/messages/create"

# エラーを含むログの抽出
docker logs backend-container | grep "Error"

# 特定の時間帯のログを抽出
docker logs backend-container | grep "2024-02-06T15"
```

### パイプを活用した複雑なフィルタリング
```bash
# エラーを含み、特定のAPIに関連するログを抽出
docker logs backend-container | grep "Error" | grep "/api/messages"

# JSONデータの内容を確認
docker logs backend-container | grep "Message created" | jq .
```

## 3. CORSデバッグのテクニック

### OPTIONSリクエストの確認
```go
// main.go
func setupCORS(r *gin.Engine) {
    fmt.Println("Setting up CORS...")
    
    r.Use(cors.New(cors.Config{
        AllowOrigins: []string{"http://localhost:3000"},
        AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
        ExposeHeaders: []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge: 12 * time.Hour,
    }))
    
    // OPTIONSリクエストのログ
    r.OPTIONS("/*path", func(c *gin.Context) {
        fmt.Printf("OPTIONS request received: %s\n", c.Request.URL.Path)
        c.Status(http.StatusNoContent)
    })
}
```

### CORSエラーのデバッグ
```bash
# OPTIONSリクエストのログを確認
docker logs backend-container | grep "OPTIONS request received"

# CORSヘッダーの確認
docker logs backend-container | grep "Access-Control-Allow"
```

## 4. WebSocketデバッグのポイント

### コネクション確立のログ
```go
func (h *WebSocketHandler) HandleWebSocket(c *gin.Context) {
    fmt.Printf("WebSocket connection attempt from: %s\n", c.Request.RemoteAddr)
    
    conn, err := h.upgrader.Upgrade(c.Writer, c.Request, nil)
    if err != nil {
        fmt.Printf("WebSocket upgrade error: %v\n", err)
        return
    }
    defer conn.Close()
    
    fmt.Printf("WebSocket connection established with: %s\n", c.Request.RemoteAddr)
}
```

### WebSocketメッセージのログ
```bash
# WebSocketの接続ログを確認
docker logs backend-container | grep "WebSocket connection"

# エラーを含むWebSocketログを確認
docker logs backend-container | grep "WebSocket" | grep "error"
```

## 5. 実践的なトラブルシューティング例

### エラーの原因特定
```bash
# エラーの発生時刻を特定
docker logs --timestamps backend-container | grep "Error"

# エラー前後のログを確認
docker logs --timestamps backend-container | grep -A 5 -B 5 "Error"

# 特定のリクエストの一連の流れを確認
docker logs backend-container | grep -E "(Started|Completed|Error)"
```

### デバッグ用ログの実装
```go
type DebugLogger struct {
    Enabled bool
}

func (l *DebugLogger) Printf(format string, v ...interface{}) {
    if l.Enabled {
        fmt.Printf("[DEBUG] "+format+"\n", v...)
    }
}

// 使用例
logger := &DebugLogger{Enabled: true}
logger.Printf("Processing request: %s", requestID)
```

## まとめ

効果的なデバッグのポイント：
1. 適切なログレベルの設定
2. 必要な情報の選択的な出力
3. grepを活用したログの絞り込み
4. エラー発生時の文脈の把握
5. システマティックな原因特定