Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multiwriter file logging #77

Closed
yusufaine opened this issue Oct 19, 2023 · 4 comments
Closed

multiwriter file logging #77

yusufaine opened this issue Oct 19, 2023 · 4 comments

Comments

@yusufaine
Copy link

I'm glad that #71 fixed the colour issue, but was wondering if there was a way to allow logging to a file without said colour tags.

I currently have a logger setup like this:

writers := []io.Writer{os.Stderr}
if (logFile != "") {
    // open file
    writers = append(writers, fd)
}

ml := log.NewWithOptions(io.MultiWriter(wrs...), loggerOpts)
ml.SetColorProfile(termenv.TrueColor)
log.SetDefault(ml)

but the log file outputs as

�[1;38;5;86mINFO�[0m �[2m<crawler/crawler.go:68>�[0m visiting �[2mdepth�[0m�[2m=�[0m0 �[2mlink�[0m�[2m=�[0mhttps://example.com
�[1;38;5;86mINFO�[0m �[2m<crawler/crawler.go:68>�[0m visiting �[2mdepth�[0m�[2m=�[0m1 �[2mlink�[0m�[2m=�[0mhttps://www.iana.org/domains/example
�[1;38;5;86mINFO�[0m �[2m<crawler/crawler.go:68>�[0m visiting �[2mdepth�[0m�[2m=�[0m2 �

image

@aymanbagabas
Copy link
Member

Hi @yusufaine, Log is meant to be used with one writer. Using SetColorProfile overrides the detected profile for the writer. Thus, using an io.MultiWriter will always disable the colors since the writer is not a terminal. Instead, you could wrap Log in a custom type that takes multiple writers and assigns each to its logger instance.

With this, if io.Writer is not a terminal, colors will be disabled.

type MultiLogger struct {
  writers []io.Writer
  loggers []*log.Logger
}

func NewMultiLogger(wrs ...io.Writer) *MultiLogger {
  ml := new(MultiLogger)
  ml.writers = make([]io.Writer, len(wrs))
  ml.loggers = make([]*log.Logger, len(wrs))
  for i, w := range wrs {
    ml.writer[i] = w
    ml.loggers[i] = log.New(w)
  }
  return ml
}

func (ml *MultiLogger) Info(msg any, kvs ...any) {
  for _, l := range ml.loggers {
    l.Info(msg, kvs...)
  }
}

@yusufaine
Copy link
Author

yusufaine commented Oct 23, 2023

Ah, I see... I've implemented a similar solution as well, thanks for this!

@cooperspencer
Copy link

I'd have a question for this specific approach, how'd you handle a log.Fatal here?

Because if I run a log.Fatal it would only write to one io.Writer

@yusufaine
Copy link
Author

@cooperspencer A similar approach can be taken, iterate over the loggers with error severity and os.Exit(1) after all the iterations, similar to how it's already implemented.

https://github.com/charmbracelet/log/blob/main/logger.go#L371

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants