github.com/TBD54566975/ftl@v0.219.0/internal/log/plain.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "time" 8 9 "github.com/mattn/go-isatty" 10 ) 11 12 var colours = map[Level]string{ 13 Trace: "\x1b[90m", // Dark gray 14 Debug: "\x1b[34m", // Blue 15 Info: "\x1b[37m", // White 16 Warn: "\x1b[33m", // Yellow 17 Error: "\x1b[31m", // Red 18 } 19 20 var _ Sink = (*plainSink)(nil) 21 22 func newPlainSink(w io.Writer, logTime bool, alwaysColor bool) *plainSink { 23 var isaTTY bool 24 if alwaysColor { 25 isaTTY = true 26 } else if f, ok := w.(*os.File); ok { 27 isaTTY = isatty.IsTerminal(f.Fd()) 28 } 29 return &plainSink{ 30 isaTTY: isaTTY, 31 w: w, 32 logTime: logTime, 33 } 34 } 35 36 type plainSink struct { 37 isaTTY bool 38 w io.Writer 39 logTime bool 40 } 41 42 // Log implements Sink 43 func (t *plainSink) Log(entry Entry) error { 44 var prefix string 45 46 // Add timestamp if required 47 if t.logTime { 48 prefix += entry.Time.Format(time.TimeOnly) + " " 49 } 50 51 // Add scope if required 52 scope, exists := entry.Attributes[scopeKey] 53 if exists { 54 prefix += entry.Level.String() + ":" + scope + ": " 55 } else { 56 prefix += entry.Level.String() + ": " 57 } 58 59 // Print 60 var err error 61 if t.isaTTY { 62 _, err = fmt.Fprintf(t.w, "%s%s%s\x1b[0m\n", colours[entry.Level], prefix, entry.Message) 63 } else { 64 _, err = fmt.Fprintf(t.w, "%s%s\n", prefix, entry.Message) 65 } 66 if err != nil { 67 return err 68 } 69 return nil 70 }