Skip to content

Instantly share code, notes, and snippets.

@turgayozgur
Last active August 14, 2019 12:25
Show Gist options
  • Save turgayozgur/057eee4fca80b61373f6b8abf84c6622 to your computer and use it in GitHub Desktop.
Save turgayozgur/057eee4fca80b61373f6b8abf84c6622 to your computer and use it in GitHub Desktop.
Golang custom logger that provides the request headers to log result.
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"runtime"
"time"
)
func main() {
http.Handle("/", errorHandler(index))
http.ListenAndServe(":8000", nil)
}
func index(w http.ResponseWriter, r *http.Request) {
panic("Something went wrong :/")
}
// Error Handler
type errorHandler func(http.ResponseWriter, *http.Request)
func (fn errorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := addHeadersForLogging(r) // Required to read headers from request context.
defer func() {
if rec := recover(); rec != nil {
logError(ctx, "Panic: %+v", rec)
w.WriteHeader(http.StatusInternalServerError)
}
}()
fn(w, r.WithContext(ctx))
}
// Error log
func logError(ctx context.Context, format string, v ...interface{}) {
// message
message := fmt.Sprintf(format, v...)
// headers
h := ctx.Value("logkey").(*Headers)
// stack trace
buf := make([]byte, 1024)
stackTrace := runtime.Stack(buf, true)
// log (use sync.Once for getting instance of new logger).
log.New(os.Stdout, "", 0).Printf("error: %s %s \"%s\"\n%s", time.Now().UTC().Format(time.RFC3339Nano), h.RequestID, message, buf[0:stackTrace])
}
// Headers contains header values to logging.
type Headers struct {
RequestID string
}
// AddHeaders will add any common HTTP headers
func addHeadersForLogging(r *http.Request) context.Context {
headers := &Headers{
RequestID: r.Header.Get("x-request-id"),
}
return context.WithValue(r.Context(), "logkey", headers)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment