Line data Source code
1 : // Package requestid は、Gin のコンテキストと HTTP ヘッダ間で
2 : // リクエストIDを取得・生成・伝播するユーティリティを提供します。
3 : package requestid
4 :
5 : import (
6 : "strings"
7 :
8 : "github.com/gin-gonic/gin"
9 : "github.com/google/uuid"
10 : )
11 :
12 : const (
13 : // HeaderCanonical は、レスポンスに設定するリクエストIDヘッダ名の正規表記です。
14 : // 入力側では "X-Request-ID" / "X-Request-Id" の双方を受け入れます。
15 : HeaderCanonical = "X-Request-ID" // 統一表記(出力はこれ)
16 : ctxKey = "request_id"
17 : )
18 :
19 : var acceptedHeaders = []string{
20 : "X-Request-ID",
21 : "X-Request-Id",
22 : //"X-Trace-Id",
23 : //"X-Correlation-Id",
24 : }
25 :
26 : // Ensure は、既存のリクエストIDをヘッダまたはコンテキストから取得し、
27 : // なければ新規生成してコンテキストとレスポンスヘッダへ設定して返します。
28 2 : func Ensure(c *gin.Context) string {
29 2 : // 1) Contextに既にあればそれを使う(※ヘッダにも揃える)
30 2 : if rid, ok := c.Get(ctxKey); ok {
31 0 : if s, ok := rid.(string); ok && s != "" {
32 0 : return setAll(c, s)
33 0 : }
34 : }
35 :
36 : // 2) 受け入れヘッダから探す(大小無視)
37 4 : for _, h := range acceptedHeaders {
38 2 : if v := c.GetHeader(h); v != "" {
39 0 : return setAll(c, v)
40 0 : }
41 : }
42 :
43 : // 3) なければ生成
44 2 : rid := uuid.NewString()
45 2 : return setAll(c, "backend_"+rid)
46 : }
47 :
48 2 : func setAll(c *gin.Context, id string) string {
49 2 : id = strings.TrimSpace(id)
50 2 : c.Set(ctxKey, id) // ハンドラ用
51 2 : c.Writer.Header().Set(HeaderCanonical, id) // レスポンス用
52 2 : return id
53 2 : }
54 :
55 : // Get は Ensure が実行済みの場合にリクエストIDを返します。未設定なら空文字を返します。
56 3 : func Get(c *gin.Context) string {
57 3 : if rid, ok := c.Get(ctxKey); ok {
58 0 : if s, ok := rid.(string); ok && s != "" {
59 0 : return s
60 0 : }
61 : }
62 3 : return ""
63 : }
|