@@ -11,7 +11,6 @@ import (
1111 "errors"
1212 "fmt"
1313 "io"
14- "log/slog/internal/buffer"
1514 "strconv"
1615 "sync"
1716 "time"
@@ -113,7 +112,7 @@ func appendJSONValue(s *handleState, v Value) error {
113112 // json.Marshal is funny about floats; it doesn't
114113 // always match strconv.AppendFloat. So just call it.
115114 // That's expensive, but floats are rare.
116- if err := appendJSONMarshal (s . buf , v .Float64 ()); err != nil {
115+ if err := appendJSONMarshal (s , v .Float64 ()); err != nil {
117116 return err
118117 }
119118 case KindBool :
@@ -129,27 +128,71 @@ func appendJSONValue(s *handleState, v Value) error {
129128 if err , ok := a .(error ); ok && ! jm {
130129 s .appendString (err .Error ())
131130 } else {
132- return appendJSONMarshal (s . buf , a )
131+ return appendJSONMarshal (s , a )
133132 }
134133 default :
135134 panic (fmt .Sprintf ("bad kind: %s" , v .Kind ()))
136135 }
137136 return nil
138137}
139138
140- func appendJSONMarshal (buf * buffer.Buffer , v any ) error {
141- // Use a json.Encoder to avoid escaping HTML.
142- var bb bytes.Buffer
143- enc := json .NewEncoder (& bb )
144- enc .SetEscapeHTML (false )
139+ func appendJSONMarshal (s * handleState , v any ) error {
140+ // Aquire a new encoder if not asigned.
141+ if s .anyEncoder == nil {
142+ s .anyEncoder = newJSONMarshalEncoder ()
143+ }
144+
145+ enc := s .anyEncoder
146+ enc .Reset () // reset the encoder, if was reused
145147 if err := enc .Encode (v ); err != nil {
146148 return err
147149 }
148- bs := bb .Bytes ()
149- buf .Write (bs [:len (bs )- 1 ]) // remove final newline
150+
151+ bs := enc .Bytes ()
152+ s .buf .Write (bs [:len (bs )- 1 ]) // remove final newline
150153 return nil
151154}
152155
156+ type jsonMarhsalEncoder struct {
157+ buf * bytes.Buffer
158+ enc * json.Encoder
159+ }
160+
161+ func newJSONMarshalEncoder () encoder {
162+ if enc := jsonEncoderPool .Get (); enc != nil {
163+ return enc .(* jsonMarhsalEncoder )
164+ }
165+
166+ buf := & bytes.Buffer {}
167+
168+ // Use a json.Encoder to avoid escaping HTML.
169+ jsonEnc := json .NewEncoder (buf )
170+ jsonEnc .SetEscapeHTML (false )
171+
172+ return & jsonMarhsalEncoder {buf : buf , enc : jsonEnc }
173+ }
174+
175+ func (e * jsonMarhsalEncoder ) Reset () {
176+ e .buf .Reset ()
177+ }
178+
179+ func (e * jsonMarhsalEncoder ) Encode (v any ) error {
180+ return e .enc .Encode (v )
181+ }
182+
183+ func (e * jsonMarhsalEncoder ) Bytes () []byte {
184+ return e .buf .Bytes ()
185+ }
186+
187+ func (e * jsonMarhsalEncoder ) Free () {
188+ const maxBufferSize = 8 << 10
189+ if e .buf .Cap () <= maxBufferSize {
190+ jsonEncoderPool .Put (e )
191+ }
192+ }
193+
194+ var jsonEncoderPool = sync.Pool {}
195+
153196// appendEscapedJSONString escapes s for JSON and appends it to buf.
154197// It does not surround the string in quotation marks.
155198//
0 commit comments