David K. Bainbridge | 528b318 | 2017-01-23 08:51:59 -0800 | [diff] [blame] | 1 | // Copyright 2014 Canonical Ltd. |
| 2 | // Licensed under the LGPLv3, see LICENCE file for details. |
| 3 | |
| 4 | package loggo |
| 5 | |
| 6 | import ( |
| 7 | "fmt" |
| 8 | "io" |
| 9 | "os" |
| 10 | "path/filepath" |
| 11 | |
| 12 | "github.com/juju/ansiterm" |
| 13 | ) |
| 14 | |
| 15 | // DefaultWriterName is the name of the default writer for |
| 16 | // a Context. |
| 17 | const DefaultWriterName = "default" |
| 18 | |
| 19 | // Writer is implemented by any recipient of log messages. |
| 20 | type Writer interface { |
| 21 | // Write writes a message to the Writer with the given level and module |
| 22 | // name. The filename and line hold the file name and line number of the |
| 23 | // code that is generating the log message; the time stamp holds the time |
| 24 | // the log message was generated, and message holds the log message |
| 25 | // itself. |
| 26 | Write(entry Entry) |
| 27 | } |
| 28 | |
| 29 | // NewMinLevelWriter returns a Writer that will only pass on the Write calls |
| 30 | // to the provided writer if the log level is at or above the specified |
| 31 | // minimum level. |
| 32 | func NewMinimumLevelWriter(writer Writer, minLevel Level) Writer { |
| 33 | return &minLevelWriter{ |
| 34 | writer: writer, |
| 35 | level: minLevel, |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | type minLevelWriter struct { |
| 40 | writer Writer |
| 41 | level Level |
| 42 | } |
| 43 | |
| 44 | // Write writes the log record. |
| 45 | func (w minLevelWriter) Write(entry Entry) { |
| 46 | if entry.Level < w.level { |
| 47 | return |
| 48 | } |
| 49 | w.writer.Write(entry) |
| 50 | } |
| 51 | |
| 52 | type simpleWriter struct { |
| 53 | writer io.Writer |
| 54 | formatter func(entry Entry) string |
| 55 | } |
| 56 | |
| 57 | // NewSimpleWriter returns a new writer that writes log messages to the given |
| 58 | // io.Writer formatting the messages with the given formatter. |
| 59 | func NewSimpleWriter(writer io.Writer, formatter func(entry Entry) string) Writer { |
| 60 | if formatter == nil { |
| 61 | formatter = DefaultFormatter |
| 62 | } |
| 63 | return &simpleWriter{writer, formatter} |
| 64 | } |
| 65 | |
| 66 | func (simple *simpleWriter) Write(entry Entry) { |
| 67 | logLine := simple.formatter(entry) |
| 68 | fmt.Fprintln(simple.writer, logLine) |
| 69 | } |
| 70 | |
| 71 | func defaultWriter() Writer { |
| 72 | return NewColorWriter(os.Stderr) |
| 73 | } |
| 74 | |
| 75 | type colorWriter struct { |
| 76 | writer *ansiterm.Writer |
| 77 | } |
| 78 | |
| 79 | var ( |
| 80 | // SeverityColor defines the colors for the levels output by the ColorWriter. |
| 81 | SeverityColor = map[Level]*ansiterm.Context{ |
| 82 | TRACE: ansiterm.Foreground(ansiterm.Default), |
| 83 | DEBUG: ansiterm.Foreground(ansiterm.Green), |
| 84 | INFO: ansiterm.Foreground(ansiterm.BrightBlue), |
| 85 | WARNING: ansiterm.Foreground(ansiterm.Yellow), |
| 86 | ERROR: ansiterm.Foreground(ansiterm.BrightRed), |
| 87 | CRITICAL: &ansiterm.Context{ |
| 88 | Foreground: ansiterm.White, |
| 89 | Background: ansiterm.Red, |
| 90 | }, |
| 91 | } |
| 92 | // LocationColor defines the colors for the location output by the ColorWriter. |
| 93 | LocationColor = ansiterm.Foreground(ansiterm.BrightBlue) |
| 94 | ) |
| 95 | |
| 96 | // NewColorWriter will write out colored severity levels if the writer is |
| 97 | // outputting to a terminal. |
| 98 | func NewColorWriter(writer io.Writer) Writer { |
| 99 | return &colorWriter{ansiterm.NewWriter(writer)} |
| 100 | } |
| 101 | |
| 102 | // Write implements Writer. |
| 103 | func (w *colorWriter) Write(entry Entry) { |
| 104 | ts := formatTime(entry.Timestamp) |
| 105 | // Just get the basename from the filename |
| 106 | filename := filepath.Base(entry.Filename) |
| 107 | |
| 108 | fmt.Fprintf(w.writer, "%s ", ts) |
| 109 | SeverityColor[entry.Level].Fprintf(w.writer, entry.Level.Short()) |
| 110 | fmt.Fprintf(w.writer, " %s ", entry.Module) |
| 111 | LocationColor.Fprintf(w.writer, "%s:%d ", filename, entry.Line) |
| 112 | fmt.Fprintln(w.writer, entry.Message) |
| 113 | } |