rs/zerolog

Readable stack trace with cockroachdb/errors

nikitacrit opened this issue · 0 comments

Hi! I am trying to use cockroachdb/errors package with zerolog. I want to make multiline, readable, verbose stack trace output at the end of log message for local development. Any ideas of better implementation? Current is annoying couse of hard coded internal formatting values (colorization). I faced core problem in string quotating code that ruin line breaks and I see no possibility too use FormatFieldValue here.
String quotation code:

case string:
	if needsQuote(fValue) {
		buf.WriteString(fv(strconv.Quote(fValue)))
	} else {
		buf.WriteString(fv(fValue))
	}

Expected result:

2023-11-03T20:08:44.7548652+03:00 ERR error="cool error text" stack="
cool error text
(1) attached stack trace
  -- stack trace:
  | main.main
  | 	C:/Users/nikita/projects/test1/main.go:21
  | runtime.main
  | 	C:/Program Files/Go/src/runtime/proc.go:267
  | runtime.goexit
  | 	C:/Program Files/Go/src/runtime/asm_amd64.s:1650
Wraps: (2) cool error text
Error types: (1) *withstack.withStack (2) *errutil.leafError"

Implementation:

func main() {
	zerolog.TimeFieldFormat = time.RFC3339Nano
	zerolog.ErrorStackMarshaler = errStackMarshaller

	log.Logger = log.Output(beautifulWriter(os.Stderr))

	log.Error().Stack().Err(errors.New("cool error text")).Send()
}

func beautifulWriter(out io.Writer) zerolog.ConsoleWriter {
	return zerolog.ConsoleWriter{
		Out:           out,
		TimeFormat:    time.RFC3339Nano,
		FieldsExclude: []string{zerolog.ErrorStackFieldName},
		FormatExtra: func(fields map[string]any, buf *bytes.Buffer) error {
			stack, ok := fields[zerolog.ErrorStackFieldName]
			if !ok {
				return nil
			}

			s := fmt.Sprintf("\x1b[%dm %v=\x1b[0m\"\n%v\"", 36, zerolog.ErrorStackFieldName, stack)

			_, err := buf.WriteString(s)
			if err != nil {
				return err
			}

			return nil
		},
	}
}

func errStackMarshaller(err error) any {
	return fmt.Sprintf("%+v", err)
}