@@ -93,9 +93,9 @@ type HandlerOptions struct {
93
93
}
94
94
95
95
type commonHandler struct {
96
- newAppender func (* buffer.Buffer ) appender
97
96
opts HandlerOptions
98
- attrs []Attr
97
+ app appender
98
+ attrSep byte // char separating attrs from each other
99
99
preformattedAttrs []byte
100
100
mu sync.Mutex
101
101
w io.Writer
@@ -109,132 +109,162 @@ func (h *commonHandler) Enabled(l Level) bool {
109
109
110
110
func (h * commonHandler ) with (as []Attr ) * commonHandler {
111
111
h2 := & commonHandler {
112
- newAppender : h .newAppender ,
112
+ app : h .app ,
113
+ attrSep : h .attrSep ,
113
114
opts : h .opts ,
114
- attrs : concat (h .attrs , as ),
115
115
preformattedAttrs : h .preformattedAttrs ,
116
116
w : h .w ,
117
117
}
118
- if h .opts .ReplaceAttr != nil {
119
- for i , p := range h2 .attrs [len (h .attrs ):] {
120
- h2 .attrs [i ] = h .opts .ReplaceAttr (p )
121
- }
122
- }
123
-
124
118
// Pre-format the attributes as an optimization.
125
- app := h2 .newAppender ((* buffer .Buffer )(& h2 .preformattedAttrs ))
126
- for _ , p := range h2 .attrs [len (h .attrs ):] {
127
- appendAttr (app , p )
119
+ state := handleState {
120
+ h2 ,
121
+ (* buffer .Buffer )(& h2 .preformattedAttrs ),
122
+ false ,
123
+ }
124
+ for _ , a := range as {
125
+ state .appendAttr (a )
128
126
}
129
127
return h2
130
128
}
131
129
132
130
func (h * commonHandler ) handle (r Record ) error {
133
- buf := buffer .New ()
134
- defer buf .Free ()
135
- app := h .newAppender (buf )
136
131
rep := h .opts .ReplaceAttr
137
- replace := func (a Attr ) {
138
- a = rep (a )
139
- if a .Key () != "" {
140
- app .appendKey (a .Key ())
141
- if err := app .appendAttrValue (a ); err != nil {
142
- app .appendString (fmt .Sprintf ("!ERROR:%v" , err ))
143
- }
144
- }
145
- }
146
-
147
- app .appendStart ()
132
+ state := handleState {h , buffer .New (), false }
133
+ defer state .buf .Free ()
134
+ h .app .appendStart (state .buf )
135
+ // time
148
136
if ! r .Time ().IsZero () {
149
137
key := "time"
150
138
val := r .Time ().Round (0 ) // strip monotonic to match Attr behavior
151
139
if rep == nil {
152
- app .appendKey (key )
153
- if err := app .appendTime (val ); err != nil {
154
- return err
155
- }
140
+ state .appendKey (key )
141
+ state .appendTime (val )
156
142
} else {
157
- replace (Time (key , val ))
143
+ state . appendAttr (Time (key , val ))
158
144
}
159
- app .appendSep ()
160
145
}
146
+ // level
161
147
if r .Level () != 0 {
162
148
key := "level"
163
149
val := r .Level ()
164
150
if rep == nil {
165
- app .appendKey (key )
166
- app .appendString (val .String ())
151
+ state .appendKey (key )
152
+ state .appendString (val .String ())
167
153
} else {
168
- replace (Any (key , val ))
154
+ state . appendAttr (Any (key , val ))
169
155
}
170
- app .appendSep ()
171
156
}
157
+ // source
172
158
if h .opts .AddSource {
173
159
file , line := r .SourceLine ()
174
160
if file != "" {
175
161
key := "source"
176
162
if rep == nil {
177
- app .appendKey (key )
178
- app .appendSource (file , line )
163
+ state .appendKey (key )
164
+ h . app .appendSource (state . buf , file , line )
179
165
} else {
180
166
buf := buffer .New ()
181
- buf .WriteString (file )
167
+ buf .WriteString (file ) // TODO: escape?
182
168
buf .WriteByte (':' )
183
169
itoa ((* []byte )(buf ), line , - 1 )
184
170
s := buf .String ()
185
171
buf .Free ()
186
- replace (String (key , s ))
172
+ state . appendAttr (String (key , s ))
187
173
}
188
- app .appendSep ()
189
174
}
190
175
}
176
+ // message
191
177
key := "msg"
192
178
val := r .Message ()
193
179
if rep == nil {
194
- app .appendKey (key )
195
- app .appendString (val )
180
+ state .appendKey (key )
181
+ state .appendString (val )
196
182
} else {
197
- replace (String (key , val ))
183
+ state . appendAttr (String (key , val ))
198
184
}
199
- * buf = append (* buf , h .preformattedAttrs ... )
185
+ // preformatted Attrs
186
+ if len (h .preformattedAttrs ) > 0 {
187
+ state .appendSep ()
188
+ state .buf .Write (h .preformattedAttrs )
189
+ }
190
+ // Attrs in Record
200
191
r .Attrs (func (a Attr ) {
201
- if rep != nil {
202
- a = rep (a )
203
- }
204
- appendAttr (app , a )
192
+ state .appendAttr (a )
205
193
})
206
- app .appendEnd ()
207
- buf .WriteByte ('\n' )
194
+ h . app .appendEnd (state . buf )
195
+ state . buf .WriteByte ('\n' )
208
196
209
197
h .mu .Lock ()
210
198
defer h .mu .Unlock ()
211
- _ , err := h .w .Write (* buf )
199
+ _ , err := h .w .Write (* state . buf )
212
200
return err
213
201
}
214
202
215
- func appendAttr (app appender , a Attr ) {
216
- if a .Key () != "" {
217
- app .appendSep ()
218
- app .appendKey (a .Key ())
219
- if err := app .appendAttrValue (a ); err != nil {
220
- app .appendString (fmt .Sprintf ("!ERROR:%v" , err ))
221
- }
203
+ // handleState holds state for a single call to commonHandler.handle.
204
+ // The initial value of sep determines whether to emit a separator
205
+ // before the next key, after which it stays true.
206
+ type handleState struct {
207
+ h * commonHandler
208
+ buf * buffer.Buffer
209
+ sep bool // Append separator before next Attr?
210
+ }
211
+
212
+ // appendAttr appends the Attr's key and value using app.
213
+ // If sep is true, it also prepends a separator.
214
+ // It handles replacement and checking for an empty key.
215
+ // It sets sep to true if it actually did the append (if the key was non-empty
216
+ // after replacement).
217
+ func (s * handleState ) appendAttr (a Attr ) {
218
+ if rep := s .h .opts .ReplaceAttr ; rep != nil {
219
+ a = rep (a )
222
220
}
221
+ if a .Key () == "" {
222
+ return
223
+ }
224
+ s .appendKey (a .Key ())
225
+ s .appendAttrValue (a )
226
+ }
227
+
228
+ func (s * handleState ) appendError (err error ) {
229
+ s .appendString (fmt .Sprintf ("!ERROR:%v" , err ))
223
230
}
224
231
225
- // An appender appends keys and values to a buffer.
226
- // TextHandler and JSONHandler both implement it.
227
- // It factors out the format-specific parts of the job.
228
- // Other than growing the buffer, none of the methods should allocate.
229
232
type appender interface {
230
- appendStart () // start a sequence of Attrs
231
- appendEnd () // end a sequence of Attrs
232
- appendSep () // separate one Attr from the next
233
- appendKey (key string ) // append a key
234
- appendString (string ) // append a string that may need to be escaped
235
- appendTime (time.Time ) error // append a time
236
- appendSource (file string , line int ) // append file:line
237
- appendAttrValue (a Attr ) error // append the Attr's value (but not its key)
233
+ appendStart (* buffer.Buffer ) // start of output
234
+ appendEnd (* buffer.Buffer ) // end of output
235
+ appendKey (* buffer.Buffer , string ) // append key and key-value separator
236
+ appendString (* buffer.Buffer , string ) // append a string
237
+ appendSource (* buffer.Buffer , string , int ) // append a filename and line
238
+ appendTime (* buffer.Buffer , time.Time ) error // append a time
239
+ appendAttrValue (* buffer.Buffer , Attr ) error // append Attr's value (but not key)
240
+ }
241
+
242
+ func (s * handleState ) appendSep () {
243
+ if s .sep {
244
+ s .buf .WriteByte (s .h .attrSep )
245
+ }
246
+ }
247
+
248
+ func (s * handleState ) appendKey (key string ) {
249
+ s .appendSep ()
250
+ s .h .app .appendKey (s .buf , key )
251
+ s .sep = true
252
+ }
253
+
254
+ func (s * handleState ) appendString (str string ) {
255
+ s .h .app .appendString (s .buf , str )
256
+ }
257
+
258
+ func (s * handleState ) appendAttrValue (a Attr ) {
259
+ if err := s .h .app .appendAttrValue (s .buf , a ); err != nil {
260
+ s .appendError (err )
261
+ }
262
+ }
263
+
264
+ func (s * handleState ) appendTime (t time.Time ) {
265
+ if err := s .h .app .appendTime (s .buf , t ); err != nil {
266
+ s .appendError (err )
267
+ }
238
268
}
239
269
240
270
// This takes half the time of Time.AppendFormat.
0 commit comments