Skip to content

Commit

Permalink
zapslog: Support for a custom mapping of slog.Level to zap.Level
Browse files Browse the repository at this point in the history
Signed-off-by: junya koyama <arukiidou@yahoo.co.jp>
  • Loading branch information
arukiidou committed Feb 7, 2024
1 parent 7db06bc commit 98c4692
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 18 deletions.
22 changes: 4 additions & 18 deletions exp/zapslog/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Handler struct {
addCaller bool
addStackAt slog.Level
callerSkip int
leveler ConvertLeveler

// List of unapplied groups.
//
Expand All @@ -54,6 +55,7 @@ func NewHandler(core zapcore.Core, opts ...HandlerOption) *Handler {
h := &Handler{
core: core,
addStackAt: slog.LevelError,
leveler: &DefaultConvertLeveler{},
}
for _, v := range opts {
v.apply(h)
Expand Down Expand Up @@ -113,31 +115,15 @@ func convertAttrToField(attr slog.Attr) zapcore.Field {
}
}

// convertSlogLevel maps slog Levels to zap Levels.
// Note that there is some room between slog levels while zap levels are continuous, so we can't 1:1 map them.
// See also https://go.googlesource.com/proposal/+/master/design/56345-structured-logging.md?pli=1#levels
func convertSlogLevel(l slog.Level) zapcore.Level {
switch {
case l >= slog.LevelError:
return zapcore.ErrorLevel
case l >= slog.LevelWarn:
return zapcore.WarnLevel
case l >= slog.LevelInfo:
return zapcore.InfoLevel
default:
return zapcore.DebugLevel
}
}

// Enabled reports whether the handler handles records at the given level.
func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool {
return h.core.Enabled(convertSlogLevel(level))
return h.core.Enabled(h.leveler.ConvertLevel(level))
}

// Handle handles the Record.
func (h *Handler) Handle(ctx context.Context, record slog.Record) error {
ent := zapcore.Entry{
Level: convertSlogLevel(record.Level),
Level: h.leveler.ConvertLevel(record.Level),
Time: record.Time,
Message: record.Message,
LoggerName: h.name,
Expand Down
65 changes: 65 additions & 0 deletions exp/zapslog/leveler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//go:build go1.21

package zapslog

import (
"log/slog"

"go.uber.org/zap/zapcore"
)

// ConvertLeveler maps from [log/slog.Level] to [go.uber.org/zap/zapcore.Level].
// Note that there is some room between slog levels while zap levels are continuous, so we can't 1:1 map them.
// See also [structured logging proposal]
//
// [structured logging proposal]: https://go.googlesource.com/proposal/+/master/design/56345-structured-logging.md?pli=1#levels
type ConvertLeveler interface {
ConvertLevel(l slog.Level) zapcore.Level
}

// DefaultConvertLeveler maps.
// implements: [go.uber.org/zap/exp/zapslog.ConvertLeveler]
type DefaultConvertLeveler struct{}

// ConvertLevel static maps from [log/slog.Level] to [go.uber.org/zap/zapcore.Level].
// - [log/slog.LevelError] to [go.uber.org/zap/zapcore.ErrorLevel]
// - [log/slog.LevelWarn] to [go.uber.org/zap/zapcore.WarnLevel]
// - [log/slog.LevelInfo] to [go.uber.org/zap/zapcore.InfoLevel]
// - [log/slog.LevelDebug] or default to [go.uber.org/zap/zapcore.DebugLevel]
//
// Note that there is some room between slog levels while zap levels are continuous, so we can't 1:1 map them.
// See also [structured logging proposal]
//
// [structured logging proposal]: https://go.googlesource.com/proposal/+/master/design/56345-structured-logging.md?pli=1#levels
func (c *DefaultConvertLeveler) ConvertLevel(l slog.Level) zapcore.Level {
switch {
case l >= slog.LevelError:
return zapcore.ErrorLevel
case l >= slog.LevelWarn:
return zapcore.WarnLevel
case l >= slog.LevelInfo:
return zapcore.InfoLevel
default:
return zapcore.DebugLevel
}
}

0 comments on commit 98c4692

Please sign in to comment.