@@ -93,9 +93,9 @@ type HandlerOptions struct {
9393}
9494
9595type commonHandler struct {
96- newAppender func (* buffer.Buffer ) appender
9796 opts HandlerOptions
98- attrs []Attr
97+ app appender
98+ attrSep byte // char separating attrs from each other
9999 preformattedAttrs []byte
100100 mu sync.Mutex
101101 w io.Writer
@@ -109,132 +109,162 @@ func (h *commonHandler) Enabled(l Level) bool {
109109
110110func (h * commonHandler ) with (as []Attr ) * commonHandler {
111111 h2 := & commonHandler {
112- newAppender : h .newAppender ,
112+ app : h .app ,
113+ attrSep : h .attrSep ,
113114 opts : h .opts ,
114- attrs : concat (h .attrs , as ),
115115 preformattedAttrs : h .preformattedAttrs ,
116116 w : h .w ,
117117 }
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-
124118 // 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 )
128126 }
129127 return h2
130128}
131129
132130func (h * commonHandler ) handle (r Record ) error {
133- buf := buffer .New ()
134- defer buf .Free ()
135- app := h .newAppender (buf )
136131 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
148136 if ! r .Time ().IsZero () {
149137 key := "time"
150138 val := r .Time ().Round (0 ) // strip monotonic to match Attr behavior
151139 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 )
156142 } else {
157- replace (Time (key , val ))
143+ state . appendAttr (Time (key , val ))
158144 }
159- app .appendSep ()
160145 }
146+ // level
161147 if r .Level () != 0 {
162148 key := "level"
163149 val := r .Level ()
164150 if rep == nil {
165- app .appendKey (key )
166- app .appendString (val .String ())
151+ state .appendKey (key )
152+ state .appendString (val .String ())
167153 } else {
168- replace (Any (key , val ))
154+ state . appendAttr (Any (key , val ))
169155 }
170- app .appendSep ()
171156 }
157+ // source
172158 if h .opts .AddSource {
173159 file , line := r .SourceLine ()
174160 if file != "" {
175161 key := "source"
176162 if rep == nil {
177- app .appendKey (key )
178- app .appendSource (file , line )
163+ state .appendKey (key )
164+ h . app .appendSource (state . buf , file , line )
179165 } else {
180166 buf := buffer .New ()
181- buf .WriteString (file )
167+ buf .WriteString (file ) // TODO: escape?
182168 buf .WriteByte (':' )
183169 itoa ((* []byte )(buf ), line , - 1 )
184170 s := buf .String ()
185171 buf .Free ()
186- replace (String (key , s ))
172+ state . appendAttr (String (key , s ))
187173 }
188- app .appendSep ()
189174 }
190175 }
176+ // message
191177 key := "msg"
192178 val := r .Message ()
193179 if rep == nil {
194- app .appendKey (key )
195- app .appendString (val )
180+ state .appendKey (key )
181+ state .appendString (val )
196182 } else {
197- replace (String (key , val ))
183+ state . appendAttr (String (key , val ))
198184 }
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
200191 r .Attrs (func (a Attr ) {
201- if rep != nil {
202- a = rep (a )
203- }
204- appendAttr (app , a )
192+ state .appendAttr (a )
205193 })
206- app .appendEnd ()
207- buf .WriteByte ('\n' )
194+ h . app .appendEnd (state . buf )
195+ state . buf .WriteByte ('\n' )
208196
209197 h .mu .Lock ()
210198 defer h .mu .Unlock ()
211- _ , err := h .w .Write (* buf )
199+ _ , err := h .w .Write (* state . buf )
212200 return err
213201}
214202
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 )
222220 }
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 ))
223230}
224231
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.
229232type 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+ }
238268}
239269
240270// This takes half the time of Time.AppendFormat.
0 commit comments