httplog icon indicating copy to clipboard operation
httplog copied to clipboard

Make logger to print stack trace in file

Open stepanleas opened this issue 2 years ago • 0 comments

When an error with level panic occurs, it does not print the stack trace. It still appears in the terminal output, but is not written in the file.

{"timestamp":"2023-12-09T13:56:15.436815815+02:00","level":"ERROR","message":"Response: 500 Server Error - interface conversion: error is *fmt.wrapError, not *app_error.ApplicationError","service":"app-logger","httpRequest":{"url":"http://localhost:8000/api/v1/hotels","method":"GET","path":"/api/v1/hotels","remoteIP":"[::1]:50340","proto":"HTTP/1.1","requestID":"stepan-ThinkPad-L15-Gen-2/f8pOxWi02A-000002"},"stacktrace":"#","panic":"interface conversion: error is *fmt.wrapError, not *app_error.ApplicationError","httpResponse":{"status":500,"bytes":0,"elapsed":1.042674,"body":""}}

const YYYYMMDD = "2006-01-02"

func newLogger() *httplog.Logger {
	return httplog.NewLogger("app-logger", httplog.Options{
		JSON:             true,
		LogLevel:         slog.LevelError,
		Concise:          true,
		MessageFieldName: "message",
		Tags: map[string]string{
			"version": "v1.0-81aa4244d9fc8076a",
			"env":     "dev",
		},
		QuietDownRoutes: []string{
			"/",
			"/ping",
		},
		QuietDownPeriod: 10 * time.Second,
		Writer:          newWriter(),
	})
}

func newWriter() io.Writer {
	fileNamePath := fmt.Sprintf("logs/%s.log", time.Now().UTC().Format(YYYYMMDD))
	errorLogFile, err := os.OpenFile(fileNamePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("Error opening file: ", err)
	}

	return io.MultiWriter(os.Stdout, errorLogFile)
}

In httplog.go file there is this function:

func (l *RequestLoggerEntry) Panic(v interface{}, stack []byte) {
	stacktrace := "#"
	if l.Options.JSON {
		stacktrace = string(stack)
	}
	l.Logger = *l.Logger.With(
		slog.Attr{
			Key:   "stacktrace",
			Value: slog.StringValue(stacktrace)},
		slog.Attr{
			Key:   "panic",
			Value: slog.StringValue(fmt.Sprintf("%+v", v)),
		})

	l.msg = fmt.Sprintf("%+v", v)

	if !l.Options.JSON {
		middleware.PrintPrettyStack(v)
	}
}

I examined a bit and it seems that the l.Options are not the same that we passed to httplog.NewLogger function. They come from RequestLoggerEntry struct, not from Logger struct.

Is there a way to enable it that I don't know?

stepanleas avatar Dec 09 '23 12:12 stepanleas