Skip to content

Commit f760df8

Browse files
committed
feat: add slog/logr logging bridges and update shared utilities
- Add slog/logr bridge in pkg/log/zap.go for Cilium v1.19 - Update pkg/utils/flow_utils.go with structpb extensions - Migrate metrics package to slog-compatible interface - Remove unused ITracer mock - Update pkg/config, pkg/common/endpoint.go, and Hubble decoder Signed-off-by: Quang Nguyen <nguyenquang@microsoft.com>
1 parent 6b7cec7 commit f760df8

File tree

11 files changed

+291
-204
lines changed

11 files changed

+291
-204
lines changed

pkg/common/endpoint.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func (ep *RetinaEndpoint) PrimaryIP() (string, error) {
164164
}
165165
}
166166

167-
return "", errors.Wrapf(ErrNoPrimaryIPFoundEndpoint, ep.Key())
167+
return "", errors.Wrapf(ErrNoPrimaryIPFoundEndpoint, "endpoint: %s", ep.Key())
168168
}
169169

170170
func (ep *RetinaEndpoint) PrimaryNetIP() (net.IP, error) {
@@ -178,7 +178,7 @@ func (ep *RetinaEndpoint) PrimaryNetIP() (net.IP, error) {
178178
}
179179
}
180180

181-
return nil, errors.Wrapf(ErrNoPrimaryIPFoundEndpoint, ep.Key())
181+
return nil, errors.Wrapf(ErrNoPrimaryIPFoundEndpoint, "endpoint: %s", ep.Key())
182182
}
183183

184184
func (o *OwnerReference) DeepCopy() *OwnerReference {

pkg/hubble/common/decoder_linux.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010
"github.com/cilium/cilium/pkg/labels"
1111
)
1212

13-
//go:generate go run github.com/golang/mock/mockgen@v1.6.0 -source decoder.go -destination=mocks/mock_types.go -package=mocks
14-
1513
type EpDecoder interface {
1614
Decode(ip netip.Addr) *flow.Endpoint
1715
IsEndpointOnLocalHost(ip string) bool

pkg/log/zap.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33
package log
44

55
import (
6+
"log/slog"
67
"net/http"
78
"os"
89
"runtime"
910
"time"
1011

1112
"github.com/Azure/azure-container-networking/zapai"
1213
"github.com/go-chi/chi/middleware"
14+
"github.com/go-logr/logr"
15+
"github.com/go-logr/zapr"
1316
logfmt "github.com/jsternberg/zap-logfmt"
1417
"github.com/microsoft/ApplicationInsights-Go/appinsights"
1518
"github.com/pkg/errors"
1619
"go.uber.org/zap"
20+
"go.uber.org/zap/exp/zapslog"
1721
"go.uber.org/zap/zapcore"
1822
"gopkg.in/natefinch/lumberjack.v2"
1923
)
@@ -46,6 +50,11 @@ func GetDefaultLogOpts() *LogOpts {
4650
}
4751

4852
func Logger() *ZapLogger {
53+
if global == nil {
54+
// Auto-initialize with default options if not already set
55+
// This provides a fallback for code that accesses Logger() before SetupZapLogger()
56+
_, _ = SetupZapLogger(GetDefaultLogOpts())
57+
}
4958
return global
5059
}
5160

@@ -202,3 +211,35 @@ func (lOpts *LogOpts) validate() {
202211
}
203212
}
204213
}
214+
215+
// SlogHandler returns an slog.Handler backed by the global zap core.
216+
// All slog messages will flow through zap's pipeline (stdout + Application Insights).
217+
func SlogHandler() slog.Handler {
218+
if global == nil {
219+
return slog.NewTextHandler(os.Stdout, nil)
220+
}
221+
return zapslog.NewHandler(global.Core(), zapslog.WithCaller(true))
222+
}
223+
224+
// SetDefaultSlog sets Go's global slog default to use the zap-backed handler.
225+
// After calling this, slog.Default() returns a logger that routes through zap.
226+
func SetDefaultSlog() {
227+
slog.SetDefault(slog.New(SlogHandler()))
228+
}
229+
230+
// SlogLogger returns a new *slog.Logger backed by the global zap core.
231+
func SlogLogger() *slog.Logger {
232+
return slog.New(SlogHandler())
233+
}
234+
235+
// LogrLogger returns a logr.Logger backed by the global zap logger.
236+
// This is useful for integrating with controller-runtime and other libraries
237+
// that use logr.Logger, ensuring consistent log format across the application.
238+
func LogrLogger() logr.Logger {
239+
if global == nil {
240+
// Fallback to a basic zap logger if global is not initialized
241+
zapLogger, _ := zap.NewProduction()
242+
return zapr.NewLogger(zapLogger)
243+
}
244+
return zapr.NewLogger(global.Logger)
245+
}

