httpretty

repository·main·Indexed 19 days ago

https://github.com/henvic/httpretty

A Go package providing pretty-printed HTTP request and response logging to the terminal, inspired by curl's verbose mode. It supports client-side logging via http.RoundTripper and server-side logging via middleware. Features include configurable visibility for headers, bodies, and TLS info, ANSI color support, custom body formatters (including a built-in JSONFormatter), and request filtering using SetFilter or WithHide.

Tokens
2.9K
Snippets
14
Records
15
Agent score
65%

What's inside httpretty

  1. Implement custom Formatters

    main
    To support custom media types, implement the httpretty.Formatter interface. This allows you to define how specific response or request bodies are pretty-printed. The package provides a httpretty.JSONFormatter which can be enabled in the logger configuration.
  2. Use httpretty on the server-side

    main

    To log incoming requests on a server, use the logger.Middleware method. This method accepts an http.Handler (such as your http.ServeMux) and wraps it to provide logging capabilities for all incoming requests.

    logger.Middleware(mux)
  3. Use httpretty on the client-side

    main

    To log outgoing HTTP requests from a client, wrap your http.RoundTripper using the logger.RoundTripper method. You can apply this to a custom http.Client or replace the http.DefaultClient.Transport to intercept all standard library HTTP calls.

    // Option 1: Using a custom client
    client := &http.Client{
    	Transport: logger.RoundTripper(http.DefaultTransport),
    }
    
    // Option 2: Replacing the default client transport
    http.DefaultClient.Transport = logger.RoundTripper(http.DefaultClient.Transport)
  4. Configure an httpretty Logger

    main

    Initialize an httpretty.Logger to control which parts of the HTTP exchange are printed to the terminal. You can toggle visibility for timestamps, TLS information, headers, and bodies, and enable colorized output. You can also attach Formatters to handle specific media types (like JSON).

    logger := &httpretty.Logger{
    	Time:           true,
    	TLS:            true,
    	RequestHeader:  true,
    	RequestBody:    true,
    	ResponseHeader: true,
    	ResponseBody:   true,
    	Colors:         true, // erase line if you don't like colors
    	Formatters:     []httpretty.Formatter{&httpretty.JSONFormatter{}},
    }
  5. Use httpretty as server-side middleware

    main

    To log incoming requests to your HTTP server, use the Logger.Middleware method. It wraps an http.Handler and uses a response recorder to capture and print the status code and body.

    Note: Server logs do not include response headers set by the server. Additionally, if a handler hijacks the connection (e.g., via http.Hijacker), the response bypasses the recorder and cannot be logged.

    logger := &httpretty.Logger{
    	Time:           true,
    	TLS:            true,
    	RequestHeader:  true,
    	RequestBody:    true,
    	ResponseHeader: true,
    	ResponseBody:   true,
    }
    
    // Wrap your handler
    http.Handle("/", logger.Middleware(myHandler))
  6. Filter requests using a custom Filter function

    main

    You can define global filtering logic for a logger by implementing a Filter function and assigning it via logger.SetFilter. A Filter returns true to skip logging the request or false to proceed with logging.

    type Filter func(req *http.Request) (skip bool, err error)
    
    logger.SetFilter(func filteredURIs(req *http.Request) (bool, error) {
    	if req.Method != http.MethodGet {
    		return true, nil
    	}
    
    	if path := req.URL.Path; path == "/debug" || strings.HasPrefix(path, "/debug/") {
    		return true, nil
    	}
    
    	return false
    })
  7. Filter requests using httpretty.WithHide

    main

    You can prevent a specific request from being logged by attaching a context to the request using httpretty.WithHide. This must be done before the request reaches the httpretty.RoundTripper.

    req = req.WithContext(httpretty.WithHide(ctx))
  8. Use JSONFormatter for pretty-printing JSON

    main

    JSONFormatter is a built-in implementation of the Formatter interface. It automatically detects JSON media types (like application/json or application/vnd.api+json) and indents the JSON content for readability.

    logger := &httpretty.Logger{
    	Formatters: []httpretty.Formatter{&httpretty.JSONFormatter{}},
    }
  9. Configure the httpretty Logger

    main

    The Logger struct is the central configuration object for httpretty. It allows you to control which parts of the HTTP traffic are printed (headers, bodies, TLS info, etc.) and how they are formatted.

    Key configuration fields include:

    • Time: Logs the request start time and duration.
    • TLS: Logs TLS information (certificates, ciphers).
    • RequestHeader / RequestBody: Controls logging of outgoing/incoming request details.
    • ResponseHeader / ResponseBody: Controls logging of incoming/outgoing response details.
    • Colors: Enables ANSI escape codes for terminal coloring.
    • Formatters: A slice of Formatter implementations to beautify bodies (e.g., JSONFormatter).
    • MaxRequestBody / MaxResponseBody: Limits the number of bytes logged for bodies.
    logger := &httpretty.Logger{
    	Time:           true,
    	TLS:            true,
    	RequestHeader:  true,
    	RequestBody:    true,
    	ResponseHeader: true,
    	ResponseBody:   true,
    	Colors:         true,
    	Formatters:     []httpretty.Formatter{&httpretty.JSONFormatter{}},
    }
  10. Hide requests from logging using WithHide

    main

    You can prevent specific requests from being logged by attaching a special value to the request's context using WithHide. This is useful for protecting sensitive requests from being exposed in logs.

    // Create a context that hides the request from httpretty
    ctx := httpretty.WithHide(context.Background())
    req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com/secret", nil)
    
    // This request will not be logged by the RoundTripper or Middleware
    client.Do(req)
  11. Access the underlying ResponseWriter with Unwrap()

    main

    Because responseRecorder wraps an existing http.ResponseWriter, it may hide specific interfaces implemented by the original writer (such as http.Flusher, http.Hijacker, http.Pusher, or deadline setters).

    Call Unwrap() to retrieve the original http.ResponseWriter. This allows you to use http.NewResponseController or type assertions to access those specialized interfaces.

    // Accessing the underlying writer to use specialized interfaces
    original := rr.Unwrap()
    
    // Example: using a ResponseController on the original writer
    controller := http.NewResponseController(original)
  12. Filter requests and bodies

    main

    The Logger provides mechanisms to skip logging based on request properties or body headers:

    • SetFilter(f Filter): Sets a function to skip entire requests. Filter receives *http.Request and returns (skip bool, err error).
    • SetBodyFilter(f BodyFilter): Sets a function to skip printing a body. BodyFilter receives http.Header and returns (skip bool, err error). This is useful for omitting bodies based on Content-Type or Content-Length.
    • SkipHeader(headers []string): Instructs the logger to skip printing specific header keys.
    // Skip all requests to a specific path
    logger.SetFilter(func(req *http.Request) (bool, error) {
    	return req.URL.Path == "/health", nil
    })
    
    // Skip printing the 'Authorization' header
    logger.SkipHeader([]string{"Authorization"})