Repository: cilium/cilium
Pull request #39164: pkg/labelsfilter: migrate to slog
Author: login: aanm
Labels: name: area/misc
description: Impacts miscellaneous areas of the code not otherwise owned by another area.
name: sig/policy
description: Impacts whether traffic is allowed or denied based on user-defined policies.
name: ready-to-merge
description: This PR has passed all tests and received consensus from code owners to merge.
name: release-note/misc
description: This PR makes changes that have no direct user impact.
name: feature/slog
Created: 2025-04-25T08:03:05Z | Merged: 2025-04-25T14:02:08Z

Migrate this package to use slog instead of logrus.


Diff:
diff --git a/daemon/cmd/daemon_main.go b/daemon/cmd/daemon_main.go
index 18ec38b7edad3..542d8f1ac57e0 100644
--- a/daemon/cmd/daemon_main.go
+++ b/daemon/cmd/daemon_main.go
@@ -1265,7 +1265,7 @@ func initEnv(vp *viper.Viper) {
 	if !option.Config.EnableIPv4 && !option.Config.EnableIPv6 {
 		log.Fatal("Either IPv4 or IPv6 addressing must be enabled")
 	}
-	if err := labelsfilter.ParseLabelPrefixCfg(option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
+	if err := labelsfilter.ParseLabelPrefixCfg(logging.DefaultSlogLogger, option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
 		log.WithError(err).Fatal("Unable to parse Label prefix configuration")
 	}
 
diff --git a/daemon/cmd/daemon_test.go b/daemon/cmd/daemon_test.go
index 4ddb04945cc0d..037b2470f5ce4 100644
--- a/daemon/cmd/daemon_test.go
+++ b/daemon/cmd/daemon_test.go
@@ -96,7 +96,9 @@ func TestMain(m *testing.M) {
 func setupDaemonSuite(tb testing.TB) *DaemonSuite {
 	testutils.IntegrationTest(tb)
 
-	ds := &DaemonSuite{}
+	ds := &DaemonSuite{
+		log: hivetest.Logger(tb),
+	}
 	ctx := context.Background()
 
 	ds.oldPolicyEnabled = policy.GetPolicyEnabled()
@@ -148,7 +150,6 @@ func setupDaemonSuite(tb testing.TB) *DaemonSuite {
 	option.Config.RunDir = testRunDir
 	option.Config.StateDir = testRunDir
 
-	ds.log = hivetest.Logger(tb)
 	err := ds.hive.Start(ds.log, ctx)
 	require.NoError(tb, err)
 
@@ -200,7 +201,7 @@ func (ds *DaemonSuite) setupConfigOptions() {
 	option.Config.DryMode = true
 	option.Config.Opts = option.NewIntOptions(&option.DaemonMutableOptionLibrary)
 	// GetConfig the default labels prefix filter
-	err := labelsfilter.ParseLabelPrefixCfg(nil, nil, "")
+	err := labelsfilter.ParseLabelPrefixCfg(ds.log, nil, nil, "")
 	if err != nil {
 		panic("ParseLabelPrefixCfg() failed")
 	}
diff --git a/daemon/cmd/endpoint_test.go b/daemon/cmd/endpoint_test.go
index 182a96ce628d0..c58a6705f90aa 100644
--- a/daemon/cmd/endpoint_test.go
+++ b/daemon/cmd/endpoint_test.go
@@ -11,6 +11,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/cilium/hive/hivetest"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
@@ -207,7 +208,7 @@ func TestHandleOutdatedPodInformer(t *testing.T) {
 	defer func(current time.Duration) { handleOutdatedPodInformerRetryPeriod = current }(handleOutdatedPodInformerRetryPeriod)
 	handleOutdatedPodInformerRetryPeriod = 1 * time.Millisecond
 
-	require.NoError(t, labelsfilter.ParseLabelPrefixCfg(nil, nil, ""))
+	require.NoError(t, labelsfilter.ParseLabelPrefixCfg(hivetest.Logger(t), nil, nil, ""))
 
 	notFoundErr := k8sErrors.NewNotFound(schema.GroupResource{Group: "core", Resource: "pod"}, "foo")
 
diff --git a/operator/cmd/root.go b/operator/cmd/root.go
index 565ff20ddd698..4d03ef966bb02 100644
--- a/operator/cmd/root.go
+++ b/operator/cmd/root.go
@@ -738,7 +738,7 @@ func (legacy *legacyOnLeader) onStart(_ cell.HookContext) error {
 	}
 
 	if legacy.clientset.IsEnabled() {
-		if err := labelsfilter.ParseLabelPrefixCfg(option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
+		if err := labelsfilter.ParseLabelPrefixCfg(legacy.logger, option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
 			log.WithError(err).Fatal("Unable to parse Label prefix configuration")
 		}
 	}
diff --git a/operator/pkg/ciliumidentity/cache_test.go b/operator/pkg/ciliumidentity/cache_test.go
index f0ff6edacdbf6..296d3cb7e6c21 100644
--- a/operator/pkg/ciliumidentity/cache_test.go
+++ b/operator/pkg/ciliumidentity/cache_test.go
@@ -28,7 +28,8 @@ var (
 )
 
 func TestMain(m *testing.M) {
-	labelsfilter.ParseLabelPrefixCfg(nil, nil, "")
+	logger := slog.New(slog.DiscardHandler)
+	labelsfilter.ParseLabelPrefixCfg(logger, nil, nil, "")
 
 	os.Exit(m.Run())
 }
diff --git a/pkg/endpoint/endpoint_test.go b/pkg/endpoint/endpoint_test.go
index f77e5e2aeeded..b2c0ec3fa9f85 100644
--- a/pkg/endpoint/endpoint_test.go
+++ b/pkg/endpoint/endpoint_test.go
@@ -52,15 +52,16 @@ type EndpointSuite struct {
 
 func setupEndpointSuite(tb testing.TB) *EndpointSuite {
 	testutils.IntegrationTest(tb)
+	logger := hivetest.Logger(tb)
 
 	s := &EndpointSuite{
 		orchestrator: &fakeTypes.FakeOrchestrator{},
-		repo:         policy.NewPolicyRepository(hivetest.Logger(tb), nil, nil, nil, nil, api.NewPolicyMetricsNoop()),
+		repo:         policy.NewPolicyRepository(logger, nil, nil, nil, nil, api.NewPolicyMetricsNoop()),
 		mgr:          cache.NewCachingIdentityAllocator(&testidentity.IdentityAllocatorOwnerMock{}, cache.AllocatorConfig{}),
 	}
 
 	// GetConfig the default labels prefix filter
-	err := labelsfilter.ParseLabelPrefixCfg(nil, nil, "")
+	err := labelsfilter.ParseLabelPrefixCfg(logger, nil, nil, "")
 	if err != nil {
 		panic("ParseLabelPrefixCfg() failed")
 	}
diff --git a/pkg/endpointmanager/manager_test.go b/pkg/endpointmanager/manager_test.go
index 121223fffe696..b9edcedfd7f83 100644
--- a/pkg/endpointmanager/manager_test.go
+++ b/pkg/endpointmanager/manager_test.go
@@ -916,10 +916,10 @@ func TestWaitForEndpointsAtPolicyRev(t *testing.T) {
 }
 
 func TestMissingNodeLabelsUpdate(t *testing.T) {
+	logger := hivetest.Logger(t)
 	// Initialize label filter config.
-	labelsfilter.ParseLabelPrefixCfg(nil, nil, "")
+	labelsfilter.ParseLabelPrefixCfg(logger, nil, nil, "")
 	s := setupEndpointManagerSuite(t)
-	logger := hivetest.Logger(t)
 	mgr := New(logger, &dummyEpSyncher{}, nil, nil, nil)
 	hostEPID := uint16(17)
 
@@ -953,10 +953,10 @@ func TestMissingNodeLabelsUpdate(t *testing.T) {
 }
 
 func TestUpdateHostEndpointLabels(t *testing.T) {
+	logger := hivetest.Logger(t)
 	// Initialize label filter config.
-	labelsfilter.ParseLabelPrefixCfg([]string{"k8s:!ignore1", "k8s:!ignore2"}, nil, "")
+	labelsfilter.ParseLabelPrefixCfg(logger, []string{"k8s:!ignore1", "k8s:!ignore2"}, nil, "")
 	s := setupEndpointManagerSuite(t)
-	logger := hivetest.Logger(t)
 	mgr := New(logger, &dummyEpSyncher{}, nil, nil, nil)
 	hostEPID := uint16(17)
 	type args struct {
diff --git a/pkg/identity/key/global_identity_test.go b/pkg/identity/key/global_identity_test.go
index 51888243edfa6..dfbe6748ff85f 100644
--- a/pkg/identity/key/global_identity_test.go
+++ b/pkg/identity/key/global_identity_test.go
@@ -6,12 +6,15 @@ package key
 import (
 	"testing"
 
+	"github.com/cilium/hive/hivetest"
+
 	"github.com/cilium/cilium/pkg/labels"
 	"github.com/cilium/cilium/pkg/labelsfilter"
 )
 
 func TestGetCIDKeyFromLabels(t *testing.T) {
-	labelsfilter.ParseLabelPrefixCfg(nil, nil, "")
+	logger := hivetest.Logger(t)
+	labelsfilter.ParseLabelPrefixCfg(logger, nil, nil, "")
 
 	tests := []struct {
 		name     string
diff --git a/pkg/labelsfilter/filter.go b/pkg/labelsfilter/filter.go
index 96fa5650077a9..cf8b4d611ecc7 100644
--- a/pkg/labelsfilter/filter.go
+++ b/pkg/labelsfilter/filter.go
@@ -6,6 +6,7 @@ package labelsfilter
 import (
 	"encoding/json"
 	"fmt"
+	"log/slog"
 	"os"
 	"regexp"
 	"strings"
@@ -13,12 +14,10 @@ import (
 	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
 	"github.com/cilium/cilium/pkg/labels"
 	"github.com/cilium/cilium/pkg/lock"
-	"github.com/cilium/cilium/pkg/logging"
 	"github.com/cilium/cilium/pkg/logging/logfields"
 )
 
 var (
-	log                    = logging.DefaultLogger.WithField(logfields.LogSubsys, "labels-filter")
 	validLabelPrefixesMU   lock.RWMutex
 	validLabelPrefixes     *labelPrefixCfg // Label prefixes used to filter from all labels
 	validNodeLabelPrefixes *labelPrefixCfg
@@ -109,17 +108,20 @@ func parseLabelPrefix(label string) (*LabelPrefix, error) {
 // ParseLabelPrefixCfg parses valid label prefixes from a file and from a slice
 // of valid prefixes. Both are optional. If both are provided, both list are
 // appended together.
-func ParseLabelPrefixCfg(prefixes, nodePrefixes []string, file string) error {
+func ParseLabelPrefixCfg(logger *slog.Logger, prefixes, nodePrefixes []string, file string) error {
 	var cfg, nodeCfg *labelPrefixCfg
 	var err error
 	var fromCustomFile bool
 
 	// Use default label prefix if configuration file not provided
 	if file == "" {
-		log.Info("Parsing base label prefixes from default label list")
+		logger.Info("Parsing base label prefixes from default label list")
 		cfg = defaultLabelPrefixCfg()
 	} else {
-		log.Infof("Parsing base label prefixes from file %s", file)
+		logger.Info(
+			"Parsing base label prefixes from file",
+			logfields.File, file,
+		)
 		cfg, err = readLabelPrefixCfgFrom(file)
 		if err != nil {
 			return fmt.Errorf("unable to read label prefix file: %w", err)
@@ -130,7 +132,10 @@ func ParseLabelPrefixCfg(prefixes, nodePrefixes []string, file string) error {
 
 	//exhaustruct:ignore // Reading clean configuration, no need to initialize
 	nodeCfg = &labelPrefixCfg{}
-	log.Infof("Parsing node label prefixes from user inputs: %v", nodePrefixes)
+	logger.Info(
+		"Parsing node label prefixes from user inputs",
+		logfields.Prefix, nodePrefixes,
+	)
 	for _, label := range nodePrefixes {
 		if len(label) == 0 {
 			continue
@@ -147,7 +152,10 @@ func ParseLabelPrefixCfg(prefixes, nodePrefixes []string, file string) error {
 		nodeCfg.LabelPrefixes = append(nodeCfg.LabelPrefixes, p)
 	}
 
-	log.Infof("Parsing additional label prefixes from user inputs: %v", prefixes)
+	logger.Info(
+		"Parsing additional label prefixes from user inputs",
+		logfields.Prefix, prefixes,
+	)
 	for _, label := range prefixes {
 		if len(label) == 0 {
 			continue
@@ -174,22 +182,24 @@ func ParseLabelPrefixCfg(prefixes, nodePrefixes []string, file string) error {
 		}
 
 		if !found {
-			log.Errorf("'%s' needs to be included in the final label list for "+
-				"Cilium to work properly.", reservedLabelsPattern)
+			logger.Error(
+				fmt.Sprintf("'%s' needs to be included in the final label list for "+
+					"Cilium to work properly.", reservedLabelsPattern),
+			)
 		}
 	}
 
 	validLabelPrefixes = cfg
 	validNodeLabelPrefixes = nodeCfg
 
-	log.Info("Final label prefixes to be used for identity evaluation:")
+	logger.Info("Final label prefixes to be used for identity evaluation:")
 	for _, l := range validLabelPrefixes.LabelPrefixes {
-		log.Infof(" - %s", l)
+		logger.Info(fmt.Sprintf(" - %s", l))
 	}
 
-	log.Info("Final node label prefixes to be used for identity evaluation:")
+	logger.Info("Final node label prefixes to be used for identity evaluation:")
 	for _, l := range validNodeLabelPrefixes.LabelPrefixes {
-		log.Infof(" - %s", l)
+		logger.Info(fmt.Sprintf(" - %s", l))
 	}
 
 	return nil
diff --git a/pkg/labelsfilter/filter_test.go b/pkg/labelsfilter/filter_test.go
index 6354687caffbe..c8438a8c48722 100644
--- a/pkg/labelsfilter/filter_test.go
+++ b/pkg/labelsfilter/filter_test.go
@@ -8,6 +8,7 @@ import (
 	"regexp"
 	"testing"
 
+	"github.com/cilium/hive/hivetest"
 	"github.com/stretchr/testify/require"
 
 	k8sConst "github.com/cilium/cilium/pkg/k8s/apis/cilium.io"
@@ -25,7 +26,7 @@ func TestFilterLabels(t *testing.T) {
 		"io.cilium.k8s.policy.serviceaccount": labels.NewLabel("io.cilium.k8s.policy.serviceaccount", "luke", labels.LabelSourceContainer),
 	}
 
-	err := ParseLabelPrefixCfg([]string{":!ignor[eE]", "id.*", "foo"}, []string{}, "")
+	err := ParseLabelPrefixCfg(hivetest.Logger(t), []string{":!ignor[eE]", "id.*", "foo"}, []string{}, "")
 	require.NoError(t, err)
 	dlpcfg := validLabelPrefixes
 	allNormalLabels := map[string]string{
@@ -73,6 +74,7 @@ func TestFilterLabels(t *testing.T) {
 }
 
 func TestDefaultFilterLabels(t *testing.T) {
+	logger := hivetest.Logger(t)
 	wanted := labels.Labels{
 		"app.kubernetes.io":                   labels.NewLabel("app.kubernetes.io", "my-nginx", labels.LabelSourceContainer),
 		"id.lizards.k8s":                      labels.NewLabel("id.lizards.k8s", "web", labels.LabelSourceK8s),
@@ -86,7 +88,7 @@ func TestDefaultFilterLabels(t *testing.T) {
 		"io.cilium.k8s.policy.serviceaccount": labels.NewLabel("io.cilium.k8s.policy.serviceaccount", "luke", labels.LabelSourceContainer),
 	}
 
-	err := ParseLabelPrefixCfg([]string{}, []string{}, "")
+	err := ParseLabelPrefixCfg(logger, []string{}, []string{}, "")
 	require.NoError(t, err)
 	dlpcfg := validLabelPrefixes
 	allNormalLabels := map[string]string{
@@ -126,6 +128,7 @@ func TestDefaultFilterLabels(t *testing.T) {
 }
 
 func TestFilterLabelsDocExample(t *testing.T) {
+	logger := hivetest.Logger(t)
 	wanted := labels.Labels{
 
 		"io.cilium.k8s.namespace.labels":      labels.NewLabel("io.cilium.k8s.namespace.labels", "foo", labels.LabelSourceK8s),
@@ -140,7 +143,7 @@ func TestFilterLabelsDocExample(t *testing.T) {
 		"io.cilium.k8s.policy.serviceaccount": labels.NewLabel("io.cilium.k8s.policy.serviceaccount", "luke", labels.LabelSourceK8s),
 	}
 
-	err := ParseLabelPrefixCfg([]string{"k8s:io.kubernetes.pod.namespace", "k8s:k8s-app", "k8s:app", "k8s:name", "k8s:kind$", "k8s:other$"}, []string{}, "")
+	err := ParseLabelPrefixCfg(logger, []string{"k8s:io.kubernetes.pod.namespace", "k8s:k8s-app", "k8s:app", "k8s:name", "k8s:kind$", "k8s:other$"}, []string{}, "")
 	require.NoError(t, err)
 	dlpcfg := validLabelPrefixes
 	allNormalLabels := map[string]string{


Reviews:
user: login: tklauser
body: LGTM, one question regarding potential replacement of the default slog logger.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-25T09:48:18Z
user: login: aanm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T11:16:37Z
user: login: bimmlerd
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-25T13:58:43Z

Review comments:
diff_hunk: @@ -738,7 +738,7 @@ func (legacy *legacyOnLeader) onStart(_ cell.HookContext) error {
 	}
 
 	if legacy.clientset.IsEnabled() {
-		if err := labelsfilter.ParseLabelPrefixCfg(option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
+		if err := labelsfilter.ParseLabelPrefixCfg(logging.DefaultSlogLogger, option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
path: operator/cmd/root.go
user: login: tklauser
body: Could we use `legacy.logger` here instead?

```suggestion
		if err := labelsfilter.ParseLabelPrefixCfg(legacy.logger, option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
```
created_at: 2025-04-25T09:46:08Z
author_association: MEMBER
diff_hunk: @@ -738,7 +738,7 @@ func (legacy *legacyOnLeader) onStart(_ cell.HookContext) error {
 	}
 
 	if legacy.clientset.IsEnabled() {
-		if err := labelsfilter.ParseLabelPrefixCfg(option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
+		if err := labelsfilter.ParseLabelPrefixCfg(logging.DefaultSlogLogger, option.Config.Labels, option.Config.NodeLabels, option.Config.LabelPrefixFile); err != nil {
path: operator/cmd/root.go
user: login: aanm
body: oh, I didn't know that `legacy` already had a logger. I'll change it. I'm planning to do a final pass on all `logging.DefaultSlogLogger` once the slog conversion is almost done.
created_at: 2025-04-25T11:16:37Z
author_association: MEMBER

PR comments:
user: login: aanm
created_at: 2025-04-25T08:03:24Z
body: /test
author_association: MEMBER
user: login: aanm
created_at: 2025-04-25T08:23:45Z
body: /test
author_association: MEMBER
user: login: aanm
created_at: 2025-04-25T11:17:00Z
body: /test
author_association: MEMBER