Skip to content

Commit

Permalink
feat: structured logging (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikouaj authored May 24, 2024
1 parent 9b96586 commit f3d08c9
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 119 deletions.
13 changes: 12 additions & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,18 @@ kind create cluster --config kind-poc-cluster.yaml
kind load docker-image --name poc kube-startup-cpu-boost:dev
```

4. Deploy controller on a cluster
4. Enable development logging and other options if needed

In `config/default/kustomization.yaml` uncomment the dev patch:

```yaml
# Uncomment below for development
- manager_config_dev_patch.yaml
```
Adapt the `config/default/manager_config_dev_patch.yaml` if needed.

5. Deploy controller on a cluster

```sh
make deploy IMG=docker.io/library/kube-startup-cpu-boost:dev
Expand Down
10 changes: 2 additions & 8 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@ import (

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
"go.uber.org/zap"
"go.uber.org/zap/zapcore"

_ "k8s.io/client-go/plugin/pkg/client/auth"

"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
ctrlZap "sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/webhook"

autoscalingv1alpha1 "github.com/google/kube-startup-cpu-boost/api/v1alpha1"
Expand Down Expand Up @@ -61,11 +59,7 @@ func main() {
setupLog.Error(err, "unable to load configuration")
os.Exit(1)
}
ctrlZapOpts := ctrlZap.Options{
Development: true,
Level: zap.NewAtomicLevelAt(zapcore.Level(cfg.ZapLogLevel)),
}
ctrl.SetLogger(ctrlZap.New(ctrlZap.UseFlagOptions(&ctrlZapOpts)))
ctrl.SetLogger(config.Logger(cfg.ZapDevelopment, cfg.ZapLogLevel))
tlsOpts := []func(*tls.Config){}

webhookServer := webhook.NewServer(webhook.Options{
Expand Down
111 changes: 3 additions & 108 deletions config/default/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ resources:
- ../rbac
- ../manager
- ../internalcert
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
#- ../certmanager

# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
#- ../prometheus

Expand All @@ -39,107 +36,5 @@ patchesStrategicMerge:
# crd/kustomization.yaml
- manager_webhook_patch.yaml

# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
# 'CERTMANAGER' needs to be enabled to use ca injection
#- webhookcainjection_patch.yaml

# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
# Uncomment the following replacements to add the cert-manager CA injection annotations
#replacements:
# - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs
# kind: Certificate
# group: cert-manager.io
# version: v1
# name: serving-cert # this name should match the one in certificate.yaml
# fieldPath: .metadata.namespace # namespace of the certificate CR
# targets:
# - select:
# kind: ValidatingWebhookConfiguration
# fieldPaths:
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
# options:
# delimiter: '/'
# index: 0
# create: true
# - select:
# kind: MutatingWebhookConfiguration
# fieldPaths:
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
# options:
# delimiter: '/'
# index: 0
# create: true
# - select:
# kind: CustomResourceDefinition
# fieldPaths:
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
# options:
# delimiter: '/'
# index: 0
# create: true
# - source:
# kind: Certificate
# group: cert-manager.io
# version: v1
# name: serving-cert # this name should match the one in certificate.yaml
# fieldPath: .metadata.name
# targets:
# - select:
# kind: ValidatingWebhookConfiguration
# fieldPaths:
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
# options:
# delimiter: '/'
# index: 1
# create: true
# - select:
# kind: MutatingWebhookConfiguration
# fieldPaths:
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
# options:
# delimiter: '/'
# index: 1
# create: true
# - select:
# kind: CustomResourceDefinition
# fieldPaths:
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
# options:
# delimiter: '/'
# index: 1
# create: true
# - source: # Add cert-manager annotation to the webhook Service
# kind: Service
# version: v1
# name: webhook-service
# fieldPath: .metadata.name # namespace of the service
# targets:
# - select:
# kind: Certificate
# group: cert-manager.io
# version: v1
# fieldPaths:
# - .spec.dnsNames.0
# - .spec.dnsNames.1
# options:
# delimiter: '.'
# index: 0
# create: true
# - source:
# kind: Service
# version: v1
# name: webhook-service
# fieldPath: .metadata.namespace # namespace of the service
# targets:
# - select:
# kind: Certificate
# group: cert-manager.io
# version: v1
# fieldPaths:
# - .spec.dnsNames.0
# - .spec.dnsNames.1
# options:
# delimiter: '.'
# index: 1
# create: true
# Uncomment below for development
#- manager_config_dev_patch.yaml
15 changes: 15 additions & 0 deletions config/default/manager_config_dev_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: manager
env:
- name: ZAP_DEVELOPMENT
value: "true"
- name: ZAP_LOG_LEVEL
value: "-5"
2 changes: 0 additions & 2 deletions config/default/manager_config_patch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: ZAP_LOG_LEVEL
value: "-5"
- name: "LEADER_ELECTION"
value: "true"
- name: METRICS_PROBE_BIND_ADDR
Expand Down
4 changes: 4 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
HealthProbeBindAddrDefault = ":8081"
SecureMetricsDefault = false
ZapLogLevelDefault = 0 // zapcore.InfoLevel
ZapDevelopmentDefault = false
)

// ConfigProvider provides the Kube Startup CPU Boost configuration
Expand All @@ -48,6 +49,8 @@ type Config struct {
SecureMetrics bool
// ZapLogLevel determines the log level for the ZAP logger
ZapLogLevel int
// ZapDevelopment determines if the ZAP logger is in development mode
ZapDevelopment bool
}

// LoadDefaults loads the default configuration values
Expand All @@ -59,4 +62,5 @@ func (c *Config) LoadDefaults() {
c.HealthProbeBindAddr = HealthProbeBindAddrDefault
c.SecureMetrics = SecureMetricsDefault
c.ZapLogLevel = ZapLogLevelDefault
c.ZapDevelopment = ZapDevelopmentDefault
}
3 changes: 3 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@ var _ = Describe("Config", func() {
It("has valid ZAP log level", func() {
Expect(cfg.ZapLogLevel).To(Equal(config.ZapLogLevelDefault))
})
It("has valid ZAP development ", func() {
Expect(cfg.ZapDevelopment).To(Equal(config.ZapDevelopmentDefault))
})
})
})
8 changes: 8 additions & 0 deletions internal/config/env_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
HealthProbeBindAddrEnvVar = "HEALTH_PROBE_BIND_ADDR"
SecureMetricsEnvVar = "SECURE_METRICS"
ZapLogLevelEnvVar = "ZAP_LOG_LEVEL"
ZapDevelopmentEnvVar = "ZAP_DEVELOPMENT"
)

