How to Implement Request/Response Logging Middleware in Gorig: A Complete Guide

Use httpx.Logging() from the httpx package to capture request details, response status, and latency by registering it with srv.Use() on your httpx.HTTP instance.

The jom-io/gorig framework provides a lightweight HTTP layer through the httpx package, making it straightforward to implement request/response logging middleware in Gorig services. By leveraging the built-in logging middleware located in httpx/mid.logger.go, you can automatically capture comprehensive telemetry for every HTTP transaction without writing boilerplate instrumentation code.

Understanding Gorig's HTTP Middleware Architecture

Gorig's HTTP stack centers around the httpx.HTTP struct defined in httpx/http.go. Middleware follows the standard Go pattern with the signature func(http.Handler) http.Handler, allowing seamless composition of cross-cutting concerns. The httpx.RegisterRouter helper and the Use method attach middleware to the server instance, executing handlers in the order they are registered.

How the Built-in Logging Middleware Works

The core implementation resides in httpx/mid.logger.go. This middleware performs four critical operations to ensure complete observability:

  1. Captures request metadata – Records the HTTP method, URL, headers, remote address, and optionally the request body.
  2. Records start time – Marks the request entry time to calculate total latency after handler completion.
  3. Wraps the ResponseWriter – Uses a proxy struct to intercept WriteHeader and Write calls, capturing the status code and response size since the standard http.ResponseWriter does not expose these after transmission.
  4. Defers log emission – Executes a deferred function that outputs a structured log line containing timestamp, request ID (if available), HTTP method, path, status, size, duration, and optional bodies.

The middleware delegates actual log output to utils/logger/logger.go, a thin wrapper that defaults to the standard library but accepts pluggable structured loggers.

Implementing Request/Response Logging in Your Service

Basic Setup with the Default Logger

To enable logging, initialize the logger and register the middleware when constructing your HTTP server. The httpx.Logging() function returns the middleware handler compatible with srv.Use().

package main

import (
	"github.com/jom-io/gorig/httpx"
	"github.com/jom-io/gorig/utils/logger"
)

func main() {
	// Initialize the default logger
	logger.Setup(logger.Config{Level: "info"})

	// Create HTTP server instance
	srv := httpx.NewHTTP()

	// Register the logging middleware
	srv.Use(httpx.Logging())

	// ... register routes and start server
	srv.Start()
}

Registering Multiple Middlewares

Middleware executes in registration order. Place httpx.Logging() early in the chain to capture the full request lifecycle, including time spent in subsequent middlewares like authentication or CORS.

func main() {
	logger.Setup(logger.Config{Level: "debug"})
	srv := httpx.NewHTTP()

	// Order matters: logging first captures total latency
	srv.Use(httpx.Logging())      // from httpx/mid.logger.go
	srv.Use(httpx.Recovery())     // panic recovery from httpx/mid.recovery.go
	srv.Use(httpx.CORS())         // CORS headers
	srv.Use(httpx.Sign())         // request signing verification

	// Register business routes using apix helpers
	srv.Handle("/api/v1/hello", apix.Handle(func(c *apix.Context) error {
		return c.JSON(apix.OK, map[string]string{"msg": "hello world"})
	}))

	srv.Start()
}

Using a Custom Logger Implementation

The middleware calls logger.Infof from utils/logger/logger.go. To use a structured logger like Zap or Logrus, replace the global logger functions before starting the server.

package logger

import (
	"github.com/sirupsen/logrus"
)

var log = logrus.New()

func Infof(format string, args ...interface{}) {
	log.Infof(format, args...)
}

func Setup(cfg Config) {
	// Configure logrus level, formatting, etc.
	log.SetLevel(logrus.InfoLevel)
	log.SetFormatter(&logrus.JSONFormatter{})
}

Key Configuration Options and Best Practices

While the built-in middleware captures comprehensive data, consider these optimizations for production workloads:

  • Body Logging Control – The middleware supports optional request/response body capture, but disable this for large file uploads or in high-throughput scenarios to prevent memory pressure and log bloat.
  • Request ID Correlation – Place a request-ID middleware before the logger to ensure the logger.Infof call includes the correlation ID in the emitted line, enabling distributed tracing.
  • Latency Measurement – Because the logger defers execution until after the handler completes, it naturally captures total round-trip time including middleware overhead, not just business logic execution.

Summary

Implementing request/response logging middleware in Gorig requires only a single line of code using httpx.Logging(), but understanding the underlying architecture in httpx/mid.logger.go helps you customize the behavior. Key takeaways include:

  • Register the middleware with srv.Use(httpx.Logging()) on your httpx.HTTP instance
  • The middleware wraps http.ResponseWriter to capture status codes and response sizes
  • Execution order matters—place logging early in the middleware chain to capture total latency
  • Replace the default logger in utils/logger/logger.go to integrate structured logging libraries like Zap or Logrus

Frequently Asked Questions

Where is the logging middleware implemented in Gorig?

The core implementation resides in httpx/mid.logger.go within the jom-io/gorig repository. This file defines the middleware function that captures request metadata, wraps the ResponseWriter, and defers log emission until the handler completes.

Can I customize the log format when using Gorig's logging middleware?

Yes, by replacing the logger implementation in utils/logger/logger.go. The middleware only calls logger.Infof, so any custom logger that implements this function signature—including structured loggers like Zap, Logrus, or Zerolog—will work seamlessly without modifying the middleware itself.

How do I capture request and response bodies in the logs?

The built-in middleware in httpx/mid.logger.go supports optional body capture through configuration, though you should use this cautiously to avoid logging sensitive data or overwhelming storage with large payloads. Check the middleware's configuration options or wrap the http.Request body with io.TeeReader in a custom implementation if you need fine-grained control.

What is the correct order for registering logging middleware with other middlewares?

Register httpx.Logging() early in the chain—typically first or immediately after request-ID middleware—using srv.Use(). This placement ensures the logger captures the total request latency including time spent in authentication, CORS, and other downstream middlewares, rather than just the business handler execution.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →