Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/logger-with-tee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"github.com/livekit/protocol": minor
"@livekit/protocol": patch
---

Replace logger.WithTap with logger.WithTee, which duplicates every log entry to a caller-supplied zaputil.Tee. The tee's core is built from the level each derived logger resolves, so the copy follows component levels rather than carrying a level of its own.

Replace ZapLogger.WithMinLevel with WithComponentLeveler, which attaches a zaputil.ComponentLeveler to a branch of the logger tree. A leveler owns the per-component level and write-enabler cache for one configuration source and can only widen its parent, so a caller can resolve levels per (tenant, component) without rebuilding loggers on a config change. ZapLogger.Leveler exposes the leveler a branch resolves through, for use as the parent of a derived one.
3 changes: 1 addition & 2 deletions livekit/egress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"testing"

"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"

"github.com/livekit/protocol/logger"
"github.com/livekit/protocol/logger/testutil"
Expand All @@ -32,7 +31,7 @@ type TestEgressLogOutput struct {

func TestLoggerProto(t *testing.T) {
ws := &testutil.BufferedWriteSyncer{}
l, err := logger.NewZapLogger(&logger.Config{}, logger.WithTap(zaputil.NewWriteEnabler(ws, zapcore.DebugLevel)))
l, err := logger.NewZapLogger(&logger.Config{Level: "debug"}, logger.WithTee(zaputil.NewTee(testutil.NewJSONCoreFactory(ws))))
require.NoError(t, err)

s3 := &S3Upload{
Expand Down
22 changes: 21 additions & 1 deletion logger/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@

package logger

import "sync"
import (
"strings"
"sync"

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

type Config struct {
JSON bool `yaml:"json,omitempty"`
Expand Down Expand Up @@ -72,3 +77,18 @@ func (c *Config) AddUpdateObserver(cb ConfigObserver) {
defer c.lock.Unlock()
c.onUpdatedCallbacks = append(c.onUpdatedCallbacks, cb)
}

// ResolveComponentLevel always resolves: an unconfigured component takes Level.
func (c *Config) ResolveComponentLevel(component string) (zapcore.Level, bool) {
c.lock.Lock()
defer c.lock.Unlock()

parts := strings.Split(component, ".")
for len(parts) > 0 {
if lvl, ok := c.ComponentLevels[strings.Join(parts, ".")]; ok {
return ParseZapLevel(lvl), true
}
parts = parts[:len(parts)-1]
}
return ParseZapLevel(c.Level), true
}
25 changes: 25 additions & 0 deletions logger/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package logger

import (
"io"
"testing"

"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"

"github.com/livekit/protocol/logger/zaputil"
)

func TestConfigResolveComponentLevel(t *testing.T) {
conf := &Config{Level: "info", ComponentLevels: map[string]string{"rtc.room": "debug"}}
root := zaputil.NewRootComponentLeveler(zapcore.AddSync(io.Discard), conf)

require.True(t, root.ComponentLevel("rtc.room").Enabled(zapcore.DebugLevel))
require.True(t, root.ComponentLevel("rtc.room.track").Enabled(zapcore.DebugLevel))
require.False(t, root.ComponentLevel("rtc").Enabled(zapcore.DebugLevel))
require.True(t, root.ComponentLevel("rtc").Enabled(zapcore.InfoLevel))

lvl, ok := (&Config{}).ResolveComponentLevel("anything")
require.True(t, ok)
require.Equal(t, zapcore.InfoLevel, lvl)
}
Loading
Loading