### Run Quickstart Example Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Execute the basic quickstart example application to see the RequestID middleware in action. ```bash go run ./example/quickstart/main.go ``` -------------------------------- ### Hertz Server Setup with Request ID Middleware Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Initialize a Hertz server and apply the `requestid.New()` middleware. This example demonstrates setting up health check and data endpoints, automatically including the request ID. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New()) // Health check endpoint - request ID included automatically h.GET("/health", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) c.JSON(consts.StatusOK, map[string]string{ "status": "ok", "request_id": id, }) }) // Data endpoint with logging h.GET("/api/data/:id", func(ctx context.Context, c *app.RequestContext) { requestID := requestid.Get(c) dataID := c.Param("id") // Log with request ID for tracing log.Printf("[%s] Fetching data %s", requestID, dataID) data := fetchData(dataID) c.JSON(consts.StatusOK, map[string]interface{}{ "request_id": requestID, "data": data, }) }) h.Spin() } func fetchData(id string) interface{} { return map[string]interface{}{"id": id} } ``` -------------------------------- ### Default Configuration Example Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md This example demonstrates how to explicitly set the default configurations for the Request ID middleware, which include UUID v4 generation, 'X-Request-ID' header, and no default handler. ```go // Equivalent to explicitly setting defaults: requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return uuid.New().String() }), requestid.WithCustomHeaderStrKey("X-Request-ID"), ) ``` -------------------------------- ### Basic Retrieval and Response with Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md This example demonstrates a complete Hertz application setup where the RequestID middleware is registered, and the retrieved request ID is included in a JSON response. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New()) h.GET("/users", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) c.JSON(consts.StatusOK, utils.H{ "request_id": id, "data": []string{"user1", "user2"}, }) }) h.Spin() } ``` -------------------------------- ### Using Handler for Context Initialization Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Example demonstrating how to use a `Handler` to initialize context values, such as storing the trace ID and timestamp for downstream use. ```APIDOC ## Example: Context Initialization Handler ```go handler := requestid.Handler(func(ctx context.Context, c *app.RequestContext, requestID string) { // Store request ID in context for downstream handlers ctx = context.WithValue(ctx, "trace-id", requestID) // Additional context setup ctx = context.WithValue(ctx, "timestamp", time.Now()) }) h.Use(requestid.New( requestid.WithHandler(handler), )) ``` ``` -------------------------------- ### Install RequestID Middleware Source: https://github.com/hertz-contrib/requestid/blob/main/README.md Use this command to install the RequestID middleware for your Hertz project. ```shell go get github.com/hertz-contrib/requestid ``` -------------------------------- ### Using Handler for Logging Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Example of how to define and use a `Handler` to log the request ID, client IP, and timestamp for each request. ```APIDOC ## Example: Logging Handler ```go handler := requestid.Handler(func(ctx context.Context, c *app.RequestContext, requestID string) { log.Printf("New request %s from %s at %s", requestID, c.ClientIP(), time.Now().Format(time.RFC3339)) }) h.Use(requestid.New( requestid.WithHandler(handler), )) ``` ``` -------------------------------- ### Configure Request ID with Sequential ID Generation Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md This example uses a generator function to create sequential IDs for requests. ```go var requestCounter int64 h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { num := atomic.AddInt64(&requestCounter, 1) return fmt.Sprintf("req-%d", num) }), )) ``` -------------------------------- ### Efficient Handler Function with Async Logging Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md An example of a handler function that uses goroutines for non-blocking logging. ```go handler := requestid.Handler(func(ctx context.Context, c *app.RequestContext, requestID string) { // Fire-and-forget logging to avoid blocking go func() { log.Printf("Request %s from %s", requestID, c.ClientIP()) }() }) ``` -------------------------------- ### Example: Context Initialization Handler for Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Shows how to use a handler to store the request ID and other relevant information into the context for downstream use. This is achieved by creating a new context with the values and passing it to subsequent handlers. ```go handler := requestid.Handler(func(ctx context.Context, c *app.RequestContext, requestID string) { // Store request ID in context for downstream handlers ctx = context.WithValue(ctx, "trace-id", requestID) // Additional context setup ctx = context.WithValue(ctx, "timestamp", time.Now()) }) h.Use(requestid.New( requestid.WithHandler(handler), )) ``` -------------------------------- ### Example: Logging Handler for Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Demonstrates how to use a handler to log the generated request ID along with client IP and timestamp. This handler is registered using `requestid.New` and `requestid.WithHandler`. ```go handler := requestid.Handler(func(ctx context.Context, c *app.RequestContext, requestID string) { log.Printf("New request %s from %s at %s", requestID, c.ClientIP(), time.Now().Format(time.RFC3339)) }) h.Use(requestid.New( requestid.WithHandler(handler), )) ``` -------------------------------- ### Example Request with X-Request-ID Header Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Client-provided request identifier for tracing across services. If the header is absent, the middleware generates one. ```http GET /api/users HTTP/1.1 Host: api.example.com X-Request-ID: client-provided-id-12345 ``` ```http # If no X-Request-ID header is present, middleware generates one GET /api/data HTTP/1.1 Host: api.example.com # No X-Request-ID header ``` -------------------------------- ### Request Processing Example with Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md Demonstrates a full request processing flow, including handler registration, retrieving the request ID, fetching data, and returning a JSON response that includes the request ID. ```go // Handler registration h.Use(requestid.New()) h.GET("/api/users", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) users := fetchUsers() c.JSON(200, map[string]interface{}{ "request_id": id, "users": users, }) }) // When client makes request: // GET /api/users HTTP/1.1 // (no X-Request-ID header) // // Response: // HTTP/1.1 200 OK // X-Request-ID: 550e8400-e29b-41d4-a716-446655440000 // // { // "request_id": "550e8400-e29b-41d4-a716-446655440000", // "users": [...] // } ``` -------------------------------- ### Example Response with X-Request-ID Header Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Middleware includes the request ID in the response header. This ID can be client-provided or generated by the middleware. ```http HTTP/1.1 200 OK Content-Type: application/json X-Request-ID: 550e8400-e29b-41d4-a716-446655440000 {"status": "ok"} ``` -------------------------------- ### Error Handling with Tracing using Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Shows how to log errors along with the request ID for easier debugging and tracing. This example requires the `requestid.New()` middleware to be active. ```go package main import ( "context" "log" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New()) h.POST("/api/process", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) data, err := processData(c.Request.Body) if err != nil { log.Printf("[%s] ERROR: %v", id, err) c.JSON(consts.StatusInternalServerError, map[string]string{ "error": err.Error(), "request_id": id, }) return } log.Printf("[%s] Processing successful", id) c.JSON(consts.StatusOK, map[string]interface{}{ "request_id": id, "data": data, }) }) h.Spin() } func processData(body []byte) (interface{}, error) { // Process implementation return nil, nil } ``` -------------------------------- ### Generate Opaque Request ID (Good Practice) Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Use opaque identifiers like UUIDs for generating request IDs to enhance security. This example demonstrates a recommended approach. ```go // Good: use opaque identifiers good := requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return uuid.New().String() }) ``` -------------------------------- ### RequestID Get Function Definition Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Provides the source code definition for the `Get` function, which retrieves the request identifier from the response headers. ```go // Get returns the request identifier func Get(c *app.RequestContext) string { return c.Response.Header.Get(headerXRequestID) } ``` -------------------------------- ### Integrate Request ID with Metrics Middleware Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Record the start time of a request using its ID for metrics collection. This can be used to track request durations or other time-based metrics associated with specific request IDs. ```go var requestsPerID = &sync.Map{} h.Use(requestid.New( requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { requestsPerID.Store(requestID, time.Now()) }), )) ``` -------------------------------- ### Incorrect Usage of Get Function Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Calling `requestid.Get(c)` without prior registration of the RequestID middleware will result in an empty string being returned. Ensure middleware is registered first. ```go // Calling Get without middleware will return empty string h.GET("/api/resource", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // Returns "" - middleware not registered }) ``` -------------------------------- ### Custom Timestamp-Based Request ID Generator Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Example of a custom generator that creates IDs based on nanosecond timestamps and a random number. Use this when a predictable, time-based ID is needed. ```go generator := requestid.Generator(func(ctx context.Context, c *app.RequestContext) string { return fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Intn(1000000)) }) h.Use(requestid.New( requestid.WithGenerator(generator), )) ``` -------------------------------- ### Logging with Request ID in Hertz Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md This example shows how to integrate request ID retrieval into a Hertz application for logging purposes. The request ID is used to prefix log messages, aiding in tracking and debugging. ```go package main import ( "context" "log" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New()) h.POST("/submit", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) log.Printf("[%s] Processing POST request from %s", id, c.ClientIP()) // Process the request result := processRequest(c) log.Printf("[%s] Request completed with status: %v", id, result) c.JSON(consts.StatusOK, map[string]interface{}{ "status": result, }) }) h.Spin() } func processRequest(c *app.RequestContext) bool { // Business logic return true } ``` -------------------------------- ### Accessing Request ID from Context Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md Demonstrates two methods to retrieve the request ID from the context: using the `Get` function and directly accessing the context value if the header key is known. Both methods yield the same result. ```go func handler(ctx context.Context, c *app.RequestContext) { // Method 1: Using Get function id1 := requestid.Get(c) // Method 2: Using context directly (if header key is known) id2 := ctx.Value("X-Request-ID").(string) // Both return the same value } ``` -------------------------------- ### Custom Request ID Generator Using Request Properties Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Example of a custom generator that creates IDs using HTTP method, request path, and a timestamp. This is useful for generating IDs that include request-specific details. ```go generator := requestid.Generator(func(ctx context.Context, c *app.RequestContext) string { method := string(c.Request.Method) path := c.Request.URI().String() timestamp := time.Now().UnixNano() return fmt.Sprintf("%s-%s-%d", method, path, timestamp) }) h.Use(requestid.New( requestid.WithGenerator(generator), )) ``` -------------------------------- ### Generate Request ID with User ID (Bad Practice) Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Avoid generating request IDs that include sensitive user information. This example shows a bad practice of embedding user IDs. ```go // Bad: includes user ID which may be sensitive bad := requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { userID := c.GetString("user_id") return fmt.Sprintf("user-%s", userID) }) ``` -------------------------------- ### Enable RequestID Tracking and Retrieve ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/00-START-HERE.md This Go code demonstrates how to enable the RequestID middleware in a Hertz server and retrieve the generated request ID within a handler. It shows the basic setup for tracking requests. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() // Enable request ID tracking h.Use(requestid.New()) h.GET("/api/data", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) c.JSON(200, map[string]string{ "request_id": id, "status": "ok", }) }) h.Spin() } ``` -------------------------------- ### Get Function Usage Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md The Get function retrieves the request identifier from the context. It is thread-safe and can be safely used in goroutines. ```APIDOC ## Get Function ### Description Returns the request identifier. ### Function Signature ```go func Get(c *app.RequestContext) string ``` ### Parameters - **c** (*app.RequestContext) - The request context. ### Returns - **string** - The request identifier. ### Thread Safety The `Get` function is thread-safe. The HTTP request context is specific to each request and is not shared across goroutines unless explicitly passed. ### Example Usage ```go h.GET("/async", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // Safe to pass to goroutine go func() { log.Printf("Async operation with ID: %s", id) }() c.JSON(200, map[string]string{"status": "ok"}) }) ``` ``` -------------------------------- ### Combine Multiple Middleware Options Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Demonstrates initializing the Request ID middleware with multiple configuration options: a custom header key, a custom ID generator, and a custom handler callback. ```go h.Use( requestid.New( requestid.WithCustomHeaderStrKey("X-Request-ID"), requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return uuid.New().String() }), requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { log.Printf("Processed request: %s", requestID) }), ), ) ``` -------------------------------- ### Get Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md The Get function retrieves the request identifier from the response headers. It is typically used within Hertz request handlers to access the request ID assigned by the RequestID middleware. ```APIDOC ## Get Function ### Description Retrieves the request identifier from the response headers that were set by the RequestID middleware. This function is used within Hertz request handlers to access the request ID that the middleware assigned. ### Signature ```go func Get(c *app.RequestContext) string ``` ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters Table | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | c | `*app.RequestContext` | Yes | The Hertz request context passed to the handler function | ### Return Type `string` - The request identifier stored in the response headers. ### Return Value Details - Returns the request ID if the middleware has been invoked and the header is set. - Returns an empty string (`""`) if: - The middleware was not registered in the handler chain. - The handler is called before the middleware executes. - The header value was not set (though this should not normally occur if middleware is properly registered). ### Example Usage ```go package main import ( "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" // Assuming RequestID middleware and Get function are imported correctly ) func rootHandler(c *app.RequestContext) { requestID := Get(c) // Call the Get function here // Use the requestID as needed c.String(200, "Request ID: "+requestID) } func main() { h := server.Default() // Register RequestID middleware (example, actual registration might differ) // h.Use(requestid.New()) h.GET("/", rootHandler) h.Spin() } ``` ``` -------------------------------- ### Configure Different Custom Headers for Multiple Services Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/option-functions.md Demonstrates setting distinct custom headers for different services using `WithCustomHeaderStrKey`. This allows for isolated request ID tracking across multiple servers, such as an API server and a webhook server. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { apiServer := server.Default() apiServer.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-API-Request-ID"), )) webhookServer := server.Default() webhookServer.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Webhook-ID"), )) } ``` -------------------------------- ### Get() - Request ID Retrieval Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/MANIFEST.md Retrieves the request ID associated with the current request context. ```APIDOC ## Get() ### Description Retrieves the request ID from the current request context. ### Function Signature `func Get(ctx context.Context) string` ### Parameters #### Context (`ctx context.Context`) - The context of the current request. ### Return Value - `string`: The request ID associated with the context. Returns an empty string if no request ID is found. ``` -------------------------------- ### Use Default Header Key Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Initializes the Request ID middleware with its default header key. No custom configuration is needed. ```go // Use the default key h.Use(requestid.New()) ``` -------------------------------- ### Get Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md Retrieves the request ID that was previously set by the RequestID middleware from the Hertz request context. ```APIDOC ## Get ### Description Retrieves the request ID from the Hertz request context. ### Function Signature ```go func Get(c *app.RequestContext) string ``` ### Parameters - `c` - The Hertz request context (`*app.RequestContext`). ### Returns - `string` - The request identifier string. Returns an empty string if the request ID is not set. ### Example ```go id := requestid.Get(c) ``` ``` -------------------------------- ### New() - Middleware Initialization Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/MANIFEST.md Initializes the RequestID middleware. This function is used to set up the middleware with default or custom configurations. ```APIDOC ## New() ### Description Initializes the RequestID middleware with optional configuration functions. ### Function Signature `func New(opts ...Option) app.HandlerFunc` ### Parameters #### Options (`opts ...Option`) - `WithGenerator(generator Generator)`: Allows specifying a custom function to generate unique IDs. - `WithCustomHeaderStrKey(key string)`: Sets a custom header key for the request ID. Defaults to `X-RequestID`. - `WithHandler(handler Handler)`: Provides a callback function to be executed after the request ID is generated and before it's sent in the response header. ### Return Value - `app.HandlerFunc`: The configured middleware handler function. ``` -------------------------------- ### Customize Request ID Generation Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/00-START-HERE.md Provide a custom generator function to format the request ID, for example, by prefixing it with 'api-'. ```go h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return "api-" + uuid.New().String() }), )) ``` -------------------------------- ### Usage with Auth Middleware (Go) Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Shows how to register the RequestID middleware before authentication middleware to ensure IDs are generated for all requests, including those handled by auth. ```go h := server.Default() // Register RequestID middleware first to generate IDs for all requests h.Use(requestid.New()) // Register auth middleware to authenticate requests h.Use(authMiddleware()) // Handlers are executed after both middleware h.GET("/api/protected", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) userID := c.GetString("user_id") // Handle authenticated request with request ID }) ``` -------------------------------- ### Run RequestID Middleware Tests Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Execute the unit tests for the RequestID middleware using the `go test` command. The `-v` flag provides verbose output. ```bash go test ./... -v ``` -------------------------------- ### Get Request ID from Context Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md Retrieve the request ID from the Hertz request context. Returns an empty string if the ID is not set. ```go id := requestid.Get(c) ``` -------------------------------- ### Get Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/middleware.md Retrieves the request identifier from the response headers. This function is used within request handlers to access the request ID that was set by the middleware. ```APIDOC ## Get Retrieves the request identifier from the response headers. This function is used within request handlers to access the request ID that was set by the middleware. ### Signature ```go func Get(c *app.RequestContext) string ``` ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | c | `*app.RequestContext` | Yes | — | The Hertz request context from the handler function | ### Return Type `string` — The request identifier value stored in the response header. Returns an empty string if the middleware has not been invoked or if the header is not set. ### Behavior Retrieves the request ID from the response header using the header key configured in the middleware (default: `X-Request-ID`). The header key is stored in the module-level variable `headerXRequestID` which is set during middleware initialization. ### Example: Basic Usage ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return "cloudwego.io" }), )) h.GET("/ping", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) c.JSON(consts.StatusOK, utils.H{ "ping": "pong", "request-id": id, }) }) h.Spin() } ``` ### Example: With Logging ```go package main import ( "context" "log" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New()) h.POST("/api/data", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) log.Printf("[%s] Processing POST request from %s", id, c.ClientIP()) // Perform business logic with trace ID c.JSON(200, map[string]string{"status": "ok"}) }) h.Spin() } ``` ``` -------------------------------- ### Configure Request ID with All Options Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Use this to set a custom header key, a custom ID generator, and a custom handler function. ```go h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return uuid.New().String() }), requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { log.Printf("Processing request %s", requestID) }), )) ``` -------------------------------- ### Correct Usage of Get Function Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Call `requestid.Get(c)` within a Hertz handler after the RequestID middleware has been registered. This ensures a valid request ID is retrieved. ```go h.Use(requestid.New()) // Register middleware first h.GET("/api/resource", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // Middleware has already run // Use id }) ``` -------------------------------- ### Retrieve RequestID and Use in Goroutine Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Demonstrates how to retrieve the request ID using `requestid.Get` and safely pass it to an asynchronous goroutine. The `Get` function is thread-safe as the context is request-specific. ```go h.GET("/async", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // Safe to pass to goroutine go func() { log.Printf("Async operation with ID: %s", id) }() c.JSON(200, map[string]string{"status": "ok"}) }) ``` -------------------------------- ### Basic Request ID Middleware Usage Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/middleware.md Demonstrates setting up the Request ID middleware with a custom generator and accessing the ID in a handler. The custom generator is used to provide a specific ID for all requests. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h := server.Default() h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return "cloudwego.io" }), )) h.GET("/ping", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) c.JSON(consts.StatusOK, utils.H{ "ping": "pong", "request-id": id, }) }) h.Spin() } ``` -------------------------------- ### Use Default Request ID Middleware Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/00-START-HERE.md Initialize the middleware with default settings for automatic UUID generation and the 'X-Request-ID' header. ```go h.Use(requestid.New()) ``` -------------------------------- ### Configure Custom Header for Request ID (X-Trace-ID) Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/option-functions.md Use `WithCustomHeaderStrKey` to set a custom header name, like `X-Trace-ID`, for request ID management. This is useful for integrating with distributed tracing systems. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), )) h.Spin() } ``` -------------------------------- ### Configure Custom Header for Request ID (Request-ID) Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/option-functions.md Integrate with legacy systems by specifying a custom header name, such as `Request-ID`, using `WithCustomHeaderStrKey`. The middleware will then use this header for request ID operations. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() // Legacy system expects this header h.Use(requestid.New( requestid.WithCustomHeaderStrKey("Request-ID"), )) h.Spin() } ``` -------------------------------- ### Basic RequestID Middleware Usage in Hertz Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Demonstrates the basic integration of the RequestID middleware into a Hertz application. It shows how to register the middleware and retrieve the generated request ID within a handler. ```go import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() // Register middleware h.Use(requestid.New()) h.GET("/api/data", func(ctx context.Context, c *app.RequestContext) { // Retrieve request ID id := requestid.Get(c) c.JSON(200, map[string]string{ "request_id": id, "status": "ok", }) }) h.Spin() } ``` -------------------------------- ### Request Flow with Client-Provided ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Illustrates the request flow when a client provides an 'X-Request-ID' header. The middleware reads the provided ID, sets the response header, and stores it in the context without generating a new one. ```text 1. Client sends request with X-Request-ID header GET /api/resource HTTP/1.1 X-Request-ID: client-id-123 2. RequestID middleware intercepts request - Reads "client-id-123" from request header - Skips generation (ID already present) - Calls handler callback if configured - Sets response header: X-Request-ID: client-id-123 - Stores in context: context["X-Request-ID"] = "client-id-123" 3. Handler receives request - Can retrieve ID via requestid.Get(c) - Returns "client-id-123" 4. Response sent to client HTTP/1.1 200 OK X-Request-ID: client-id-123 {response body} ``` -------------------------------- ### Configure Single RequestID Middleware Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Register a single RequestID middleware with a custom header key for both reading and writing. ```go h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Request-ID"), )) ``` -------------------------------- ### Create Sequential IDs for Testing Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Configures the RequestID middleware to generate sequential IDs (e.g., 'req-1', 'req-2') using an atomic counter, which is useful for testing purposes. ```go var counter int64 h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { id := atomic.AddInt64(&counter, 1) return fmt.Sprintf("req-%d", id) }), )) ``` -------------------------------- ### Request ID Middleware with Logging Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/middleware.md Shows how to integrate the Request ID middleware and use the generated ID for logging within a handler. This is useful for tracing requests through your application. ```go package main import ( "context" "log" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() h.Use(requestid.New()) h.POST("/api/data", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) log.Printf("[%s] Processing POST request from %s", id, c.ClientIP()) // Perform business logic with trace ID c.JSON(200, map[string]string{"status": "ok"}) }) h.Spin() } ``` -------------------------------- ### Configure RequestID for Distributed Tracing Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Sets up the RequestID middleware to use 'X-Trace-ID' for custom header key and includes a handler to send the generated ID to a tracing system. ```go h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, id string) { // Send to tracing system (Jaeger, Zipkin, etc.) }), )) ``` -------------------------------- ### Custom Header Integration with Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Demonstrates how to configure the RequestID middleware to use a custom header key (e.g., 'X-Trace-ID') for both receiving and sending the request ID. This is useful for integrating with existing tracing systems. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/protocol/consts" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() // Use custom header key h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), )) h.GET("/status", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // The ID will be from X-Trace-ID header c.JSON(consts.StatusOK, map[string]string{ "trace_id": id, "status": "ok", }) }) h.Spin() } ``` -------------------------------- ### Get Request ID from Context Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/middleware.md Retrieves the request identifier from the response headers. This function is used within request handlers to access the request ID that was set by the middleware. Returns an empty string if the middleware has not been invoked or if the header is not set. ```go func Get(c *app.RequestContext) string ``` -------------------------------- ### Configuration Options Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Provides options to customize the behavior of the RequestID middleware. ```APIDOC ## Configuration Options ### WithGenerator() #### Description Sets a custom function for generating request IDs. #### Signature `func(g Generator) Option` ### WithCustomHeaderStrKey() #### Description Sets a custom header name for storing the request ID. #### Signature `func(s HeaderStrKey) Option` ### WithHandler() #### Description Sets a callback function to handle the generated request ID. #### Signature `func(h Handler) Option` ``` -------------------------------- ### Request ID Configuration for Testing Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Sets a deterministic ID for testing purposes. ```go h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return "test-id-123" }), )) ``` -------------------------------- ### Middleware Initialization Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/README.md Initializes the RequestID middleware for Hertz applications. Accepts optional configuration options. ```APIDOC ## New ### Description Initializes the RequestID middleware. You can provide custom options to configure its behavior. ### Function Signature `New(opts ...Option) app.HandlerFunc` ### Parameters - `opts` (...Option): A variadic list of `Option` functions to configure the middleware. ``` -------------------------------- ### Use Custom Header Key for Trace ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/types.md Initializes the Request ID middleware with a custom header key for distributed tracing. This allows for specific tracking of trace information. ```go // Custom key for distributed tracing h.Use( requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), ), ) ``` -------------------------------- ### Combined Configuration for Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md Combine multiple configuration options, including custom header, custom generator, and handler callback, for comprehensive request ID management. ```go h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), requestid.WithGenerator(customGenerator), requestid.WithHandler(customHandler), )) ``` -------------------------------- ### Enrich Context with Request Information Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/option-functions.md Use `WithHandler` to set request-specific information, like ID and timestamp, into the Hertz context for access by subsequent handlers. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) type RequestInfo struct { ID string Timestamp int64 } func main() { h := server.Default() h.Use(requestid.New( requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { // Store request info for access by handlers c.Set("request-info", RequestInfo{ ID: requestID, Timestamp: time.Now().Unix(), }) }), )) h.Spin() } ``` -------------------------------- ### Idempotent Requests with Client-Provided IDs Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/endpoints.md Implement idempotency by storing and checking client-provided request IDs. This prevents duplicate processing of requests. ```go // Client can retry with same request ID h.POST("/api/transfer", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // Store request ID to detect duplicate requests if isProcessed(id) { c.JSON(200, getCachedResult(id)) return } result := processTransfer() cacheResult(id, result) c.JSON(200, result) }) ``` -------------------------------- ### Create Default RequestID Generator Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Initializes the RequestID middleware with default settings, generating UUID v4 IDs and using 'X-Request-ID' as the header key. No custom handler is configured. ```go requestid.New() // Equivalent to: requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return uuid.New().String() // UUID v4 }), requestid.WithCustomHeaderStrKey("X-Request-ID"), // No handler ) ``` -------------------------------- ### Configure Request ID with Logging and Tracing Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md This configuration sets a custom header and a handler to store the trace ID for logging and log request metadata. ```go h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { // Store trace ID for logging c.Set("trace_id", requestID) // Log request metadata log.WithFields(log.Fields{ "trace_id": requestID, "method": c.Request.Method, "path": c.Request.URI().String(), }).Info("request started") }), )) ``` -------------------------------- ### Configure RequestID for Structured Logging Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Sets up the RequestID middleware to store the generated ID in the context with the key 'request_id' for structured logging. It also shows how to retrieve and use this ID within handlers. ```go h.Use(requestid.New( requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, id string) { c.Set("request_id", id) }), )) // In handlers h.GET("/", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) log.WithField("request_id", id).Info("handling request") }) ``` -------------------------------- ### Configure Handler Callback for RequestID Middleware Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/index.md Demonstrates how to register a callback function with the RequestID middleware. This function is executed after the request ID has been determined, allowing for custom logic such as logging. ```go h.Use(requestid.New( requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { log.Printf("Handling request: %s", requestID) }), )) ``` -------------------------------- ### Propagate Request ID to Helper Functions Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/get-function.md Demonstrates how to retrieve and propagate the generated request ID to helper functions for logging or database operations. Ensure the `requestid.New()` middleware is used. ```go package main import ( "context" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) type RequestContext struct { ID string UserID string } func main() { h := server.Default() h.Use(requestid.New()) h.GET("/api/data", func(ctx context.Context, c *app.RequestContext) { id := requestid.Get(c) // Propagate request ID to helper functions rc := &RequestContext{ ID: id, UserID: c.GetString("user_id"), } data := fetchData(ctx, rc) c.JSON(200, data) }) h.Spin() } func fetchData(ctx context.Context, rc *RequestContext) interface{} { // Use rc.ID for logging, database queries, etc. return map[string]interface{}{ "request_id": rc.ID, "data": []string{}, } } ``` -------------------------------- ### Multiple Request ID Middleware Instances Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Configures two separate request ID middleware instances for different purposes, such as internal tracing and client correlation. ```go // Separate ID for internal tracing h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Internal-Trace-ID"), )) // Separate ID for client correlation h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Correlation-ID"), )) ``` -------------------------------- ### Configure Custom ID Generator with Sequential IDs Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/option-functions.md Employ `WithGenerator` to create sequential request IDs by atomically incrementing a counter. This is suitable for scenarios requiring ordered identifiers. ```go package main import ( "context" "fmt" "sync/atomic" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) func main() { h := server.Default() var counter int64 h.Use(requestid.New( requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { id := atomic.AddInt64(&counter, 1) return fmt.Sprintf("req-%d", id) }), )) h.Spin() } ``` -------------------------------- ### Add Logging with Request ID Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/00-START-HERE.md Implement a custom handler to log the request ID along with other request details like the client IP. ```go h.Use(requestid.New( requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, id string) { log.Printf("Request %s from %s", id, c.ClientIP()) }), )) ``` -------------------------------- ### Option Functions Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/MANIFEST.md Functions used to configure the RequestID middleware. ```APIDOC ## Option Functions ### WithGenerator() #### Description Sets a custom function to generate unique request IDs. #### Function Signature `func WithGenerator(generator Generator) Option` #### Parameters - `generator (Generator)`: A function of type `Generator` that returns a unique string ID. ### WithCustomHeaderStrKey() #### Description Sets a custom header key for storing the request ID. #### Function Signature `func WithCustomHeaderStrKey(key string) Option` #### Parameters - `key (string)`: The custom header key (e.g., `X-Correlation-ID`). ### WithHandler() #### Description Provides a callback function to be executed after the request ID is generated. #### Function Signature `func WithHandler(handler Handler) Option` #### Parameters - `handler (Handler)`: A function of type `Handler` that accepts the context and the generated request ID. ``` -------------------------------- ### New Middleware Initialization Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/complete-reference.md Initializes the RequestID middleware for Hertz. It can be configured with various options to customize its behavior, such as setting custom headers or generators. ```APIDOC ## New ### Description Initializes the RequestID middleware with optional configuration. ### Function Signature ```go func New(opts ...Option) app.HandlerFunc ``` ### Parameters - `opts` - Variadic configuration options of type `Option`. ### Returns - `app.HandlerFunc` - A Hertz middleware handler function. ### Behavior 1. Creates middleware configuration with defaults. 2. Applies all provided options. 3. Returns a handler that: - Checks for request ID in configured header. - Generates one if not present. - Calls handler callback if configured. - Sets response header. - Stores in context. - Continues to next handler. ### Example ```go h.Use(requestid.New()) ``` ``` -------------------------------- ### Record Metrics with Request ID Handler Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/api-reference/option-functions.md Utilize `WithHandler` to record request metrics, such as the timestamp of when a request ID was processed. This requires a shared metrics structure. ```go package main import ( "context" "sync" "time" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/requestid" ) type RequestMetrics struct { mu sync.RWMutex requests map[string]time.Time } var metrics = &RequestMetrics{ requests: make(map[string]time.Time), } func main() { h := server.Default() h.Use(requestid.New( requestid.WithHandler(func(ctx context.Context, c *app.RequestContext, requestID string) { metrics.mu.Lock() metrics.requests[requestID] = time.Now() metrics.mu.Unlock() }), )) h.Spin() } ``` -------------------------------- ### Configure Request ID with Custom Header and Generator Source: https://github.com/hertz-contrib/requestid/blob/main/_autodocs/configuration.md Configure the Request ID middleware with a custom header key and a UUID generator. Ensure valid configurations to avoid runtime errors. ```go // Valid: both options are correct h.Use(requestid.New( requestid.WithCustomHeaderStrKey("X-Trace-ID"), requestid.WithGenerator(func(ctx context.Context, c *app.RequestContext) string { return uuid.New().String() }), )) ```