diff --git a/aitelemetry/telemetrywrapper.go b/aitelemetry/telemetrywrapper.go index 06a134d2d2..39deebb802 100644 --- a/aitelemetry/telemetrywrapper.go +++ b/aitelemetry/telemetrywrapper.go @@ -3,6 +3,7 @@ package aitelemetry import ( "fmt" "os" + "path/filepath" "runtime" "time" @@ -36,6 +37,8 @@ const ( defaultRefreshTimeoutInSecs = 10 ) +var MetadataFile = filepath.Join(os.TempDir(), "azuremetadata.json") + type Level = contracts.SeverityLevel const ( @@ -98,7 +101,7 @@ func getMetadata(th *telemetryHandle) { // check if metadata in memory otherwise initiate wireserver request for { - metadata, err = common.GetHostMetadata(metadataFile) + metadata, err = common.GetHostMetadata(MetadataFile) if err == nil || th.disableMetadataRefreshThread { break } @@ -117,14 +120,14 @@ func getMetadata(th *telemetryHandle) { th.metadata = metadata th.rwmutex.Unlock() - lockclient, err := processlock.NewFileLock(metadataFile + store.LockExtension) + lockclient, err := processlock.NewFileLock(MetadataFile + store.LockExtension) if err != nil { log.Printf("Error initializing file lock:%v", err) return } // Save metadata retrieved from wireserver to a file - kvs, err := store.NewJsonFileStore(metadataFile, lockclient, nil) + kvs, err := store.NewJsonFileStore(MetadataFile, lockclient, nil) if err != nil { debugLog("[AppInsights] Error initializing kvs store: %v", err) return @@ -134,7 +137,7 @@ func getMetadata(th *telemetryHandle) { log.Errorf("getMetadata: Not able to acquire lock:%v", err) return } - metadataErr := common.SaveHostMetadata(th.metadata, metadataFile) + metadataErr := common.SaveHostMetadata(th.metadata, MetadataFile) err = kvs.Unlock() if err != nil { log.Errorf("getMetadata: Not able to release lock:%v", err) diff --git a/aitelemetry/telemetrywrapper_linux.go b/aitelemetry/telemetrywrapper_linux.go deleted file mode 100644 index 17bf74fc7c..0000000000 --- a/aitelemetry/telemetrywrapper_linux.go +++ /dev/null @@ -1,5 +0,0 @@ -package aitelemetry - -const ( - metadataFile = "/tmp/azuremetadata.json" -) diff --git a/aitelemetry/telemetrywrapper_windows.go b/aitelemetry/telemetrywrapper_windows.go deleted file mode 100644 index cd49357705..0000000000 --- a/aitelemetry/telemetrywrapper_windows.go +++ /dev/null @@ -1,8 +0,0 @@ -package aitelemetry - -import ( - "os" - "path/filepath" -) - -var metadataFile = filepath.FromSlash(os.Getenv("TEMP")) + "\\azuremetadata.json" diff --git a/cns/configuration/configuration.go b/cns/configuration/configuration.go index c183c9f0e2..e468b39d6a 100644 --- a/cns/configuration/configuration.go +++ b/cns/configuration/configuration.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-container-networking/cns" "github.com/Azure/azure-container-networking/cns/logger" + loggerv2 "github.com/Azure/azure-container-networking/cns/logger/v2" "github.com/Azure/azure-container-networking/common" "github.com/pkg/errors" ) @@ -30,12 +31,14 @@ type CNSConfig struct { EnableCNIConflistGeneration bool EnableIPAMv2 bool EnableK8sDevicePlugin bool + EnableLoggerV2 bool EnablePprof bool EnableStateMigration bool EnableSubnetScarcity bool EnableSwiftV2 bool InitializeFromCNI bool KeyVaultSettings KeyVaultSettings + Logger loggerv2.Config MSISettings MSISettings ManageEndpointState bool ManagedSettings ManagedSettings diff --git a/cns/logger/cnslogger.go b/cns/logger/cnslogger.go index a898859493..5289259903 100644 --- a/cns/logger/cnslogger.go +++ b/cns/logger/cnslogger.go @@ -17,7 +17,7 @@ import ( // wait time for closing AI telemetry session. const waitTimeInSecs = 10 -type CNSLogger struct { +type logger struct { logger *log.Logger zapLogger *zap.Logger th ai.TelemetryHandle @@ -30,7 +30,8 @@ type CNSLogger struct { metadata map[string]string } -func New(fileName string, logLevel, logTarget int, logDir string) (*CNSLogger, error) { +// Deprecated: The v1 logger is deprecated. Migrate to zap using the cns/logger/v2 package. +func New(fileName string, logLevel, logTarget int, logDir string) (loggershim, error) { l, err := log.NewLoggerE(fileName, logLevel, logTarget, logDir) if err != nil { return nil, errors.Wrap(err, "could not get new logger") @@ -46,18 +47,18 @@ func New(fileName string, logLevel, logTarget int, logDir string) (*CNSLogger, e } zapLogger := zap.New(platformCore, zap.AddCaller()).With(zap.Int("pid", os.Getpid())) - return &CNSLogger{ + return &logger{ logger: l, zapLogger: zapLogger, metadata: map[string]string{}, }, nil } -func (c *CNSLogger) InitAI(aiConfig ai.AIConfig, disableTraceLogging, disableMetricLogging, disableEventLogging bool) { +func (c *logger) InitAI(aiConfig ai.AIConfig, disableTraceLogging, disableMetricLogging, disableEventLogging bool) { c.InitAIWithIKey(aiConfig, aiMetadata, disableTraceLogging, disableMetricLogging, disableEventLogging) } -func (c *CNSLogger) InitAIWithIKey(aiConfig ai.AIConfig, instrumentationKey string, disableTraceLogging, disableMetricLogging, disableEventLogging bool) { +func (c *logger) InitAIWithIKey(aiConfig ai.AIConfig, instrumentationKey string, disableTraceLogging, disableMetricLogging, disableEventLogging bool) { th, err := ai.NewAITelemetry("", instrumentationKey, aiConfig) if err != nil { c.logger.Errorf("Error initializing AI Telemetry:%v", err) @@ -70,14 +71,14 @@ func (c *CNSLogger) InitAIWithIKey(aiConfig ai.AIConfig, instrumentationKey stri c.disableEventLogging = disableEventLogging } -func (c *CNSLogger) Close() { +func (c *logger) Close() { c.logger.Close() if c.th != nil { c.th.Close(waitTimeInSecs) } } -func (c *CNSLogger) SetContextDetails(orchestrator, nodeID string) { +func (c *logger) SetContextDetails(orchestrator, nodeID string) { c.logger.Logf("SetContext details called with: %v orchestrator nodeID %v", orchestrator, nodeID) c.m.Lock() c.metadata[orchestratorTypeKey] = orchestrator @@ -85,13 +86,13 @@ func (c *CNSLogger) SetContextDetails(orchestrator, nodeID string) { c.m.Unlock() } -func (c *CNSLogger) SetAPIServer(apiserver string) { +func (c *logger) SetAPIServer(apiserver string) { c.m.Lock() c.metadata[apiServerKey] = apiserver c.m.Unlock() } -func (c *CNSLogger) Printf(format string, args ...any) { +func (c *logger) Printf(format string, args ...any) { c.logger.Logf(format, args...) c.zapLogger.Info(fmt.Sprintf(format, args...)) if c.th == nil || c.disableTraceLogging { @@ -101,7 +102,7 @@ func (c *CNSLogger) Printf(format string, args ...any) { c.sendTraceInternal(msg, ai.InfoLevel) } -func (c *CNSLogger) Debugf(format string, args ...any) { +func (c *logger) Debugf(format string, args ...any) { c.logger.Debugf(format, args...) c.zapLogger.Debug(fmt.Sprintf(format, args...)) if c.th == nil || c.disableTraceLogging { @@ -111,7 +112,7 @@ func (c *CNSLogger) Debugf(format string, args ...any) { c.sendTraceInternal(msg, ai.DebugLevel) } -func (c *CNSLogger) Warnf(format string, args ...any) { +func (c *logger) Warnf(format string, args ...any) { c.logger.Warnf(format, args...) c.zapLogger.Warn(fmt.Sprintf(format, args...)) if c.th == nil || c.disableTraceLogging { @@ -121,7 +122,7 @@ func (c *CNSLogger) Warnf(format string, args ...any) { c.sendTraceInternal(msg, ai.WarnLevel) } -func (c *CNSLogger) Errorf(format string, args ...any) { +func (c *logger) Errorf(format string, args ...any) { c.logger.Errorf(format, args...) c.zapLogger.Error(fmt.Sprintf(format, args...)) if c.th == nil || c.disableTraceLogging { @@ -131,7 +132,7 @@ func (c *CNSLogger) Errorf(format string, args ...any) { c.sendTraceInternal(msg, ai.ErrorLevel) } -func (c *CNSLogger) Request(tag string, request any, err error) { +func (c *logger) Request(tag string, request any, err error) { c.logger.Request(tag, request, err) if c.th == nil || c.disableTraceLogging { return @@ -147,7 +148,7 @@ func (c *CNSLogger) Request(tag string, request any, err error) { c.sendTraceInternal(msg, lvl) } -func (c *CNSLogger) Response(tag string, response any, returnCode types.ResponseCode, err error) { +func (c *logger) Response(tag string, response any, returnCode types.ResponseCode, err error) { c.logger.Response(tag, response, int(returnCode), returnCode.String(), err) if c.th == nil || c.disableTraceLogging { return @@ -166,7 +167,7 @@ func (c *CNSLogger) Response(tag string, response any, returnCode types.Response c.sendTraceInternal(msg, lvl) } -func (c *CNSLogger) ResponseEx(tag string, request, response any, returnCode types.ResponseCode, err error) { +func (c *logger) ResponseEx(tag string, request, response any, returnCode types.ResponseCode, err error) { c.logger.ResponseEx(tag, request, response, int(returnCode), returnCode.String(), err) if c.th == nil || c.disableTraceLogging { return @@ -185,7 +186,7 @@ func (c *CNSLogger) ResponseEx(tag string, request, response any, returnCode typ c.sendTraceInternal(msg, lvl) } -func (c *CNSLogger) sendTraceInternal(msg string, lvl ai.Level) { +func (c *logger) sendTraceInternal(msg string, lvl ai.Level) { report := ai.Report{ Message: msg, Level: lvl, @@ -198,7 +199,7 @@ func (c *CNSLogger) sendTraceInternal(msg string, lvl ai.Level) { c.th.TrackLog(report) } -func (c *CNSLogger) LogEvent(event ai.Event) { +func (c *logger) LogEvent(event ai.Event) { if c.th == nil || c.disableEventLogging { return } @@ -208,7 +209,7 @@ func (c *CNSLogger) LogEvent(event ai.Event) { c.th.TrackEvent(event) } -func (c *CNSLogger) SendMetric(metric ai.Metric) { +func (c *logger) SendMetric(metric ai.Metric) { if c.th == nil || c.disableMetricLogging { return } diff --git a/cns/logger/log.go b/cns/logger/log.go index ec1d32056d..2a0d903a03 100644 --- a/cns/logger/log.go +++ b/cns/logger/log.go @@ -6,66 +6,95 @@ import ( "github.com/Azure/azure-container-networking/cns/types" ) +type loggershim interface { + Close() + InitAI(aitelemetry.AIConfig, bool, bool, bool) + InitAIWithIKey(aitelemetry.AIConfig, string, bool, bool, bool) + SetContextDetails(string, string) + SetAPIServer(string) + Printf(string, ...any) + Debugf(string, ...any) + Warnf(string, ...any) + LogEvent(aitelemetry.Event) + Errorf(string, ...any) + Request(string, any, error) + Response(string, any, types.ResponseCode, error) + ResponseEx(string, any, any, types.ResponseCode, error) + SendMetric(aitelemetry.Metric) +} + var ( - Log *CNSLogger - aiMetadata string // this var is set at build time. + Log loggershim AppInsightsIKey = aiMetadata + aiMetadata string // this var is set at build time. ) -// todo: the functions below should be removed. CNSLogger should be injected where needed and not used from package level scope. - +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Close() { Log.Close() } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func InitLogger(fileName string, logLevel, logTarget int, logDir string) { Log, _ = New(fileName, logLevel, logTarget, logDir) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func InitAI(aiConfig aitelemetry.AIConfig, disableTraceLogging, disableMetricLogging, disableEventLogging bool) { Log.InitAI(aiConfig, disableTraceLogging, disableMetricLogging, disableEventLogging) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func InitAIWithIKey(aiConfig aitelemetry.AIConfig, instrumentationKey string, disableTraceLogging, disableMetricLogging, disableEventLogging bool) { Log.InitAIWithIKey(aiConfig, instrumentationKey, disableTraceLogging, disableMetricLogging, disableEventLogging) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func SetContextDetails(orchestrator, nodeID string) { Log.SetContextDetails(orchestrator, nodeID) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Printf(format string, args ...any) { Log.Printf(format, args...) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Debugf(format string, args ...any) { Log.Debugf(format, args...) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Warnf(format string, args ...any) { Log.Warnf(format, args...) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func LogEvent(event aitelemetry.Event) { Log.LogEvent(event) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Errorf(format string, args ...any) { Log.Errorf(format, args...) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Request(tag string, request any, err error) { Log.Request(tag, request, err) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func Response(tag string, response any, returnCode types.ResponseCode, err error) { Log.Response(tag, response, returnCode, err) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func ResponseEx(tag string, request, response any, returnCode types.ResponseCode, err error) { Log.ResponseEx(tag, request, response, returnCode, err) } +// Deprecated: The global logger is deprecated. Migrate to zap using the cns/logger/v2 package and pass the logger instead. func SendMetric(metric aitelemetry.Metric) { Log.SendMetric(metric) } diff --git a/cns/logger/v2/config.go b/cns/logger/v2/config.go index d64d6486fa..5f4a095fb3 100644 --- a/cns/logger/v2/config.go +++ b/cns/logger/v2/config.go @@ -42,8 +42,8 @@ func (c *Config) UnmarshalJSON(data []byte) error { return nil } -// Normalize checks the Config for missing or illegal values and sets them -// to defaults if appropriate. +// Normalize checks the Config for missing/default values and sets them +// if appropriate. func (c *Config) Normalize() { if c.File != nil { if c.File.Filepath == "" { diff --git a/cns/logger/v2/cores/ai.go b/cns/logger/v2/cores/ai.go index 76ba6add65..d7cc82b801 100644 --- a/cns/logger/v2/cores/ai.go +++ b/cns/logger/v2/cores/ai.go @@ -62,6 +62,6 @@ func ApplicationInsightsCore(cfg *AppInsightsConfig) (zapcore.Core, func(), erro core := zapai.NewCore(cfg.level, sink) core = core.WithFieldMappers(zapai.DefaultMappers) // add normalized fields for the built-in AI Tags - // TODO(rbtr): move to the caller + return core.With(cfg.Fields), aiclose, nil } diff --git a/cns/logger/v2/cores/etw_windows.go b/cns/logger/v2/cores/etw_windows.go index 51e6656f48..da0d49b672 100644 --- a/cns/logger/v2/cores/etw_windows.go +++ b/cns/logger/v2/cores/etw_windows.go @@ -1,15 +1,41 @@ package logger import ( + "encoding/json" + "github.com/Azure/azure-container-networking/zapetw" + "github.com/pkg/errors" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) type ETWConfig struct { - EventName string - Level zapcore.Level - ProviderName string + EventName string `json:"eventname"` + Level string `json:"level"` + level zapcore.Level `json:"-"` + ProviderName string `json:"providername"` + Fields []zapcore.Field `json:"fields"` +} + +// UnmarshalJSON implements json.Unmarshaler for the Config. +// It only differs from the default by parsing the +// Level string into a zapcore.Level and setting the level field. +func (cfg *ETWConfig) UnmarshalJSON(data []byte) error { + type Alias ETWConfig + aux := &struct { + *Alias + }{ + Alias: (*Alias)(cfg), + } + if err := json.Unmarshal(data, &aux); err != nil { + return errors.Wrap(err, "failed to unmarshal ETWConfig") + } + lvl, err := zapcore.ParseLevel(cfg.Level) + if err != nil { + return errors.Wrap(err, "failed to parse ETWConfig Level") + } + cfg.level = lvl + return nil } // ETWCore builds a zapcore.Core that sends logs to ETW. @@ -18,5 +44,5 @@ func ETWCore(cfg *ETWConfig) (zapcore.Core, func(), error) { encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder jsonEncoder := zapcore.NewJSONEncoder(encoderConfig) - return zapetw.New(cfg.ProviderName, cfg.EventName, jsonEncoder, cfg.Level) //nolint:wrapcheck // ignore + return zapetw.New(cfg.ProviderName, cfg.EventName, jsonEncoder, cfg.level) //nolint:wrapcheck // ignore } diff --git a/cns/logger/v2/cores/file.go b/cns/logger/v2/cores/file.go index 21b6b1182a..7aa01bb8e7 100644 --- a/cns/logger/v2/cores/file.go +++ b/cns/logger/v2/cores/file.go @@ -10,11 +10,12 @@ import ( ) type FileConfig struct { - Filepath string `json:"filepath"` - Level string `json:"level"` - level zapcore.Level `json:"-"` - MaxBackups int `json:"maxBackups"` - MaxSize int `json:"maxSize"` + Filepath string `json:"filepath"` + Level string `json:"level"` + level zapcore.Level `json:"-"` + MaxBackups int `json:"maxBackups"` + MaxSize int `json:"maxSize"` + Fields []zapcore.Field `json:"fields"` } // UnmarshalJSON implements json.Unmarshaler for the Config. diff --git a/cns/logger/v2/cores/stdout.go b/cns/logger/v2/cores/stdout.go index 93ad09767a..9882483690 100644 --- a/cns/logger/v2/cores/stdout.go +++ b/cns/logger/v2/cores/stdout.go @@ -1,13 +1,42 @@ package logger import ( + "encoding/json" "os" logfmt "github.com/jsternberg/zap-logfmt" + "github.com/pkg/errors" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) +type StdoutConfig struct { + Level string `json:"level"` + level zapcore.Level `json:"-"` + Fields []zapcore.Field `json:"fields"` +} + +// UnmarshalJSON implements json.Unmarshaler for the Config. +// It only differs from the default by parsing the +// Level string into a zapcore.Level and setting the level field. +func (cfg *StdoutConfig) UnmarshalJSON(data []byte) error { + type Alias StdoutConfig + aux := &struct { + *Alias + }{ + Alias: (*Alias)(cfg), + } + if err := json.Unmarshal(data, &aux); err != nil { + return errors.Wrap(err, "failed to unmarshal StdoutConfig") + } + lvl, err := zapcore.ParseLevel(cfg.Level) + if err != nil { + return errors.Wrap(err, "failed to parse StdoutConfig Level") + } + cfg.level = lvl + return nil +} + // StdoutCore builds a zapcore.Core that writes to stdout. func StdoutCore(l zapcore.Level) zapcore.Core { encoderConfig := zap.NewProductionEncoderConfig() diff --git a/cns/logger/v2/fields.go b/cns/logger/v2/fields.go new file mode 100644 index 0000000000..926ac0720f --- /dev/null +++ b/cns/logger/v2/fields.go @@ -0,0 +1,23 @@ +package logger + +import ( + "github.com/Azure/azure-container-networking/common" + "go.uber.org/zap" +) + +// MetadataToFields transforms Az IMDS Metadata in to zap.Field for +// attaching to a root zap core or logger instance. +// This uses the nice-names from the zapai.DefaultMappers instead of +// raw AppInsights key names. +func MetadataToFields(meta common.Metadata) []zap.Field { + return []zap.Field{ + zap.String("account", meta.SubscriptionID), + zap.String("anonymous_user_id", meta.VMName), + zap.String("location", meta.Location), + zap.String("resource_group", meta.ResourceGroupName), + zap.String("vm_size", meta.VMSize), + zap.String("os_version", meta.OSVersion), + zap.String("vm_id", meta.VMID), + zap.String("session_id", meta.VMID), + } +} diff --git a/cns/logger/v2/logger.go b/cns/logger/v2/logger.go index 2064f18e1c..f5c5c3a85b 100644 --- a/cns/logger/v2/logger.go +++ b/cns/logger/v2/logger.go @@ -1,3 +1,5 @@ +// Package logger provides an opinionated logger for CNS which knows how to +// log to Application Insights, file, stdout and ETW (based on platform). package logger import ( @@ -14,6 +16,7 @@ func (c compoundCloser) Close() { } } +// New creates a v2 CNS logger built with Zap. func New(cfg *Config) (*zap.Logger, func(), error) { cfg.Normalize() core := cores.StdoutCore(cfg.level) diff --git a/cns/logger/v2/logger_linux.go b/cns/logger/v2/logger_linux.go index c875f3faaf..e0311284fc 100644 --- a/cns/logger/v2/logger_linux.go +++ b/cns/logger/v2/logger_linux.go @@ -4,7 +4,7 @@ import ( "go.uber.org/zap/zapcore" ) -// platformCore returns a no-op core for Linux. +// On Linux, platformCore returns a no-op core. func platformCore(*Config) (zapcore.Core, func(), error) { return zapcore.NewNopCore(), func() {}, nil } diff --git a/cns/logger/v2/logger_windows.go b/cns/logger/v2/logger_windows.go index e6e5f198dc..186fae1f14 100644 --- a/cns/logger/v2/logger_windows.go +++ b/cns/logger/v2/logger_windows.go @@ -5,7 +5,7 @@ import ( "go.uber.org/zap/zapcore" ) -// platformCore returns a zapcore.Core that sends logs to ETW. +// On Windows, platformCore returns a zapcore.Core that sends logs to ETW. func platformCore(cfg *Config) (zapcore.Core, func(), error) { if cfg.ETW == nil { return zapcore.NewNopCore(), func() {}, nil diff --git a/cns/logger/v2/shim.go b/cns/logger/v2/shim.go new file mode 100644 index 0000000000..b427cef8f4 --- /dev/null +++ b/cns/logger/v2/shim.go @@ -0,0 +1,64 @@ +package logger + +import ( + "github.com/Azure/azure-container-networking/aitelemetry" + "github.com/Azure/azure-container-networking/cns/types" + "go.uber.org/zap" +) + +// shim wraps the Zap logger to provide a compatible interface to the +// legacy CNS logger. This is temporary and exists to make migration +// feasible and optional. +type shim struct { + z *zap.Logger + closer func() +} + +func (s *shim) Close() { + _ = s.z.Sync() + s.closer() +} + +func (s *shim) Printf(format string, a ...any) { + s.z.Sugar().Infof(format, a...) +} + +func (s *shim) Debugf(format string, a ...any) { + s.z.Sugar().Debugf(format, a...) +} + +func (s *shim) Warnf(format string, a ...any) { + s.z.Sugar().Warnf(format, a...) +} + +func (s *shim) Errorf(format string, a ...any) { + s.z.Sugar().Errorf(format, a...) +} + +func (s *shim) Request(msg string, data any, err error) { + s.z.Sugar().Infow("Request", "message", msg, "data", data, "error", err) +} + +func (s *shim) Response(msg string, data any, code types.ResponseCode, err error) { + s.z.Sugar().Infow("Response", "message", msg, "data", data, "code", code, "error", err) +} + +func (s *shim) ResponseEx(msg string, request, response any, code types.ResponseCode, err error) { + s.z.Sugar().Infow("ResponseEx", "message", msg, "request", request, "response", response, "code", code, "error", err) +} + +func (*shim) InitAI(aitelemetry.AIConfig, bool, bool, bool) {} + +func (*shim) InitAIWithIKey(aitelemetry.AIConfig, string, bool, bool, bool) {} + +func (s *shim) SetContextDetails(string, string) {} + +func (s *shim) SetAPIServer(string) {} + +func (s *shim) SendMetric(aitelemetry.Metric) {} + +func (s *shim) LogEvent(aitelemetry.Event) {} + +func AsV1(z *zap.Logger, closer func()) *shim { //nolint:revive // I want it to be annoying to use. + return &shim{z: z, closer: closer} +} diff --git a/cns/service/main.go b/cns/service/main.go index fb1655accd..e5348da028 100644 --- a/cns/service/main.go +++ b/cns/service/main.go @@ -41,6 +41,7 @@ import ( nncctrl "github.com/Azure/azure-container-networking/cns/kubecontroller/nodenetworkconfig" podctrl "github.com/Azure/azure-container-networking/cns/kubecontroller/pod" "github.com/Azure/azure-container-networking/cns/logger" + loggerv2 "github.com/Azure/azure-container-networking/cns/logger/v2" "github.com/Azure/azure-container-networking/cns/metric" "github.com/Azure/azure-container-networking/cns/middlewares" "github.com/Azure/azure-container-networking/cns/multitenantcontroller" @@ -66,10 +67,10 @@ import ( "github.com/Azure/azure-container-networking/store" "github.com/Azure/azure-container-networking/telemetry" "github.com/avast/retry-go/v4" + "github.com/go-logr/zapr" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" "go.uber.org/zap" - "go.uber.org/zap/zapcore" "golang.org/x/time/rate" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -84,7 +85,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/healthz" - ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap" ctrlmgr "sigs.k8s.io/controller-runtime/pkg/manager" ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics/server" ) @@ -130,7 +130,6 @@ const ( var ( rootCtx context.Context rootErrCh chan error - z *zap.Logger ) // Version is populated by make during build. @@ -629,13 +628,28 @@ func main() { } } - // configure zap logger - zconfig := zap.NewProductionConfig() - zconfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - if z, err = zconfig.Build(); err != nil { + // Get host metadata and attach it to logger(v2) appinsights config. + // If this errors, we will not have metadata in the AI logs. Should we exit? + metadata, _ := acn.GetHostMetadata(aitelemetry.MetadataFile) + aifields := loggerv2.MetadataToFields(metadata) + if cnsconfig.Logger.AppInsights != nil { + cnsconfig.Logger.AppInsights.Fields = append(cnsconfig.Logger.AppInsights.Fields, aifields...) + } + + // build the zap logger + z, c, err := loggerv2.New(&cnsconfig.Logger) + defer c() + if err != nil { fmt.Printf("failed to create logger: %v", err) os.Exit(1) } + host, _ := os.Hostname() + z = z.With(zap.String("hostname", host), zap.String("version", version), zap.String("kubernetes_apiserver", os.Getenv("KUBERNETES_SERVICE_HOST"))) + // Set the v2 logger to the global logger if v2 logger enabled. + if cnsconfig.EnableLoggerV2 { + logger.Printf("hotswapping logger v2") //nolint:staticcheck // ignore new deprecation + logger.Log = loggerv2.AsV1(z, c) + } // start the healthz/readyz/metrics server readyCh := make(chan interface{}) @@ -866,7 +880,7 @@ func main() { logger.Printf("Set GlobalPodInfoScheme %v (InitializeFromCNI=%t)", cns.GlobalPodInfoScheme, cnsconfig.InitializeFromCNI) - err = InitializeCRDState(rootCtx, httpRemoteRestService, cnsconfig) + err = InitializeCRDState(rootCtx, z, httpRemoteRestService, cnsconfig) if err != nil { logger.Errorf("Failed to start CRD Controller, err:%v.\n", err) return @@ -1369,7 +1383,9 @@ func reconcileInitialCNSState(ctx context.Context, cli nodeNetworkConfigGetter, } // InitializeCRDState builds and starts the CRD controllers. -func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cnsconfig *configuration.CNSConfig) error { +// +//nolint:gocyclo // legacy +func InitializeCRDState(ctx context.Context, z *zap.Logger, httpRestService cns.HTTPService, cnsconfig *configuration.CNSConfig) error { // convert interface type to implementation type httpRestServiceImplementation, ok := httpRestService.(*restserver.HTTPRestService) if !ok { @@ -1511,7 +1527,7 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn Scheme: scheme, Metrics: ctrlmetrics.Options{BindAddress: "0"}, Cache: cacheOpts, - Logger: ctrlzap.New(), + Logger: zapr.NewLogger(z), } manager, err := ctrl.NewManager(kubeConfig, managerOpts)