pkg/log/zap_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
package log
44

55
import (
6+
"log/slog"
67
"os"
78
"path/filepath"
89
"strings"
910
"testing"
1011

1112
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
1214
"go.uber.org/zap"
1315
)
1416

@@ -51,3 +53,67 @@ func TestLogFileRotation(t *testing.T) {
5153
assert.NoError(t, err, "Test log file walk through failed with err")
5254
assert.Equal(t, expectedReplicas, curReplicas, "Test log file replicas are not as expected on 2nd try")
5355
}
56+
57+
func TestSlogHandler(t *testing.T) {
58+
// Reset the global logger for this test
59+
global = nil
60+
61+
_, err := SetupZapLogger(GetDefaultLogOpts())
62+
require.NoError(t, err)
63+
64+
handler := SlogHandler()
65+
require.NotNil(t, handler)
66+
67+
logger := slog.New(handler)
68+
// Should not panic
69+
logger.Info("test message from slog", "key", "value")
70+
71+
// SetDefaultSlog should make slog.Default() return zap-backed logger
72+
SetDefaultSlog()
73+
slog.Default().Info("default slog test", "source", "TestSlogHandler")
74+
75+
// SlogLogger should return a new logger
76+
slogLogger := SlogLogger()
77+
require.NotNil(t, slogLogger)
78+
slogLogger.Info("from SlogLogger", "test", true)
79+
}
80+
81+
func TestSlogHandlerFallback(t *testing.T) {
82+
// Reset global to test fallback behavior
83+
global = nil
84+
85+
// Without zap setup, SlogHandler should return a fallback text handler
86+
handler := SlogHandler()
87+
require.NotNil(t, handler)
88+
89+
// Should not panic even without zap being setup
90+
logger := slog.New(handler)
91+
logger.Info("fallback test message", "key", "value")
92+
}
93+
94+
func TestLogrLogger(t *testing.T) {
95+
// Reset the global logger for this test
96+
global = nil
97+
98+
_, err := SetupZapLogger(GetDefaultLogOpts())
99+
require.NoError(t, err)
100+
101+
logrLogger := LogrLogger()
102+
require.NotNil(t, logrLogger)
103+
104+
// Should not panic and should log using the same format as Retina's zap logger
105+
logrLogger.Info("test message from logr", "key", "value")
106+
logrLogger.V(1).Info("debug message from logr", "level", 1)
107+
}
108+
109+
func TestLogrLoggerFallback(t *testing.T) {
110+
// Reset global to test fallback behavior
111+
global = nil
112+
113+
// Without zap setup, LogrLogger should return a fallback logger
114+
logrLogger := LogrLogger()
115+
require.NotNil(t, logrLogger)
116+
117+
// Should not panic even without zap being setup
118+
logrLogger.Info("fallback logr test message", "key", "value")
119+
}

pkg/metrics/metrics.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
package metrics
44

