From f5433f460dec73a340608863a1557b78f4bb84d8 Mon Sep 17 00:00:00 2001 From: googs1025 Date: Sat, 21 Dec 2024 19:32:16 +0800 Subject: [PATCH] feature: add custom message for systemlogmonitor rule --- pkg/systemlogmonitor/README.md | 3 +- pkg/systemlogmonitor/config.go | 2 +- pkg/systemlogmonitor/log_monitor.go | 11 +++++-- pkg/systemlogmonitor/log_monitor_test.go | 38 ++++++++++++++++++++++++ pkg/systemlogmonitor/types/types.go | 5 ++++ 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/pkg/systemlogmonitor/README.md b/pkg/systemlogmonitor/README.md index 796ed30af..f86e55279 100644 --- a/pkg/systemlogmonitor/README.md +++ b/pkg/systemlogmonitor/README.md @@ -37,7 +37,8 @@ with new rule definition: "type": "temporary/permanent", "condition": "NodeConditionOfPermanentIssue", "reason": "CamelCaseShortReason", - "pattern": "regexp matching the issue in the log" + "pattern": "regexp matching the issue in the log", + "patternGeneratedMessageSuffix": "Please check the network connectivity and ensure that all required services are running. For more details, see our documentation at https://example.com/docs/troubleshooting." } ``` diff --git a/pkg/systemlogmonitor/config.go b/pkg/systemlogmonitor/config.go index 2ac0013f8..bbc5c1115 100644 --- a/pkg/systemlogmonitor/config.go +++ b/pkg/systemlogmonitor/config.go @@ -46,7 +46,7 @@ type MonitorConfig struct { EnableMetricsReporting *bool `json:"metricsReporting,omitempty"` } -// ApplyConfiguration applies default configurations. +// ApplyDefaultConfiguration applies default configurations. func (mc *MonitorConfig) ApplyDefaultConfiguration() { if mc.BufferSize == 0 { mc.BufferSize = defaultBufferSize diff --git a/pkg/systemlogmonitor/log_monitor.go b/pkg/systemlogmonitor/log_monitor.go index 254ae5448..cb0cdd0b4 100644 --- a/pkg/systemlogmonitor/log_monitor.go +++ b/pkg/systemlogmonitor/log_monitor.go @@ -18,6 +18,7 @@ package systemlogmonitor import ( "encoding/json" + "fmt" "os" "time" @@ -165,7 +166,7 @@ func (l *logMonitor) parseLog(log *systemlogtypes.Log) { func (l *logMonitor) generateStatus(logs []*systemlogtypes.Log, rule systemlogtypes.Rule) *types.Status { // We use the timestamp of the first log line as the timestamp of the status. timestamp := logs[0].Timestamp - message := generateMessage(logs) + message := generateMessage(logs, rule.PatternGeneratedMessageSuffix) var events []types.Event var changedConditions []*types.Condition if rule.Type == types.Temp { @@ -250,10 +251,14 @@ func initialConditions(defaults []types.Condition) []types.Condition { return conditions } -func generateMessage(logs []*systemlogtypes.Log) string { +func generateMessage(logs []*systemlogtypes.Log, patternGeneratedMessageSuffix string) string { messages := []string{} for _, log := range logs { messages = append(messages, log.Message) } - return concatLogs(messages) + logMessage := concatLogs(messages) + if patternGeneratedMessageSuffix != "" { + return fmt.Sprintf("%s; %s", logMessage, patternGeneratedMessageSuffix) + } + return logMessage } diff --git a/pkg/systemlogmonitor/log_monitor_test.go b/pkg/systemlogmonitor/log_monitor_test.go index ac18e9e14..230e9c659 100644 --- a/pkg/systemlogmonitor/log_monitor_test.go +++ b/pkg/systemlogmonitor/log_monitor_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/node-problem-detector/pkg/problemdaemon" "k8s.io/node-problem-detector/pkg/problemmetrics" logtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types" + systemlogtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types" "k8s.io/node-problem-detector/pkg/types" "k8s.io/node-problem-detector/pkg/util" "k8s.io/node-problem-detector/pkg/util/metrics" @@ -699,3 +700,40 @@ func TestInitializeProblemMetricsOrDie(t *testing.T) { }) } } + +func TestGenerateMessage(t *testing.T) { + tests := []struct { + name string + logs []*systemlogtypes.Log + patternGeneratedMessageSuffix string + want string + }{ + { + name: "No rule message", + logs: []*systemlogtypes.Log{ + {Message: "First log message"}, + {Message: "Second log message"}, + }, + patternGeneratedMessageSuffix: "", + want: "First log message\nSecond log message", + }, + { + name: "With rule message", + logs: []*systemlogtypes.Log{ + {Message: "First log message"}, + {Message: "Second log message"}, + }, + patternGeneratedMessageSuffix: "refer www.foo.com/docs for playbook on how to fix the issue", + want: "First log message\nSecond log message; refer www.foo.com/docs for playbook on how to fix the issue", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := generateMessage(tt.logs, tt.patternGeneratedMessageSuffix) + if got != tt.want { + t.Errorf("generateMessage() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/systemlogmonitor/types/types.go b/pkg/systemlogmonitor/types/types.go index b46facd48..75c3e6e57 100644 --- a/pkg/systemlogmonitor/types/types.go +++ b/pkg/systemlogmonitor/types/types.go @@ -42,4 +42,9 @@ type Rule struct { // Pattern is the regular expression to match the problem in log. // Notice that the pattern must match to the end of the line. Pattern string `json:"pattern"` + // PatternGeneratedMessageSuffix is an optional suffix appended to the matched pattern. + // This suffix provides additional context or instructions for resolving the issue. + // It can be used to include environment-specific details, links to documentation, + // or any other information that helps users understand and address the problem. + PatternGeneratedMessageSuffix string `json:"patternGeneratedMessageSuffix,omitempty"` }