Skip to content

Commit 914c9e2

Browse files
authored
Add LogLevel & LogFormat flags (#6520)
1 parent d27bdb8 commit 914c9e2

File tree

10 files changed

+207
-28
lines changed

10 files changed

+207
-28
lines changed

charts/nginx-ingress/templates/_helpers.tpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ Build the args for the service binary.
244244
- -health-status={{ .Values.controller.healthStatus }}
245245
- -health-status-uri={{ .Values.controller.healthStatusURI }}
246246
- -nginx-debug={{ .Values.controller.nginxDebug }}
247-
- -v={{ .Values.controller.logLevel }}
247+
- -log-level={{ .Values.controller.logLevel }}
248+
- -log-format={{ .Values.controller.logFormat }}
248249
- -nginx-status={{ .Values.controller.nginxStatus.enable }}
249250
{{- if .Values.controller.nginxStatus.enable }}
250251
- -nginx-status-port={{ .Values.controller.nginxStatus.port }}

charts/nginx-ingress/values.schema.json

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -486,17 +486,32 @@
486486
]
487487
},
488488
"logLevel": {
489-
"type": "integer",
490-
"default": 1,
489+
"type": "string",
490+
"default": "info",
491491
"title": "The logLevel of the Ingress Controller",
492492
"enum": [
493-
0,
494-
1,
495-
2,
496-
3
493+
"trace",
494+
"debug",
495+
"info",
496+
"warning",
497+
"error",
498+
"fatal"
499+
],
500+
"examples": [
501+
"info"
502+
]
503+
},
504+
"logFormat": {
505+
"type": "string",
506+
"default": "glog",
507+
"title": "The logFormat of the Ingress Controller",
508+
"enum": [
509+
"glog",
510+
"json",
511+
"text"
497512
],
498513
"examples": [
499-
1
514+
"json"
500515
]
501516
},
502517
"customPorts": {
@@ -1674,7 +1689,7 @@
16741689
"hostNetwork": false,
16751690
"nginxDebug": false,
16761691
"shareProcessNamespace": false,
1677-
"logLevel": 1,
1692+
"logLevel": "info",
16781693
"customPorts": [],
16791694
"image": {
16801695
"repository": "nginx/nginx-ingress",
@@ -2214,7 +2229,7 @@
22142229
},
22152230
"hostNetwork": false,
22162231
"nginxDebug": false,
2217-
"logLevel": 1,
2232+
"logLevel": "info",
22182233
"customPorts": [],
22192234
"image": {
22202235
"repository": "nginx/nginx-ingress",

charts/nginx-ingress/values.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,11 @@ controller:
123123
## Share process namespace between containers in the Ingress Controller pod.
124124
shareProcessNamespace: false
125125

126-
## The log level of the Ingress Controller.
127-
logLevel: 1
126+
## The log level of the Ingress Controller. Options include: trace, debug, info, warning, error, fatal
127+
logLevel: info
128+
129+
## Sets the log format of Ingress Controller. Options include: glog, json, text
130+
logFormat: glog
128131

129132
## A list of custom ports to expose on the NGINX Ingress Controller pod. Follows the conventional Kubernetes yaml syntax for container ports.
130133
customPorts: []

cmd/nginx-ingress/flags.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const (
1919
dynamicWeightChangesParam = "weight-changes-dynamic-reload"
2020
appProtectLogLevelDefault = "fatal"
2121
appProtectEnforcerAddrDefault = "127.0.0.1:50000"
22+
logLevelDefault = "info"
23+
logFormatDefault = "glog"
2224
)
2325

2426
var (
@@ -208,6 +210,11 @@ var (
208210

209211
enableTelemetryReporting = flag.Bool("enable-telemetry-reporting", true, "Enable gathering and reporting of product related telemetry.")
210212

213+
logFormat = flag.String("log-format", logFormatDefault, "Set log format to either glog, text, or json.")
214+
215+
logLevel = flag.String("log-level", logLevelDefault,
216+
`Sets log level for Ingress Controller. Allowed values: fatal, error, warning, info, debug, trace.`)
217+
211218
enableDynamicWeightChangesReload = flag.Bool(dynamicWeightChangesParam, false, "Enable changing weights of split clients without reloading NGINX. Requires -nginx-plus")
212219

213220
startupCheckFn func() error
@@ -223,6 +230,16 @@ func parseFlags() {
223230
}
224231

225232
func initValidate() {
233+
logFormatValidationError := validateLogFormat(*logFormat)
234+
if logFormatValidationError != nil {
235+
glog.Warningf("Invalid log format: %s. Valid options are: glog, text, json. Falling back to default: %s", *logFormat, logFormatDefault)
236+
}
237+
238+
logLevelValidationError := validateLogLevel(*logLevel)
239+
if logLevelValidationError != nil {
240+
glog.Warningf("Invalid log level: %s. Valid options are: trace, debug, info, warning, error, fatal. Falling back to default: %s", *logLevel, logLevelDefault)
241+
}
242+
226243
if *enableLatencyMetrics && !*enablePrometheusMetrics {
227244
glog.Warning("enable-latency-metrics flag requires enable-prometheus-metrics, latency metrics will not be collected")
228245
*enableLatencyMetrics = false
@@ -347,8 +364,8 @@ func mustValidateFlags() {
347364
}
348365

349366
if *appProtectLogLevel != appProtectLogLevelDefault && *appProtect && *nginxPlus {
350-
logLevelValidationError := validateAppProtectLogLevel(*appProtectLogLevel)
351-
if logLevelValidationError != nil {
367+
appProtectlogLevelValidationError := validateLogLevel(*appProtectLogLevel)
368+
if appProtectlogLevelValidationError != nil {
352369
glog.Fatalf("Invalid value for app-protect-log-level: %v", *appProtectLogLevel)
353370
}
354371
}
@@ -443,8 +460,8 @@ func validatePort(port int) error {
443460
return nil
444461
}
445462

446-
// validateAppProtectLogLevel makes sure a given logLevel is one of the allowed values
447-
func validateAppProtectLogLevel(logLevel string) error {
463+
// validateLogLevel makes sure a given logLevel is one of the allowed values
464+
func validateLogLevel(logLevel string) error {
448465
switch strings.ToLower(logLevel) {
449466
case
450467
"fatal",
@@ -455,7 +472,16 @@ func validateAppProtectLogLevel(logLevel string) error {
455472
"trace":
456473
return nil
457474
}
458-
return fmt.Errorf("invalid App Protect log level: %v", logLevel)
475+
return fmt.Errorf("invalid log level: %v", logLevel)
476+
}
477+
478+
// validateLogFormat makes sure a given logFormat is one of the allowed values
479+
func validateLogFormat(logFormat string) error {
480+
switch strings.ToLower(logFormat) {
481+
case "glog", "json", "text":
482+
return nil
483+
}
484+
return fmt.Errorf("invalid log format: %v", logFormat)
459485
}
460486

461487
// parseNginxStatusAllowCIDRs converts a comma separated CIDR/IP address string into an array of CIDR/IP addresses.

cmd/nginx-ingress/flags_test.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,17 @@ func TestValidateLocation(t *testing.T) {
125125
}
126126
}
127127

128-
func TestValidateAppProtectLogLevel(t *testing.T) {
128+
func TestValidateLogLevel(t *testing.T) {
129129
badLogLevels := []string{
130130
"",
131131
"critical",
132132
"none",
133133
"info;",
134134
}
135135
for _, badLogLevel := range badLogLevels {
136-
err := validateAppProtectLogLevel(badLogLevel)
136+
err := validateLogLevel(badLogLevel)
137137
if err == nil {
138-
t.Errorf("validateAppProtectLogLevel(%v) returned no error when it should have returned an error", badLogLevel)
138+
t.Errorf("validateLogLevel(%v) returned no error when it should have returned an error", badLogLevel)
139139
}
140140
}
141141

@@ -148,9 +148,9 @@ func TestValidateAppProtectLogLevel(t *testing.T) {
148148
"trace",
149149
}
150150
for _, goodLogLevel := range goodLogLevels {
151-
err := validateAppProtectLogLevel(goodLogLevel)
151+
err := validateLogLevel(goodLogLevel)
152152
if err != nil {
153-
t.Errorf("validateAppProtectLogLevel(%v) returned an error when it should have returned no error: %v", goodLogLevel, err)
153+
t.Errorf("validateLogLevel(%v) returned an error when it should have returned no error: %v", goodLogLevel, err)
154154
}
155155
}
156156
}
@@ -172,3 +172,30 @@ func TestValidateNamespaces(t *testing.T) {
172172
}
173173
}
174174
}
175+
176+
func TestValidateLogFormat(t *testing.T) {
177+
badLogFormats := []string{
178+
"",
179+
"jason",
180+
"txt",
181+
"gloog",
182+
}
183+
for _, badLogFormat := range badLogFormats {
184+
err := validateLogFormat(badLogFormat)
185+
if err == nil {
186+
t.Errorf("validateLogFormat(%v) returned no error when it should have returned an error", badLogFormat)
187+
}
188+
}
189+
190+
goodLogFormats := []string{
191+
"json",
192+
"text",
193+
"glog",
194+
}
195+
for _, goodLogFormat := range goodLogFormats {
196+
err := validateLogFormat(goodLogFormat)
197+
if err != nil {
198+
t.Errorf("validateLogFormat(%v) returned an error when it should have returned no error: %v", goodLogFormat, err)
199+
}
200+
}
201+
}

cmd/nginx-ingress/main.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"io"
7+
"log/slog"
68
"net"
79
"net/http"
810
"os"
@@ -41,12 +43,23 @@ import (
4143

4244
kitlog "github.com/go-kit/log"
4345
"github.com/go-kit/log/level"
46+
47+
nic_logger "github.com/nginxinc/kubernetes-ingress/internal/logger"
48+
nic_glog "github.com/nginxinc/kubernetes-ingress/internal/logger/glog"
4449
)
4550

4651
// Injected during build
4752
var (
4853
version string
4954
telemetryEndpoint string
55+
logLevels = map[string]slog.Level{
56+
"trace": nic_glog.LevelTrace,
57+
"debug": nic_glog.LevelDebug,
58+
"info": nic_glog.LevelInfo,
59+
"warning": nic_glog.LevelWarning,
60+
"error": nic_glog.LevelError,
61+
"fatal": nic_glog.LevelFatal,
62+
}
5063
)
5164

5265
const (
@@ -63,6 +76,9 @@ func main() {
6376
commitHash, commitTime, dirtyBuild := getBuildInfo()
6477
fmt.Printf("NGINX Ingress Controller Version=%v Commit=%v Date=%v DirtyState=%v Arch=%v/%v Go=%v\n", version, commitHash, commitTime, dirtyBuild, runtime.GOOS, runtime.GOARCH, runtime.Version())
6578
parseFlags()
79+
ctx := initLogger(*logFormat, logLevels[*logLevel], os.Stdout)
80+
_ = nic_logger.LoggerFromContext(ctx)
81+
6682
initValidate()
6783
parsedFlags := os.Args[1:]
6884

@@ -877,3 +893,25 @@ func updateSelfWithVersionInfo(kubeClient *kubernetes.Clientset, version, appPro
877893
glog.Errorf("Failed to update pod labels after %d attempts", maxRetries)
878894
}
879895
}
896+
897+
func initLogger(logFormat string, level slog.Level, out io.Writer) context.Context {
898+
programLevel := new(slog.LevelVar) // Info by default
899+
var h slog.Handler
900+
switch {
901+
case logFormat == "glog":
902+
h = nic_glog.New(out, &nic_glog.Options{Level: programLevel})
903+
case logFormat == "json":
904+
h = slog.NewJSONHandler(out, &slog.HandlerOptions{Level: programLevel})
905+
case logFormat == "text":
906+
h = slog.NewTextHandler(out, &slog.HandlerOptions{Level: programLevel})
907+
default:
908+
h = nic_glog.New(out, &nic_glog.Options{Level: programLevel})
909+
}
910+
l := slog.New(h)
911+
slog.SetDefault(l)
912+
c := context.Background()
913+
914+
programLevel.Set(level)
915+
916+
return nic_logger.ContextWithLogger(c, l)
917+
}

cmd/nginx-ingress/main_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"regexp"
6+
"testing"
7+
8+
nic_logger "github.com/nginxinc/kubernetes-ingress/internal/logger"
9+
nic_glog "github.com/nginxinc/kubernetes-ingress/internal/logger/glog"
10+
)
11+
12+
func TestLogFormats(t *testing.T) {
13+
testCases := []struct {
14+
name string
15+
format string
16+
wantre string
17+
}{
18+
{
19+
name: "glog format message",
20+
format: "glog",
21+
wantre: `^I\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`,
22+
},
23+
{
24+
name: "json format message",
25+
format: "json",
26+
wantre: `^{"time":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+.*","level":"INFO","msg":".*}`,
27+
},
28+
{
29+
name: "text format message",
30+
format: "text",
31+
wantre: `^time=\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+.*level=\w+\smsg=\w+`,
32+
},
33+
}
34+
t.Parallel()
35+
for _, tc := range testCases {
36+
t.Run(tc.name, func(t *testing.T) {
37+
var buf bytes.Buffer
38+
ctx := initLogger(tc.format, nic_glog.LevelInfo, &buf)
39+
l := nic_logger.LoggerFromContext(ctx)
40+
l.Log(ctx, nic_glog.LevelInfo, "test")
41+
got := buf.String()
42+
re := regexp.MustCompile(tc.wantre)
43+
if !re.MatchString(got) {
44+
t.Errorf("\ngot:\n%q\nwant:\n%q", got, tc.wantre)
45+
}
46+
})
47+
}
48+
}

docs/content/configuration/global-configuration/command-line-arguments.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,26 @@ Path to the TransportServer NGINX configuration template for a TransportServer r
324324

325325
Log level for V logs.
326326

327+
<a name="cmdoption-log-level"></a>
328+
329+
---
330+
331+
### -log-level `<string>`
332+
333+
Log level for Ingress Controller logs. Allowed values: fatal, error, warn, info, debug, trace.
334+
335+
- Default is `info`.
336+
337+
<a name="cmdoption-log-format"></a>
338+
339+
---
340+
341+
### -log-format `<string>`
342+
343+
Log format for Ingress Controller logs. Allowed values: glog, json, text.
344+
345+
- Default is `glog`.
346+
327347
<a name="cmdoption-version"></a>
328348

329349
---

docs/content/installation/installing-nic/installation-with-helm.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,8 @@ The following tables lists the configurable parameters of the NGINX Ingress Cont
309309
| **controller.hostNetwork** | Enables the Ingress Controller pods to use the host's network namespace. | false |
310310
| **controller.dnsPolicy** | DNS policy for the Ingress Controller pods. | ClusterFirst |
311311
| **controller.nginxDebug** | Enables debugging for NGINX. Uses the `nginx-debug` binary. Requires `error-log-level: debug` in the ConfigMap via `controller.config.entries`. | false |
312-
| **controller.logLevel** | The log level of the Ingress Controller. | 1 |
312+
| **controller.logLevel** | The log level of the Ingress Controller. | info |
313+
| **controller.logFormat** | The log format of the Ingress Controller. | glog |
313314
| **controller.image.digest** | The image digest of the Ingress Controller. | None |
314315
| **controller.image.repository** | The image repository of the Ingress Controller. | nginx/nginx-ingress |
315316
| **controller.image.tag** | The tag of the Ingress Controller image. | {{< nic-version >}} |

0 commit comments

Comments
 (0)