Skip to content

Commit

Permalink
Add hcat event logger.
Browse files Browse the repository at this point in the history
  • Loading branch information
hashi-derek authored and noejbrown committed Jul 8, 2022
1 parent 1da0245 commit 42e8af3
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
42 changes: 42 additions & 0 deletions controller/watcher.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package controller

import (
"encoding/json"
"fmt"
"math/rand"
"reflect"
"time"

"github.com/hashicorp/consul-terraform-sync/config"
"github.com/hashicorp/consul-terraform-sync/logging"
"github.com/hashicorp/consul-terraform-sync/retry"
"github.com/hashicorp/hcat"
"github.com/hashicorp/hcat/events"
)

const (
Expand Down Expand Up @@ -63,6 +67,7 @@ func newWatcher(conf *config.Config, maxRetries int) (*hcat.Watcher, error) {
Clients: clients,
Cache: hcat.NewStore(),
ConsulRetryFunc: wr.retryConsul,
EventHandler: newWatcherEventHandler(logging.Global().Named(hcatLogSystemName)),
}), nil
}

Expand Down Expand Up @@ -124,3 +129,40 @@ func setVaultClient(clients *hcat.ClientSet, conf *config.Config) error {

return clients.AddVault(vault)
}

func newWatcherEventHandler(logger logging.Logger) events.EventHandler {
return func(e events.Event) {
// Log events at different log levels based on the type
var level logging.Level
switch e.(type) {
case events.Trace:
// Only show hcat Trace events when trace logging is enabled.
level = logging.Trace
default:
// Everything else is shown when debug is enabled.
level = logging.Debug
}

// Default to emitting the go format for the event.
event := fmt.Sprintf("%+v", e)

// If the output log level is Trace, then emit the json format for the event.
// This could be very large in certain circumstances, because it displays
// nested data structures.
if logger.IsTrace() {
b, err := json.Marshal(e)
if err != nil {
logger.Warn("Unexpected error marshalling event to json", "error", err, "event", e)
return
}
event = string(b)
}

// Emit the log and include the type name, if possible.
tName := "nil"
if t := reflect.TypeOf(e); t != nil {
tName = t.Name()
}
logger.Log(level, "event received", "type", tName, "event", event)
}
}
45 changes: 45 additions & 0 deletions controller/watcher_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package controller

import (
"bytes"
"encoding/json"
"fmt"
"math/rand"
"testing"
"time"

"github.com/hashicorp/consul-terraform-sync/logging"
"github.com/hashicorp/hcat/events"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestWatchRetry_retryConsul(t *testing.T) {
Expand Down Expand Up @@ -55,3 +61,42 @@ func TestWatchRetry_retryConsul(t *testing.T) {
})
}
}

func Test_newWatcherEventHandler(t *testing.T) {
toJson := func(v any) string {
b, err := json.Marshal(v)
require.NoError(t, err)
return string(b)
}
toGo := func(v any) string {
return fmt.Sprintf("%+v", v)
}

testCases := []struct {
logLevel string
shouldLog bool
findString func(v any) string
event events.Event
}{
{"TRACE", true, toJson, events.Trace{ID: "logged"}},
{"DEBUG", false, toGo, events.Trace{ID: "not logged"}},
{"TRACE", true, toJson, events.NoNewData{ID: "logged"}},
{"DEBUG", true, toGo, events.NewData{ID: "logged"}},
{"INFO", false, toGo, events.RetryAttempt{ID: "not logged"}},
{"DEBUG", true, func(v any) string { return "type=nil" }, nil},
}

for _, tc := range testCases {
var buf bytes.Buffer
logger := logging.NewTestLogger(tc.logLevel, &buf)
handler := newWatcherEventHandler(logger)
handler(tc.event)
toFind := tc.findString(tc.event)
if tc.shouldLog {
assert.Contains(t, buf.String(), toFind)
} else {
assert.NotContains(t, buf.String(), toFind)
assert.Equal(t, "", buf.String())
}
}
}
11 changes: 11 additions & 0 deletions logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,19 @@ var Levels = []string{"TRACE", "DEBUG", "INFO", "WARN", "ERR"}
// it is set by the Setup() function and is shared with all other setup variations (i.e. SetupLocal())
var LogLevel = ""

// Alias the hclog levels so that the hclog package doesn't need to be exposed for `logger.Log(...)` calls.
type Level = hclog.Level

const (
defaultLogLevel = "INFO"

NoLevel Level = hclog.NoLevel
Trace Level = hclog.Trace
Debug Level = hclog.Debug
Info Level = hclog.Info
Warn Level = hclog.Warn
Error Level = hclog.Error
Off Level = hclog.Off
)

// Logger is a type alias for hclog.Logger
Expand Down

0 comments on commit 42e8af3

Please sign in to comment.