refactors HTTP server initialization, improves logging middleware, and updates documentation (#1)

Reviewed-on: #1
This commit is contained in:
2025-08-24 15:50:34 +00:00
parent 92e78f533a
commit cb0c87d200
2 changed files with 27 additions and 10 deletions

View File

@@ -1,3 +1,6 @@
// Package http provides functionality for setting up and managing HTTP servers.
// It includes features for health checks, Prometheus metrics, OpenTelemetry
// tracing, and custom middleware integration.
package http
import (
@@ -133,8 +136,8 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
}
}
// Returns a shutdown func and a done channel if the
// server aborts abnormally. Returns error on failure to start
// InitHTTPServer returns a shutdown func and a done channel if the
// server aborts abnormally. Returns error on failure to start.
func InitHTTPServer(opts *opts.AppHTTP) (
func(context.Context) error, <-chan any, error,
) {

View File

@@ -3,7 +3,8 @@ package http
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"regexp"
"time"
@@ -41,29 +42,42 @@ func loggingMiddleware(appCtx context.Context, next http.Handler) http.Handler {
Dur("duration", time.Since(start)).
Msg("http request served")
// Log response body
// Log response with body if not 204
if lrr.statusCode == http.StatusNoContent {
trcLog := log.Trace().
Str("path", r.URL.Path).
Int("statusCode", lrr.statusCode)
trcLog.Msg("http response (no content)") // Explicitly log 204
return // No body to log for 204 No Content
}
trcLog := log.Trace().
Str("path", r.URL.Path).
Int("statusCode", lrr.statusCode)
// Check if it's JSON
firstByte, err := lrr.body.ReadByte()
if err != nil {
trcLog.Err(errors.New("invalid response body")).Send()
return
if err == io.EOF {
// Body is empty, which might be valid for some non-204 responses.
trcLog.Msg("http response (empty body)")
} else {
// Other error reading the body. Wrap the original error for context.
trcLog.Err(fmt.Errorf("error reading response body: %w", err)).Send()
}
return // No further body processing if there was an error or it was empty
}
lrr.body.UnreadByte()
lrr.body.UnreadByte() // Put the byte back for Bytes() to read
if firstByte == '{' {
trcLog = trcLog.RawJSON("response", lrr.body.Bytes())
} else {
trcLog = trcLog.Bytes("response", lrr.body.Bytes())
}
trcLog.Msg("response payload")
trcLog.Msg("http response")
})
}
// Implement Flush to support the http.Flusher interface
// Flush implements the http.Flusher interface to allow flushing buffered data.
func (w *LoggingResponseWriter) Flush() {
if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
flusher.Flush()