blob: b3fe3e5e9268c203fda8135f671bac2c5b1063c2 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2014 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package loggo
5
6import (
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.
17const DefaultWriterName = "default"
18
19// Writer is implemented by any recipient of log messages.
20type 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.
32func NewMinimumLevelWriter(writer Writer, minLevel Level) Writer {
33 return &minLevelWriter{
34 writer: writer,
35 level: minLevel,
36 }
37}
38
39type minLevelWriter struct {
40 writer Writer
41 level Level
42}
43
44// Write writes the log record.
45func (w minLevelWriter) Write(entry Entry) {
46 if entry.Level < w.level {
47 return
48 }
49 w.writer.Write(entry)
50}
51
52type 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.
59func 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
66func (simple *simpleWriter) Write(entry Entry) {
67 logLine := simple.formatter(entry)
68 fmt.Fprintln(simple.writer, logLine)
69}
70
71func defaultWriter() Writer {
72 return NewColorWriter(os.Stderr)
73}
74
75type colorWriter struct {
76 writer *ansiterm.Writer
77}
78
79var (
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.
98func NewColorWriter(writer io.Writer) Writer {
99 return &colorWriter{ansiterm.NewWriter(writer)}
100}
101
102// Write implements Writer.
103func (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}