-
Notifications
You must be signed in to change notification settings - Fork 1
/
interface.go
219 lines (209 loc) · 6.3 KB
/
interface.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package message
import (
"github.com/cdr/grip/level"
)
// Composer defines an interface with a "String()" method that
// returns the message in string format. Objects that implement this
// interface, in combination to the Compose[*] operations, the
// String() method is only caled if the priority of the method is
// greater than the threshold priority. This makes it possible to
// defer building log messages (that may be somewhat expensive to
// generate) until it's certain that we're going to be outputting the
// message.
type Composer interface {
// Returns the content of the message as a string for use in
// line-printing logging engines.
String() string
// A "raw" format of the logging output for use by some Sender
// implementations that write logged items to interfaces that
// accept JSON or another structured format.
Raw() interface{}
// Returns "true" when the message has content and should be
// logged, and false otherwise. When false, the sender can
// (and should!) ignore messages even if they are otherwise
// above the logging threshold.
Loggable() bool
// Annotate makes it possible for Senders and Journalers to
// add structured data to a log message. May return an error
// when the key alrady exists.
Annotate(string, interface{}) error
// Priority returns the priority of the message.
Priority() level.Priority
SetPriority(level.Priority) error
}
// ConvertToComposer can coerce unknown objects into Composer
// instances, as possible. This method will override the priority of
// composers set to it.
func ConvertToComposer(p level.Priority, message interface{}) Composer {
return convert(p, message, true)
}
// ConvertToComposerWithLevel can coerce unknown objects into
// Composers, but will only override the priority of Composers.
func ConvertToComposerWithLevel(p level.Priority, message interface{}) Composer {
return convert(p, message, false)
}
func convert(p level.Priority, message interface{}, overRideLevel bool) Composer {
switch message := message.(type) {
case Composer:
if overRideLevel || message.Priority() != level.Invalid {
_ = message.SetPriority(p)
}
return message
case []Composer:
out := NewGroupComposer(message)
// this only sets constituent
// messages priority when its not otherwise set.
_ = out.SetPriority(p)
return out
case string:
return NewDefaultMessage(p, message)
case error:
return NewErrorMessage(p, message)
case FieldsProducer:
return NewFieldsProducerMessage(p, message)
case func() Fields:
return NewFieldsProducerMessage(p, message)
case ComposerProducer:
return NewComposerProducerMessage(p, message)
case func() Composer:
return NewComposerProducerMessage(p, message)
case func() map[string]interface{}:
return NewConvertedFieldsProducer(p, message)
case ErrorProducer:
return NewErrorProducerMessage(p, message)
case func() error:
return NewErrorProducerMessage(p, message)
case []string:
return newLinesFromStrings(p, message)
case []interface{}:
return NewLineMessage(p, message...)
case []byte:
return NewBytesMessage(p, message)
case Fields:
return NewFields(p, message)
case map[string]interface{}:
return NewFields(p, Fields(message))
case [][]string:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = newLinesFromStrings(p, message[idx])
}
return NewGroupComposer(grp)
case [][]byte:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewBytesMessage(p, message[idx])
}
return NewGroupComposer(grp)
case []map[string]interface{}:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewFields(p, message[idx])
}
out := NewGroupComposer(grp)
return out
case []Fields:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewFields(p, message[idx])
}
out := NewGroupComposer(grp)
return out
case []FieldsProducer:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewFieldsProducerMessage(p, message[idx])
}
return NewGroupComposer(grp)
case []func() Fields:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewFieldsProducerMessage(p, message[idx])
}
return NewGroupComposer(grp)
case []func() map[string]interface{}:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewConvertedFieldsProducer(p, message[idx])
}
return NewGroupComposer(grp)
case []ComposerProducer:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewComposerProducerMessage(p, message[idx])
}
return NewGroupComposer(grp)
case []func() Composer:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewComposerProducerMessage(p, message[idx])
}
return NewGroupComposer(grp)
case []ErrorProducer:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewErrorProducerMessage(p, message[idx])
}
return NewGroupComposer(grp)
case []func() error:
grp := make([]Composer, len(message))
for idx := range message {
grp[idx] = NewErrorProducerMessage(p, message[idx])
}
return NewGroupComposer(grp)
case nil:
return NewLineMessage(p)
default:
return NewFormattedMessage(p, "%+v", message)
}
}
// IsStructured returns false if the Composer has a string form which
// is merely a representation of the structured form.
//
// Additionally, returns true for all unknown types, including all types not
// produced by this package.
func IsStructured(msg Composer) bool {
switch m := msg.(type) {
case *stringMessage:
return false
case *formatMessenger:
return false
case *lineMessenger:
return false
case *bytesMessage:
return false
case *SystemInfo:
return true
case *ProcessInfo:
return true
case *GoRuntimeInfo:
return true
case *jiraMessage:
return true
case *jiraComment:
return false
case *githubStatusMessage:
return true
case *errorMessage:
return true
case *emailMessage:
return true
case *fieldMessage:
return true
case *GroupComposer:
return true
case *fieldsProducerMessage:
m.resolve()
return IsStructured(m.cached)
case *composerProducerMessage:
m.resolve()
return IsStructured(m.cached)
case *errorProducerMessage:
m.resolve()
return IsStructured(m.cached)
case errorComposerShim:
return IsStructured(m.Composer)
default:
return true
}
}