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 package http
import ( import (
@@ -133,8 +136,8 @@ func prepHTTPServer(opts *opts.AppHTTP) *http.Server {
} }
} }
// Returns a shutdown func and a done channel if the // InitHTTPServer returns a shutdown func and a done channel if the
// server aborts abnormally. Returns error on failure to start // server aborts abnormally. Returns error on failure to start.
func InitHTTPServer(opts *opts.AppHTTP) ( func InitHTTPServer(opts *opts.AppHTTP) (
func(context.Context) error, <-chan any, error, func(context.Context) error, <-chan any, error,
) { ) {

View File

@@ -3,7 +3,8 @@ package http
import ( import (
"bytes" "bytes"
"context" "context"
"errors" "fmt"
"io"
"net/http" "net/http"
"regexp" "regexp"
"time" "time"
@@ -41,29 +42,42 @@ func loggingMiddleware(appCtx context.Context, next http.Handler) http.Handler {
Dur("duration", time.Since(start)). Dur("duration", time.Since(start)).
Msg("http request served") 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(). trcLog := log.Trace().
Str("path", r.URL.Path). Str("path", r.URL.Path).
Int("statusCode", lrr.statusCode) Int("statusCode", lrr.statusCode)
// Check if it's JSON
firstByte, err := lrr.body.ReadByte() firstByte, err := lrr.body.ReadByte()
if err != nil { if err != nil {
trcLog.Err(errors.New("invalid response body")).Send() if err == io.EOF {
return // 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 == '{' { if firstByte == '{' {
trcLog = trcLog.RawJSON("response", lrr.body.Bytes()) trcLog = trcLog.RawJSON("response", lrr.body.Bytes())
} else { } else {
trcLog = trcLog.Bytes("response", lrr.body.Bytes()) 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() { func (w *LoggingResponseWriter) Flush() {
if flusher, ok := w.ResponseWriter.(http.Flusher); ok { if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
flusher.Flush() flusher.Flush()