Skip to content

Commit

Permalink
Merge branch 'logging-enhancements'
Browse files Browse the repository at this point in the history
  • Loading branch information
BuJo committed Jul 10, 2024
2 parents c8b9e40 + 07f82d2 commit 9c8d899
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 82 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# Releases

## 1.9.x
## 1.9.x - 2024-07-XX Tracing IDs

* Using `tuwat -otelUrl stdout` or `TUWAT_OTEL_URL=stdout` now enables
tracing output on stdout.
* Add spans/traces to logs to enable correlation
* Cleanup file paths in logging for visibility by stripping the
build path.
* Remove error logging keys containing `<nil>` strings.

## 1.8.0 - 2024-06-05 Icinga2 Host ACKs

Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ require (
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240709173604-40e1e62336c5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
google.golang.org/genproto/googleapis/api v0.0.0-20240709173604-40e1e62336c5 h1:a/Z0jgw03aJ2rQnp5PlPpznJqJft0HyvyrcUcxgzPwY=
google.golang.org/genproto/googleapis/api v0.0.0-20240709173604-40e1e62336c5/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5 h1:SbSDUWW1PAO24TNpLdeheoYPd7kllICcLU52x6eD4kQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
29 changes: 14 additions & 15 deletions pkg/web/alerts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package web

import (
"errors"
"log/slog"
"net/http"
"path/filepath"
Expand Down Expand Up @@ -33,7 +34,11 @@ func (h *webHandler) wsalerts(s *websocket.Conn) {
if err := recover(); err != nil {
switch err := err.(type) {
case error:
slog.InfoContext(s.Request().Context(), "panic serving", slog.Any("error", err))
if errors.Is(err, DisconnectError) {
slog.DebugContext(s.Request().Context(), "panic serving", slog.Any("error", err))
} else {
slog.InfoContext(s.Request().Context(), "panic serving", slog.Any("error", err))
}
default:
slog.InfoContext(s.Request().Context(), "panic serving", slog.Any("error", err))
}
Expand All @@ -50,7 +55,6 @@ func (h *webHandler) wsalerts(s *websocket.Conn) {

tr := trace.SpanFromContext(s.Request().Context()).SpanContext().TraceID().String()
slog.InfoContext(s.Request().Context(), "Registering websocket connection",
slog.String("client", tr),
slog.String("dashboard", dashboardName))
update := h.aggregator.Register(tr)
defer h.aggregator.Unregister(tr)
Expand All @@ -59,18 +63,15 @@ func (h *webHandler) wsalerts(s *websocket.Conn) {
select {
case _, ok := <-update:
if !ok {
slog.DebugContext(s.Request().Context(), "stop sending to websocket client, update channel closed",
slog.String("client", tr))
slog.DebugContext(s.Request().Context(), "stop sending to websocket client, update channel closed")
update = nil
}

slog.DebugContext(s.Request().Context(), "sending to websocket client",
slog.String("client", tr))
slog.DebugContext(s.Request().Context(), "sending to websocket client")
aggregate := h.aggregator.Alerts(dashboardName)
renderer(webContent{Content: aggregate})
case <-s.Request().Context().Done():
slog.DebugContext(s.Request().Context(), "stop sending to websocket client, req ctx done",
slog.String("client", tr))
slog.DebugContext(s.Request().Context(), "stop sending to websocket client, req ctx done")
return
}
}
Expand All @@ -94,28 +95,26 @@ func (h *webHandler) ssealerts(w http.ResponseWriter, req *http.Request) {
defer cancel()

tr := trace.SpanFromContext(req.Context()).SpanContext().TraceID().String()
slog.InfoContext(req.Context(), "Registering sse connection", slog.String("client", tr))
slog.InfoContext(req.Context(), "Registering sse connection")
update := h.aggregator.Register(tr)
defer h.aggregator.Unregister(tr)

for {
select {
case _, ok := <-update:
if !ok {
slog.DebugContext(req.Context(), "stop sending to sse client", slog.String("client", tr))
slog.DebugContext(req.Context(), "stop sending to sse client")
return
}

slog.DebugContext(req.Context(), "sending to sse client", slog.String("client", tr))
slog.DebugContext(req.Context(), "sending to sse client")
aggregate := h.aggregator.Alerts(dashboardName)
if err := renderer(webContent{Content: aggregate}); err != nil {
slog.DebugContext(req.Context(), "stop sending to sse client",
slog.String("client", tr),
slog.Any("error", err))
slog.DebugContext(req.Context(), "stop sending to sse client", slog.Any("error", err))
return
}
case <-req.Context().Done():
slog.InfoContext(req.Context(), "stop sending to sse client", slog.String("client", tr))
slog.InfoContext(req.Context(), "stop sending to sse client")
return
}
}
Expand Down
111 changes: 54 additions & 57 deletions pkg/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"embed"
"encoding/json"
"errors"
"fmt"
html "html/template"
"io/fs"
Expand Down Expand Up @@ -47,6 +48,11 @@ type webContent struct {
Style string
}

var (
TemplateError = errors.New("template execution failed")
DisconnectError = errors.New("client disconnected")
)

func WebHandler(cfg *config.Config, aggregator *aggregation.Aggregator) http.Handler {
handler := &webHandler{
aggregator: aggregator,
Expand Down Expand Up @@ -82,7 +88,11 @@ func (h *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := recover(); err != nil {
switch err := err.(type) {
case error:
slog.ErrorContext(r.Context(), "panic serving", slog.Any("error", err))
if errors.Is(err, DisconnectError) {
slog.DebugContext(r.Context(), "panic serving", slog.Any("error", err))
} else {
slog.InfoContext(r.Context(), "panic serving", slog.Any("error", err))
}
default:
slog.ErrorContext(r.Context(), "panic serving", slog.Any("error", err))
}
Expand All @@ -99,11 +109,8 @@ func (h *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
type renderFunc func(w http.ResponseWriter, statusCode int, data webContent)

func (h *webHandler) baseRenderer(req *http.Request, dashboardName string, patterns ...string) renderFunc {
var templateFiles []string
var templateDefinition string

templateFiles = append([]string{"_base.gohtml"}, patterns...)
templateDefinition = "base"
templateFiles := append([]string{"_base.gohtml"}, patterns...)
templateDefinition := "base"

funcs := html.FuncMap{
"niceDuration": niceDuration,
Expand All @@ -126,20 +133,15 @@ func (h *webHandler) baseRenderer(req *http.Request, dashboardName string, patte
data.Dashboards = h.dashboards
data.Dashboard = dashboardName

err := tmpl.ExecuteTemplate(w, templateDefinition, data)
if err != nil {
slog.ErrorContext(req.Context(), "template execution failed", slog.Any("error", err))
panic(err)
if err := tmpl.ExecuteTemplate(w, templateDefinition, data); err != nil {
panic(errors.Join(TemplateError, err))
}
}
}

func (h *webHandler) partialRenderer(req *http.Request, dashboardName string, patterns ...string) renderFunc {
var templateFiles []string
var templateDefinition string

templateFiles = append([]string{"_stream.gohtml"}, patterns...)
templateDefinition = "base"
templateFiles := append([]string{"_stream.gohtml"}, patterns...)
templateDefinition := "base"

funcs := html.FuncMap{
"niceDuration": niceDuration,
Expand All @@ -161,22 +163,17 @@ func (h *webHandler) partialRenderer(req *http.Request, dashboardName string, pa
data.Style = h.style
data.Dashboard = dashboardName

err := tmpl.ExecuteTemplate(w, templateDefinition, data)
if err != nil {
slog.ErrorContext(req.Context(), "template execution failed", slog.Any("error", err))
panic(err)
if err := tmpl.ExecuteTemplate(w, templateDefinition, data); err != nil {
panic(errors.Join(TemplateError, err))
}
}
}

type sseRenderFunc func(data webContent) error

func (h *webHandler) sseRenderer(w http.ResponseWriter, req *http.Request, patterns ...string) (sseRenderFunc, context.CancelFunc) {
var templateFiles []string
var templateDefinition string

templateFiles = append([]string{"_stream.gohtml"}, patterns...)
templateDefinition = "content-container"
templateFiles := append([]string{"_stream.gohtml"}, patterns...)
templateDefinition := "content-container"

funcs := html.FuncMap{
"niceDuration": niceDuration,
Expand All @@ -186,7 +183,9 @@ func (h *webHandler) sseRenderer(w http.ResponseWriter, req *http.Request, patte
tmpl, err := tmpl.ParseFS(h.fs, templateFiles...)
if err != nil {
slog.ErrorContext(req.Context(), "compiling template failed", slog.Any("error", err))
panic(err)
return func(data webContent) error {
return err
}, func() {}
}

// prepare the flusher
Expand All @@ -204,8 +203,7 @@ func (h *webHandler) sseRenderer(w http.ResponseWriter, req *http.Request, patte
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

_, err = fmt.Fprint(w, "retry: 60000\n\n")
if err != nil {
if _, err := fmt.Fprint(w, "retry: 60000\n\n"); err != nil {
return func(data webContent) error {
return err
}, cancel
Expand All @@ -220,41 +218,45 @@ func (h *webHandler) sseRenderer(w http.ResponseWriter, req *http.Request, patte

buf := new(bytes.Buffer)

err = tmpl.ExecuteTemplate(buf, templateDefinition, data)
if err != nil {
slog.InfoContext(req.Context(), "template execution failed", slog.Any("error", err))
panic(err)
if err := tmpl.ExecuteTemplate(buf, templateDefinition, data); err != nil {
panic(errors.Join(TemplateError, err))
}

tr := trace.SpanFromContext(req.Context())
_, err = fmt.Fprintf(w, "id: %s\n", tr.SpanContext().TraceID())
_, err = fmt.Fprint(w, "event: message\n")
if _, err := fmt.Fprintf(w, "id: %s\n", tr.SpanContext().TraceID()); err != nil {
panic(errors.Join(DisconnectError, err))
}
if _, err := fmt.Fprint(w, "event: message\n"); err != nil {
panic(errors.Join(DisconnectError, err))
}

scanner := bufio.NewScanner(buf)
for scanner.Scan() {
_, err = w.Write([]byte("data: "))
_, err = w.Write(scanner.Bytes())
_, err = w.Write([]byte("\n"))
if _, err := w.Write([]byte("data: ")); err != nil {
panic(errors.Join(DisconnectError, err))
}
if _, err := w.Write(scanner.Bytes()); err != nil {
panic(errors.Join(DisconnectError, err))
}
if _, err := w.Write([]byte("\n")); err != nil {
panic(errors.Join(DisconnectError, err))
}
}

if _, err := w.Write([]byte("\n")); err != nil {
panic(errors.Join(DisconnectError, err))
}
_, err = w.Write([]byte("\n"))
flusher.Flush()

if err != nil {
slog.InfoContext(req.Context(), "template execution failed", slog.Any("error", err))
}
return err
return nil
}, cancel
}

type wsRenderFunc func(data webContent)

func (h *webHandler) wsRenderer(s *websocket.Conn, patterns ...string) wsRenderFunc {
var templateFiles []string
var templateDefinition string

templateFiles = append([]string{"_stream.gohtml"}, patterns...)
templateDefinition = "content-container"
templateFiles := append([]string{"_stream.gohtml"}, patterns...)
templateDefinition := "content-container"

funcs := html.FuncMap{
"niceDuration": niceDuration,
Expand All @@ -263,14 +265,13 @@ func (h *webHandler) wsRenderer(s *websocket.Conn, patterns ...string) wsRenderF
tmpl := html.New(templateDefinition).Funcs(funcs)
tmpl, err := tmpl.ParseFS(h.fs, templateFiles...)
if err != nil {
slog.ErrorContext(s.Request().Context(), "compiling template failed", slog.Any("error", err))
panic(err)
panic(errors.Join(TemplateError, err))
}

return func(data webContent) {
w, err := s.NewFrameWriter(websocket.TextFrame)
if err != nil {
panic(err)
panic(fmt.Errorf("cannot create websocket text frame writer: %w", err))
}

data.Version = version.Info.Version
Expand All @@ -279,16 +280,12 @@ func (h *webHandler) wsRenderer(s *websocket.Conn, patterns ...string) wsRenderF

buf := new(bytes.Buffer)

err = tmpl.ExecuteTemplate(buf, templateDefinition, data)
if err != nil {
slog.InfoContext(s.Request().Context(), "template execution failed", slog.Any("error", err))
panic(err)
if err := tmpl.ExecuteTemplate(buf, templateDefinition, data); err != nil {
panic(errors.Join(TemplateError, err))
}

_, err = w.Write(buf.Bytes())
if err != nil {
slog.InfoContext(s.Request().Context(), "sending failed", slog.Any("error", err))
panic(err)
if _, err = w.Write(buf.Bytes()); err != nil {
panic(errors.Join(DisconnectError, err))
}
}
}
Expand Down

0 comments on commit 9c8d899

Please sign in to comment.