@@ -26,6 +26,7 @@ import (
2626 "context"
2727 "log/slog"
2828 "runtime"
29+ "slices"
2930
3031 "go.uber.org/zap"
3132 "go.uber.org/zap/internal/stacktrace"
@@ -163,15 +164,19 @@ func (h *Handler) Handle(ctx context.Context, record slog.Record) error {
163164 }
164165
165166 fields := make ([]zapcore.Field , 0 , record .NumAttrs ()+ 1 )
167+ var addedNamespace bool
166168 record .Attrs (func (attr slog.Attr ) bool {
167169 f := convertAttrToField (attr )
168- if h .holdGroup != "" && f != zap .Skip () {
169- fields = append (fields , zap .Namespace (h .holdGroup ))
170- h .holdGroup = ""
170+ if ! addedNamespace && f != zap .Skip () {
171+ addedNamespace = true
171172 }
172173 fields = append (fields , f )
173174 return true
174175 })
176+ if h .holdGroup != "" && addedNamespace {
177+ // group is before than other fields.
178+ fields = slices .Insert (fields , 0 , zap .Namespace (h .holdGroup ))
179+ }
175180
176181 ce .Write (fields ... )
177182 return nil
@@ -181,31 +186,35 @@ func (h *Handler) Handle(ctx context.Context, record slog.Record) error {
181186// both the receiver's attributes and the arguments.
182187func (h * Handler ) WithAttrs (attrs []slog.Attr ) slog.Handler {
183188 fields := make ([]zapcore.Field , 0 , len (attrs )+ 1 )
189+ var addedNamespace bool
184190 for _ , attr := range attrs {
185191 f := convertAttrToField (attr )
186- if h .holdGroup != "" && f != zap .Skip () {
187- fields = append (fields , zap .Namespace (h .holdGroup ))
188- h .holdGroup = ""
192+ if ! addedNamespace && f != zap .Skip () {
193+ addedNamespace = true
189194 }
190195 fields = append (fields , f )
191196 }
192- return h .withFields (fields ... )
197+ if h .holdGroup != "" && addedNamespace {
198+ // group is before than other fields.
199+ fields = slices .Insert (fields , 0 , zap .Namespace (h .holdGroup ))
200+ return h .withFields ("" , fields ... )
201+ }
202+ return h .withFields (h .holdGroup , fields ... )
193203}
194204
195205// WithGroup returns a new Handler with the given group appended to
196206// the receiver's existing groups.
197207func (h * Handler ) WithGroup (group string ) slog.Handler {
198- cloned := * h
199208 if h .holdGroup != "" {
200- cloned . core = h . core . With ([]zapcore. Field { zap .Namespace (h .holdGroup )} )
209+ return h . withFields ( group , zap .Namespace (h .holdGroup ))
201210 }
202- cloned .holdGroup = group
203- return & cloned
211+ return h .withFields (group )
204212}
205213
206- // withFields returns a cloned Handler with the given fields.
207- func (h * Handler ) withFields (fields ... zapcore.Field ) * Handler {
214+ // withFields returns a cloned Handler with the given groups and fields.
215+ func (h * Handler ) withFields (newGroup string , fields ... zapcore.Field ) * Handler {
208216 cloned := * h
217+ cloned .holdGroup = newGroup
209218 cloned .core = h .core .With (fields )
210219 return & cloned
211220}
0 commit comments