Skip to content

Commit 3f4c867

Browse files
authored
Merge pull request #22 from NETWAYS/improved-errs
Improve logging messages for Icinga client
2 parents c8a1c04 + 3bb7fce commit 3f4c867

3 files changed

Lines changed: 40 additions & 6 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Flags:
6969
--plugin-output-annotations=message,... List of Annotation names to be used to set the plugin output for the Icinga service ($ALERTMANAGER_ICINGA_BRIDGE_PLUGINOUTPUT_ANNOTATIONS)
7070
--checks-interval=12h Interval (in seconds) to be used for Icinga check_interval and retry_interval ($ALERTMANAGER_ICINGA_BRIDGE_SERVICE_CHECKS_INTERVAL)
7171
--keep-for=168h How long to keep created alerts around after they have been resolved ($ALERTMANAGER_ICINGA_BRIDGE_KEEP_FOR)
72-
--static-service-vars=KEY=VALUE;... Custom variable to be set for craeted Icinga services (variable=value, can be repeated) ($ALERTMANAGER_ICINGA_BRIDGE_STATIC_SERVICE_VAR)
72+
--static-service-vars=KEY=VALUE;... Custom variable to be set for created Icinga services (variable=value, can be repeated) ($ALERTMANAGER_ICINGA_BRIDGE_STATIC_SERVICE_VAR)
7373
```
7474

7575
Most flags can be set with environment variables, refer to the help to see which flags.

internal/icinga2/icinga.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"net"
1515
"net/http"
1616
"net/url"
17+
"strings"
1718
"time"
1819

1920
"github.com/NETWAYS/alertmanager-icinga-bridge/internal/config"
@@ -71,7 +72,7 @@ func NewClient(config *config.Config, logger *slog.Logger) *Client {
7172

7273
// Do is a small wrapper that tries the given request against all given Icinga API endpoints
7374
func (c *Client) Do(req *http.Request, path string) (*http.Response, error) {
74-
lastErr := ErrNoEndpointReachable
75+
var endpointErrors strings.Builder
7576

7677
for _, base := range c.IcingaURL {
7778
req.URL, _ = req.URL.Parse(base + path)
@@ -87,23 +88,24 @@ func (c *Client) Do(req *http.Request, path string) (*http.Response, error) {
8788
resp, err := c.httpClient.Do(req)
8889

8990
if err != nil {
90-
// Got an error while trying to reach the endpoint, trying the next
91-
lastErr = err
91+
c.logger.Warn(fmt.Sprintf("Icinga API not reachable at %s. Trying next endpoint", req.URL), "component", "icinga", "error", err.Error())
92+
fmt.Fprintf(&endpointErrors, " error: '%s' from '%s'", req.URL, err.Error())
9293

94+
// Trying the next endpoint
9395
continue
9496
}
9597

9698
if resp.StatusCode >= 500 {
9799
resp.Body.Close()
98-
lastErr = fmt.Errorf("error %d from %s", resp.StatusCode, req.URL)
100+
fmt.Fprintf(&endpointErrors, " error: '%d' from '%s'", resp.StatusCode, req.URL)
99101

100102
continue
101103
}
102104

103105
return resp, nil
104106
}
105107

106-
return nil, fmt.Errorf("all endpoints failed, last error: %w", lastErr)
108+
return nil, fmt.Errorf("failed to call one of the configured endpoints. %s", endpointErrors.String())
107109
}
108110

109111
// ProcessCheckResult handles a process-check-result for a given service
@@ -173,6 +175,7 @@ func (c *Client) GetHost(ctx context.Context, name string) (Host, error) {
173175
errDecode := json.Unmarshal(bodyBytes, &result)
174176

175177
if errDecode != nil {
178+
c.logger.Debug("Response body: " + string(bodyBytes))
176179
return Host{}, fmt.Errorf("could not unmarshal JSON: %w", errDecode)
177180
}
178181

@@ -216,6 +219,7 @@ func (c *Client) GetService(ctx context.Context, name string) (Service, error) {
216219
errDecode := json.Unmarshal(bodyBytes, &result)
217220

218221
if errDecode != nil {
222+
c.logger.Debug("Response body: " + string(bodyBytes))
219223
return Service{}, fmt.Errorf("could not unmarshal JSON: %w", errDecode)
220224
}
221225

@@ -265,6 +269,7 @@ func (c *Client) GetServices(ctx context.Context, filter QueryFilter) ([]Service
265269
errDecode := json.Unmarshal(bodyBytes, &result)
266270

267271
if errDecode != nil {
272+
c.logger.Debug("Response body: " + string(bodyBytes))
268273
return []Service{}, fmt.Errorf("could not unmarshal JSON: %w", errDecode)
269274
}
270275

internal/icinga2/icinga_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package icinga2
44

55
import (
6+
"bytes"
67
"context"
78
"encoding/json"
89
"io"
@@ -11,6 +12,7 @@ import (
1112
"net/http/httptest"
1213
"os"
1314
"reflect"
15+
"strings"
1416
"testing"
1517

1618
"github.com/NETWAYS/alertmanager-icinga-bridge/internal/config"
@@ -58,6 +60,33 @@ func TestServiceFullName(t *testing.T) {
5860
}
5961
}
6062

63+
func TestGetHost_WithInvalidReponse(t *testing.T) {
64+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
65+
w.WriteHeader(http.StatusOK)
66+
w.Write([]byte(`<invalid JSON>`))
67+
}))
68+
69+
defer server.Close()
70+
71+
var buf bytes.Buffer
72+
logger := slog.New(slog.NewTextHandler(&buf, &slog.HandlerOptions{Level: slog.LevelDebug}))
73+
74+
client := NewClient(testConfig(server.URL), logger)
75+
76+
_, err := client.GetHost(context.Background(), "unittest")
77+
78+
if err == nil {
79+
t.Fatalf("expected error, got nil")
80+
}
81+
82+
actual := buf.String()
83+
expected := "Response body: <invalid JSON>"
84+
85+
if !strings.Contains(actual, expected) {
86+
t.Fatalf("expected %v, got %v", expected, actual)
87+
}
88+
}
89+
6190
func TestGetHost(t *testing.T) {
6291
datasetHost := "testdata/host.json"
6392

0 commit comments

Comments
 (0)