How to log only errors like 404 with chi in go?

1.1k Views Asked by At

I'm using chi with our Go webservices.

How to configure the logger (middleware) so it only logs requests that ended up with errors (like 404) but it doesn't log successful requests (with status code 200)?

Here's our current implementation (with no logging at all)

r := chi.NewRouter()

if DEBUG_LOGS {
    r.Use(middleware.Logger)
} else {

}
1

There are 1 best solutions below

0
On BEST ANSWER

The easiest way is to implement the logging function by yourself using the example from the chi package (for simplicity, I removed the colors).

package main

import (
    "bytes"
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
)

const DEBUG_LOGS = true

func main() {
    api := &http.Server{Addr: ":8000"}

    r := chi.NewRouter()

    if DEBUG_LOGS {
        // create default logger/zerolog/logrus
        logger := log.New(os.Stdout, "", log.LstdFlags)
        r.Use(middleware.RequestLogger(&StructuredLogger{logger}))
    }

    r.Get("/tea", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusTeapot) })
    r.Get("/ok", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })

    api.Handler = r

    err := api.ListenAndServe()
    if err != nil {
        log.Fatal(err)
    }
}

// below is the implementation of the custom logger.

type StructuredLogger struct {
    Logger middleware.LoggerInterface
}

type LogEntry struct {
    *StructuredLogger
    request  *http.Request
    buf      *bytes.Buffer
    useColor bool
}

func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
    entry := &LogEntry{
        StructuredLogger: l,
        request:          r,
        buf:              &bytes.Buffer{},
        useColor:         false,
    }

    reqID := middleware.GetReqID(r.Context())
    if reqID != "" {
        fmt.Fprintf(entry.buf, "[%s] ", reqID)
    }

    fmt.Fprintf(entry.buf, "\"")
    fmt.Fprintf(entry.buf, "%s ", r.Method)

    scheme := "http"
    if r.TLS != nil {
        scheme = "https"
    }
    fmt.Fprintf(entry.buf, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto)

    entry.buf.WriteString("from ")
    entry.buf.WriteString(r.RemoteAddr)
    entry.buf.WriteString(" - ")

    return entry
}

func (l *LogEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) {
    // Do nothing if status code is 200/201/eg
    if status < 300 {
        return
    }

    fmt.Fprintf(l.buf, "%03d", status)
    fmt.Fprintf(l.buf, " %dB", bytes)

    l.buf.WriteString(" in ")
    if elapsed < 500*time.Millisecond {
        fmt.Fprintf(l.buf, "%s", elapsed)
    } else if elapsed < 5*time.Second {
        fmt.Fprintf(l.buf, "%s", elapsed)
    } else {
        fmt.Fprintf(l.buf, "%s", elapsed)
    }

    l.Logger.Print(l.buf.String())
}

func (l *LogEntry) Panic(v interface{}, stack []byte) {
    middleware.PrintPrettyStack(v)
}