type LookupEnvFunc func(key string) (string, bool)
Expand Down Expand Up @@ -91,6 +92,13 @@ func (p *EnvConfigProvider) LoadConfig() (*Config, error) {
errs = append(errs, fmt.Errorf("%s value is not an int: %s", ZapLogLevelEnvVar, err))
}
}
if v, ok := p.lookupFunc(ZapDevelopmentEnvVar); ok {
boolVal, err := strconv.ParseBool(v)
config.ZapDevelopment = boolVal
if err != nil {
errs = append(errs, fmt.Errorf("%s value is not a bool: %s", ZapDevelopmentEnvVar, err))
}
}
var err error
if len(errs) > 0 {
err = errors.Join(errs...)
Expand Down
8 changes: 8 additions & 0 deletions internal/config/env_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,13 @@ var _ = Describe("EnvProvider", func() {
Expect(cfg.ZapLogLevel).To(Equal(logLevel))
})
})
When("zap development variable is set", func() {
BeforeEach(func() {
lookupFuncMap[config.ZapDevelopmentEnvVar] = "true"
})
It("has valid zap development", func() {
Expect(cfg.ZapDevelopment).To(BeTrue())
})
})
})
})
64 changes: 64 additions & 0 deletions internal/config/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"github.com/go-logr/logr"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
ctrlZap "sigs.k8s.io/controller-runtime/pkg/log/zap"
)

func Logger(development bool, level int) logr.Logger {
ctrlZapOpts := ctrlZap.Options{
Development: true,
Level: zap.NewAtomicLevelAt(zapcore.Level(level)),
}
if !development {
ctrlZapOpts.Development = false
ctrlZapOpts.EncoderConfigOptions = []ctrlZap.EncoderConfigOption{
logEncoderOptionsProd(),
}
}
return ctrlZap.New(ctrlZap.UseFlagOptions(&ctrlZapOpts))
}

// logEncoderOptionsProd
func logEncoderOptionsProd() ctrlZap.EncoderConfigOption {
return func(ec *zapcore.EncoderConfig) {
ec.LevelKey = "severity"
ec.MessageKey = "message"
ec.TimeKey = "time"
ec.EncodeTime = zapcore.RFC3339TimeEncoder
ec.EncodeLevel = func(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
switch l {
case zapcore.InfoLevel:
enc.AppendString("info")
case zapcore.WarnLevel:
enc.AppendString("warning")
case zapcore.ErrorLevel:
enc.AppendString("error")
case zapcore.DPanicLevel:
enc.AppendString("critical")
case zapcore.PanicLevel:
enc.AppendString("alert")
case zapcore.FatalLevel:
enc.AppendString("emergency")
default:
enc.AppendString("debug")
}
}
}
}

0 comments on commit f3d08c9

Please sign in to comment.