package middleware import ( "regexp" "github.com/gin-gonic/gin" "github.com/google/uuid" ) // requestIDKey — ключ, под которым id лежит в контексте gin. const requestIDKey = "request_id" // incomingID — допустимый входящий X-Request-Id: до 64 символов из // [A-Za-z0-9._-]. Посторонние символы (переводы строк, кавычки) в логах // выглядели бы как подделка записей, поэтому чужой заголовок отбрасываем. var incomingID = regexp.MustCompile(`^[A-Za-z0-9._-]{1,64}$`) // RequestID берёт id из заголовка X-Request-Id (если он осмысленный) // или генерирует свой, кладёт в контекст и возвращает клиенту тем же // заголовком. Дальше этот id подхватывают access-log и логи безопасности: // один запрос проходится по логам одной строкой. func RequestID() gin.HandlerFunc { return func(c *gin.Context) { id := c.GetHeader("X-Request-Id") if !incomingID.MatchString(id) { id = uuid.NewString() } c.Set(requestIDKey, id) c.Header("X-Request-Id", id) c.Next() } } // RequestIDFrom возвращает id текущего запроса; "" вне middleware. func RequestIDFrom(c *gin.Context) string { return c.GetString(requestIDKey) }