-
Notifications
You must be signed in to change notification settings - Fork 66
/
healthchecks.go
121 lines (105 loc) · 3.42 KB
/
healthchecks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2022 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
//
// 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 healthchecks
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/GoogleCloudPlatform/ops-agent/internal/logs"
)
var healthChecksLogFile = "health-checks.log"
type HealthCheck interface {
Name() string
RunCheck(logger logs.StructuredLogger) error
}
type HealthCheckResult struct {
Name string
Err error
}
func singleErrorResultMessage(e error, Name string) string {
if e != nil {
if healthError, ok := e.(HealthCheckError); ok {
if healthError.IsFatal {
return fmt.Sprintf("[%s] Result: FAIL, Error code: %s, Failure: %s, Solution: %s, Resource: %s",
Name, healthError.Code, healthError.Message, healthError.Action, healthError.ResourceLink)
} else {
return fmt.Sprintf("[%s] Result: WARNING, Error code: %s, Failure: %s, Solution: %s, Resource: %s",
Name, healthError.Code, healthError.Message, healthError.Action, healthError.ResourceLink)
}
}
return fmt.Sprintf("[%s] Result: ERROR, Detail: %s", Name, e.Error())
}
return fmt.Sprintf("[%s] Result: PASS", Name)
}
func (r HealthCheckResult) LogResult(logger logs.StructuredLogger) {
for _, e := range r.ErrorSlice() {
if e == nil {
logger.Infof(singleErrorResultMessage(e, r.Name))
} else {
if healthError, ok := e.(HealthCheckError); ok {
if healthError.IsFatal {
logger.Errorw(singleErrorResultMessage(e, r.Name), "code", healthError.Code)
} else {
logger.Warnw(singleErrorResultMessage(e, r.Name), "code", healthError.Code)
}
} else {
logger.Errorf(singleErrorResultMessage(e, r.Name))
}
}
}
}
func (r HealthCheckResult) ErrorSlice() []error {
if mwErr, ok := r.Err.(MultiWrappedError); ok {
return mwErr.Unwrap()
}
return []error{r.Err}
}
func LogHealthCheckResults(healthCheckResults []HealthCheckResult, logger logs.StructuredLogger) {
for _, result := range healthCheckResults {
result.LogResult(logger)
}
}
func CreateHealthChecksLogger(logDir string) logs.StructuredLogger {
path := filepath.Join(logDir, healthChecksLogFile)
// Make sure the directory exists before writing the file.
if err := os.MkdirAll(logDir, 0755); err != nil {
log.Printf("failed to create directory for %q: %v", path, err)
return logs.Default()
}
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Printf("failed to open health checks log file %q: %v", path, err)
return logs.Default()
}
file.Close()
return logs.New(path)
}
type HealthCheckRegistry []HealthCheck
func HealthCheckRegistryFactory() HealthCheckRegistry {
return HealthCheckRegistry{
PortsCheck{},
NetworkCheck{},
APICheck{},
}
}
func (r HealthCheckRegistry) RunAllHealthChecks(logger logs.StructuredLogger) []HealthCheckResult {
var result []HealthCheckResult
for _, c := range r {
r := HealthCheckResult{Name: c.Name(), Err: c.RunCheck(logger)}
r.LogResult(logger)
result = append(result, r)
}
return result
}