55
import (
6+
"log/slog"
7+
68
"github.com/microsoft/retina/pkg/exporter"
7-
"github.com/microsoft/retina/pkg/log"
89
"github.com/microsoft/retina/pkg/utils"
910
"github.com/prometheus/client_golang/prometheus"
1011
dto "github.com/prometheus/client_model/go"
1112
)
1213

1314
// Initiates and creates the common metrics
14-
func InitializeMetrics() {
15-
metricsLogger = log.Logger().Named("metrics")
15+
func InitializeMetrics(logger *slog.Logger) {
16+
metricsLogger = logger.With("module", "metrics")
1617

1718
if isInitialized {
1819
metricsLogger.Warn("Metrics already initialized. Exiting.")

pkg/metrics/metrics_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package metrics
55

66
import (
7+
"log/slog"
78
"testing"
89

910
"github.com/microsoft/retina/pkg/log"
@@ -12,7 +13,7 @@ import (
1213
func TestInitialization_FirstInit(t *testing.T) {
1314
log.SetupZapLogger(log.GetDefaultLogOpts())
1415

15-
InitializeMetrics()
16+
InitializeMetrics(slog.Default())
1617

1718
// All metrics should be initialized.
1819
objs := []interface{}{DropPacketsGauge, DropBytesGauge, ForwardBytesGauge, ForwardPacketsGauge, NodeConnectivityStatusGauge, NodeConnectivityLatencyGauge, PluginManagerFailedToReconcileCounter}
@@ -31,7 +32,7 @@ func TestInitialization_MultipleInit(t *testing.T) {
3132
}()
3233
log.SetupZapLogger(log.GetDefaultLogOpts())
3334

34-
InitializeMetrics()
35+
InitializeMetrics(slog.Default())
3536
// Should not panic when reinitializing.
36-
InitializeMetrics()
37+
InitializeMetrics(slog.Default())
3738
}

pkg/metrics/types.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
package metrics
44

55
import (
6-
"github.com/microsoft/retina/pkg/log"
6+
"log/slog"
7+
78
"github.com/prometheus/client_golang/prometheus"
8-
"go.uber.org/zap"
99
)
1010

1111
const (
@@ -87,7 +87,7 @@ var (
8787
// Interface Stats
8888
InterfaceStatsGauge GaugeVec
8989

90-
metricsLogger *log.ZapLogger
90+
metricsLogger *slog.Logger
9191

9292
// Control Plane Metrics
9393
PluginManagerFailedToReconcileCounter CounterVec
@@ -119,7 +119,9 @@ func ToPrometheusType(metric interface{}) prometheus.Collector {
119119
case CounterVec:
120120
return m.(*prometheus.CounterVec)
121121
default:
122-
metricsLogger.Error("error converting unknown metric type", zap.Any("metric", m))
122+
if metricsLogger != nil {
123+
metricsLogger.Error("error converting unknown metric type", slog.Any("metric", m))
124+
}
123125
return nil
124126
}
125127
}

pkg/plugin/common/common_linux.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,7 @@ import (
2222
"golang.org/x/sys/unix"
2323
)
2424

25-
//go:generate go run go.uber.org/mock/mockgen@v0.4.0 -destination=mocks/mock_types.go -package=mocks . ITracer
26-
27-
// Interface for IG tracers.
28-
// Ref: https://pkg.go.dev/github.com/inspektor-gadget/inspektor-gadget@v0.18.1/pkg/gadgets/trace/dns/tracer#Tracer
29-
type ITracer interface {
30-
SetEventHandler(interface{})
31-
Attach(pid uint32) error
32-
Detach(pid uint32) error
33-
Close()
34-
}
35-
36-
// Interface for IG event handlers. Maps to cilum Flow.
25+
// ProtocolToFlow converts a protocol string to the corresponding Unix protocol number.
3726
func ProtocolToFlow(protocol string) int {
3827
switch protocol {
3928
case "tcp":

pkg/plugin/common/mocks/mock_types.go

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)