This is an automated email from the ASF dual-hosted git repository.
orpiske pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push:
new 475fc8d Configure kubernetes to use structured log
475fc8d is described below
commit 475fc8d58a79e602724442f96bcc72f819380505
Author: Otavio Rodolfo Piske <[email protected]>
AuthorDate: Thu May 13 13:57:05 2021 +0200
Configure kubernetes to use structured log
Also include an integration test to ensure no unstructured logs leak
from other parts of the code
---
e2e/common/operator_metrics_test.go | 20 +++++++++----
e2e/common/structured_logs_test.go | 58 +++++++++++++++++++++++++++++++++++++
e2e/support/test_support.go | 12 ++++++--
e2e/support/util/structured_log.go | 26 +++++++++++++++--
pkg/cmd/operator/operator.go | 3 ++
5 files changed, 110 insertions(+), 9 deletions(-)
diff --git a/e2e/common/operator_metrics_test.go
b/e2e/common/operator_metrics_test.go
index fa10779..ebe6dc2 100644
--- a/e2e/common/operator_metrics_test.go
+++ b/e2e/common/operator_metrics_test.go
@@ -56,7 +56,7 @@ func TestMetrics(t *testing.T) {
pod := OperatorPod(ns)()
Expect(pod).NotTo(BeNil())
- logs := StructuredLogs(ns, pod.Name, corev1.PodLogOptions{})
+ logs := StructuredLogs(ns, pod.Name, corev1.PodLogOptions{},
false)
Expect(logs).NotTo(BeEmpty())
response, err := TestClient().CoreV1().RESTClient().Get().
@@ -81,14 +81,19 @@ func TestMetrics(t *testing.T) {
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName":
Equal("camel-k.controller.build"),
"Message": Equal("Build state
transition"),
- "Phase":
Equal(string(v1.BuildPhasePending)),
+ "Phase": MatchFields(IgnoreExtras,
+ Fields{
+ "Name":
Equal(string(v1.BuildPhasePending)),
+ }),
"RequestName": Equal(build.Name),
}), LogEntryNoop).
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName":
Equal("camel-k.controller.build"),
"Message": Equal("Reconciling
Build"),
"RequestName": Equal(build.Name),
- }), func(l *LogEntry) { ts1 = l.Timestamp.Time
}).
+ }), func(l *LogEntry) {
+ ts1 = l.Timestamp.Time
+ }).
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName": Equal("camel-k.builder"),
"Message": HavePrefix("resolved base
image:"),
@@ -97,7 +102,9 @@ func TestMetrics(t *testing.T) {
"LoggerName":
Equal("camel-k.controller.build"),
"Message": Equal("Reconciling
Build"),
"RequestName": Equal(build.Name),
- }), func(l *LogEntry) { ts2 = l.Timestamp.Time
}).
+ }), func(l *LogEntry) {
+ ts2 = l.Timestamp.Time
+ }).
Walk()
Expect(err).To(BeNil())
Expect(ts1).NotTo(BeZero())
@@ -337,7 +344,10 @@ func TestMetrics(t *testing.T) {
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName":
Equal("camel-k.controller.build"),
"Message": Equal("Build state
transition"),
- "Phase":
Equal(string(v1.BuildPhasePending)),
+ "Phase": MatchFields(IgnoreExtras,
+ Fields{
+ "Name":
Equal(string(v1.BuildPhasePending)),
+ }),
"RequestName": Equal(build.Name),
}), func(l *LogEntry) { ts2 = l.Timestamp.Time
}).
Walk()
diff --git a/e2e/common/structured_logs_test.go
b/e2e/common/structured_logs_test.go
new file mode 100644
index 0000000..e80a820
--- /dev/null
+++ b/e2e/common/structured_logs_test.go
@@ -0,0 +1,58 @@
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go ->
Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You 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
+
+ http://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 common
+
+import (
+ . "github.com/onsi/gomega"
+ "testing"
+
+ corev1 "k8s.io/api/core/v1"
+
+ . "github.com/apache/camel-k/e2e/support"
+ v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+)
+
+func TestStructuredLogs(t *testing.T) {
+ WithNewTestNamespace(t, func(ns string) {
+ name := "java"
+ Expect(Kamel("install", "-n", ns).Execute()).To(Succeed())
+ Expect(Kamel("run", "-n", ns, "files/Java.java",
+ "-t", "logging.format=json").Execute()).To(Succeed())
+ Eventually(IntegrationPodPhase(ns, name),
TestTimeoutMedium).Should(Equal(corev1.PodRunning))
+ Eventually(IntegrationCondition(ns, name,
v1.IntegrationConditionReady),
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+
+ pod := OperatorPod(ns)()
+ Expect(pod).NotTo(BeNil())
+
+ logs := StructuredLogs(ns, pod.Name, corev1.PodLogOptions{},
false)
+ Expect(logs).NotTo(BeEmpty())
+
+ it := Integration(ns, name)()
+ Expect(it).NotTo(BeNil())
+ build := Build(ns, it.Status.IntegrationKit.Name)()
+ Expect(build).NotTo(BeNil())
+
+ // Clean up
+ Expect(Kamel("delete", "--all", "-n",
ns).Execute()).To(Succeed())
+ })
+}
+
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index cdc0998..ad57ef6 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -266,7 +266,7 @@ func Logs(ns, podName string, options corev1.PodLogOptions)
func() string {
}
}
-func StructuredLogs(ns, podName string, options corev1.PodLogOptions)
[]util.LogEntry {
+func StructuredLogs(ns, podName string, options corev1.PodLogOptions,
ignoreParseErrors bool) []util.LogEntry {
byteReader, err := TestClient().CoreV1().Pods(ns).GetLogs(podName,
&options).Stream(TestContext)
if err != nil {
log.Error(err, "Error while reading container logs")
@@ -285,8 +285,16 @@ func StructuredLogs(ns, podName string, options
corev1.PodLogOptions) []util.Log
t := scanner.Text()
err := json.Unmarshal([]byte(t), &entry)
if err != nil {
- continue
+ if ignoreParseErrors {
+ continue
+ } else {
+ log.Errorf(err, "Unable to parse structured
content: %s", t)
+ return nil
+ }
}
+
+ log.Debug("Parsed: %s with phase '%s'\n", entry.Message,
entry.Phase.Name)
+
entries = append(entries, entry)
}
diff --git a/e2e/support/util/structured_log.go
b/e2e/support/util/structured_log.go
index ca26628..7b621dc 100644
--- a/e2e/support/util/structured_log.go
+++ b/e2e/support/util/structured_log.go
@@ -20,6 +20,7 @@ limitations under the License.
package util
import (
+ "encoding/json"
"math"
"strconv"
"time"
@@ -43,6 +44,27 @@ func (t *Time) UnmarshalJSON(s []byte) (err error) {
return nil
}
+type Phase struct {
+ Name string
+}
+
+func (p *Phase) UnmarshalJSON(b []byte) error {
+ if b[0] != '"' {
+ var tmp int
+
+ json.Unmarshal(b, &tmp)
+ p.Name = strconv.Itoa(tmp)
+
+ return nil
+ }
+
+ if err := json.Unmarshal(b, &p.Name); err != nil {
+ return err
+ }
+
+ return nil
+}
+
type LogEntry struct {
// Zap
Level zapcore.Level `json:"level,omitempty"`
@@ -57,7 +79,7 @@ type LogEntry struct {
// Camel K
Namespace string `json:"ns,omitempty"`
Name string `json:"name,omitempty"`
- Phase string `json:"phase,omitempty"`
+ Phase Phase `json:"phase,omitempty"`
PhaseFrom string `json:"phase-from,omitempty"`
PhaseTo string `json:"phase-to,omitempty"`
-}
+}
\ No newline at end of file
diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go
index 31b4da6..c64f503 100644
--- a/pkg/cmd/operator/operator.go
+++ b/pkg/cmd/operator/operator.go
@@ -21,6 +21,7 @@ import (
"context"
"flag"
"fmt"
+ "k8s.io/klog/v2"
"math/rand"
"os"
"runtime"
@@ -77,6 +78,8 @@ func Run(healthPort, monitoringPort int32) {
o.Development = false
}))
+ klog.SetLogger(log)
+
printVersion()
watchNamespace, err := getWatchNamespace()