OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / sirupsen / logrus / text_formatter.go
1 package logrus
2
3 import (
4         "bytes"
5         "fmt"
6         "io"
7         "os"
8         "sort"
9         "strings"
10         "sync"
11         "time"
12
13         "golang.org/x/crypto/ssh/terminal"
14 )
15
16 const (
17         nocolor = 0
18         red     = 31
19         green   = 32
20         yellow  = 33
21         blue    = 36
22         gray    = 37
23 )
24
25 var (
26         baseTimestamp time.Time
27 )
28
29 func init() {
30         baseTimestamp = time.Now()
31 }
32
33 // TextFormatter formats logs into text
34 type TextFormatter struct {
35         // Set to true to bypass checking for a TTY before outputting colors.
36         ForceColors bool
37
38         // Force disabling colors.
39         DisableColors bool
40
41         // Disable timestamp logging. useful when output is redirected to logging
42         // system that already adds timestamps.
43         DisableTimestamp bool
44
45         // Enable logging the full timestamp when a TTY is attached instead of just
46         // the time passed since beginning of execution.
47         FullTimestamp bool
48
49         // TimestampFormat to use for display when a full timestamp is printed
50         TimestampFormat string
51
52         // The fields are sorted by default for a consistent output. For applications
53         // that log extremely frequently and don't use the JSON formatter this may not
54         // be desired.
55         DisableSorting bool
56
57         // QuoteEmptyFields will wrap empty fields in quotes if true
58         QuoteEmptyFields bool
59
60         // Whether the logger's out is to a terminal
61         isTerminal bool
62
63         sync.Once
64 }
65
66 func (f *TextFormatter) init(entry *Entry) {
67         if entry.Logger != nil {
68                 f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
69         }
70 }
71
72 func (f *TextFormatter) checkIfTerminal(w io.Writer) bool {
73         switch v := w.(type) {
74         case *os.File:
75                 return terminal.IsTerminal(int(v.Fd()))
76         default:
77                 return false
78         }
79 }
80
81 // Format renders a single log entry
82 func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
83         var b *bytes.Buffer
84         keys := make([]string, 0, len(entry.Data))
85         for k := range entry.Data {
86                 keys = append(keys, k)
87         }
88
89         if !f.DisableSorting {
90                 sort.Strings(keys)
91         }
92         if entry.Buffer != nil {
93                 b = entry.Buffer
94         } else {
95                 b = &bytes.Buffer{}
96         }
97
98         prefixFieldClashes(entry.Data)
99
100         f.Do(func() { f.init(entry) })
101
102         isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
103
104         timestampFormat := f.TimestampFormat
105         if timestampFormat == "" {
106                 timestampFormat = defaultTimestampFormat
107         }
108         if isColored {
109                 f.printColored(b, entry, keys, timestampFormat)
110         } else {
111                 if !f.DisableTimestamp {
112                         f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
113                 }
114                 f.appendKeyValue(b, "level", entry.Level.String())
115                 if entry.Message != "" {
116                         f.appendKeyValue(b, "msg", entry.Message)
117                 }
118                 for _, key := range keys {
119                         f.appendKeyValue(b, key, entry.Data[key])
120                 }
121         }
122
123         b.WriteByte('\n')
124         return b.Bytes(), nil
125 }
126
127 func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
128         var levelColor int
129         switch entry.Level {
130         case DebugLevel:
131                 levelColor = gray
132         case WarnLevel:
133                 levelColor = yellow
134         case ErrorLevel, FatalLevel, PanicLevel:
135                 levelColor = red
136         default:
137                 levelColor = blue
138         }
139
140         levelText := strings.ToUpper(entry.Level.String())[0:4]
141
142         if f.DisableTimestamp {
143                 fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
144         } else if !f.FullTimestamp {
145                 fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
146         } else {
147                 fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
148         }
149         for _, k := range keys {
150                 v := entry.Data[k]
151                 fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
152                 f.appendValue(b, v)
153         }
154 }
155
156 func (f *TextFormatter) needsQuoting(text string) bool {
157         if f.QuoteEmptyFields && len(text) == 0 {
158                 return true
159         }
160         for _, ch := range text {
161                 if !((ch >= 'a' && ch <= 'z') ||
162                         (ch >= 'A' && ch <= 'Z') ||
163                         (ch >= '0' && ch <= '9') ||
164                         ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
165                         return true
166                 }
167         }
168         return false
169 }
170
171 func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
172         if b.Len() > 0 {
173                 b.WriteByte(' ')
174         }
175         b.WriteString(key)
176         b.WriteByte('=')
177         f.appendValue(b, value)
178 }
179
180 func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
181         stringVal, ok := value.(string)
182         if !ok {
183                 stringVal = fmt.Sprint(value)
184         }
185
186         if !f.needsQuoting(stringVal) {
187                 b.WriteString(stringVal)
188         } else {
189                 b.WriteString(fmt.Sprintf("%q", stringVal))
190         }
191 }