Repository: uber-go/zap
File: exp/zapslog/slog.go (Go)

Code before:
//
// 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 zapslog

package zapslog

import (
	"context"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"golang.org/x/exp/slog"
)

type handler struct {
	logger *zap.Logger
}

var _ slog.Handler = (*handler)(nil)

// group holds all the Attrs saved in a slog.GroupValue.
type group struct {
	attrs []slog.Attr
}

func (g *group) MarshalLogObject(enc zapcore.ObjectEncoder) error {
	for _, attr := range g.attrs {
		convertAttrToField(attr).AddTo(enc)
	}
	return nil
}

func convertAttrToField(attr slog.Attr) zapcore.Field {
	switch attr.Value.Kind() {
	case slog.KindBool:
		return zap.Bool(attr.Key, attr.Value.Bool())
	case slog.KindDuration:
		return zap.Duration(attr.Key, attr.Value.Duration())
	case slog.KindFloat64:
		return zap.Float64(attr.Key, attr.Value.Float64())
	case slog.KindInt64:

Review comment (suggestion):
@knight42 I think there was a misunderstanding.
We want to implement this interface around zapcore.Core.

slog.Handler and zapcore.Core are at the same level
similar to how slog.Logger and zap.Logger are at the same level.

Code after:
//
// 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.

package zapslog

import (
	"context"
	"runtime"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"golang.org/x/exp/slog"
)

// Handler implements the slog.Handler by writing to a zap Core.
type Handler struct {
	core      zapcore.Core
	name      string // logger name
	addSource bool
}

// HandlerOptions are options for a Zap-based [slog.Handler].
type HandlerOptions struct {
	// LoggerName is used for log entries received from slog.
	//
	// Defaults to empty.
	LoggerName string

	// AddSource configures the handler to annotate each message with the filename,
	// line number, and function name.
	// AddSource is false by default to skip the cost of computing
	// this information.
	AddSource bool
}

// New builds a [Handler] that writes to the supplied [zapcore.Core].
// This handler may be supplied to [slog.New] to create a new [slog.Logger].
func (opts HandlerOptions) New(core zapcore.Core) *Handler {
	return &Handler{
		core:      core,
		name:      opts.LoggerName,
		addSource: opts.AddSource,