Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: track config hash on config reload #1212

Merged
merged 3 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,37 @@ type App struct {
// program will exit.
func (a *App) Start() error {
a.Logger.Debug().Logf("Starting up App...")
a.Metrics.Register("config_hash", "gauge")
a.Metrics.Register("rule_config_hash", "gauge")

a.IncomingRouter.SetVersion(a.Version)
a.PeerRouter.SetVersion(a.Version)

a.Config.RegisterReloadCallback(func(configHash, rulesHash string) {
if a.Logger != nil {
a.Logger.Warn().WithFields(map[string]interface{}{
"configHash": configHash,
"rulesHash": rulesHash,
}).Logf("configuration change was detected and the configuration was reloaded.")

cfgMetric, err := config.ConfigHashMetrics(configHash)
if err != nil {
a.Logger.Error().Logf("error calculating config hash metrics: %s", err)
} else {
a.Metrics.Gauge("config_hash", cfgMetric)
}

ruleMetric, err := config.ConfigHashMetrics(rulesHash)
if err != nil {
a.Logger.Error().Logf("error calculating config hash metrics: %s", err)
} else {
a.Metrics.Gauge("rule_config_hash", ruleMetric)
}

}

})

// launch our main routers to listen for incoming event traffic from both peers
// and external sources
a.IncomingRouter.LnS("incoming")
Expand Down
6 changes: 0 additions & 6 deletions cmd/refinery/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,6 @@ func main() {
fmt.Println("Config and Rules validated successfully.")
os.Exit(0)
}
c.RegisterReloadCallback(func() {
if a.Logger != nil {
a.Logger.Info().Logf("configuration change was detected and the configuration was reloaded")
}
})

// get desired implementation for each dependency to inject
lgr := logger.GetLoggerImplementation(c)
collector := collect.GetCollectorImplementation(c)
Expand Down
2 changes: 1 addition & 1 deletion collect/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (i *InMemCollector) Start() error {
}

// sendReloadSignal will trigger the collector reloading its config, eventually.
func (i *InMemCollector) sendReloadSignal() {
func (i *InMemCollector) sendReloadSignal(cfgHash, ruleHash string) {
// non-blocking insert of the signal here so we don't leak goroutines
select {
case i.reload <- struct{}{}:
Expand Down
4 changes: 3 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Config interface {
// consumers of configuration set config values on startup, they should
// check their values haven't changed and re-start anything that needs
// restarting with the new values.
RegisterReloadCallback(callback func())
RegisterReloadCallback(callback ConfigReloadCallback)

// GetListenAddr returns the address and port on which to listen for
// incoming events
Expand Down Expand Up @@ -191,6 +191,8 @@ type Config interface {
GetParentIdFieldNames() []string
}

type ConfigReloadCallback func(configHash, ruleCfgHash string)

type ConfigMetadata struct {
Type string `json:"type"`
ID string `json:"id"`
Expand Down
19 changes: 19 additions & 0 deletions config/configLoadHelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"os"
"path/filepath"
"reflect"
"strconv"

"github.com/creasty/defaults"
"github.com/pelletier/go-toml/v2"
Expand Down Expand Up @@ -240,3 +241,21 @@ func readConfigInto(dest any, location string, opts *CmdEnv) (string, error) {

return hash, nil
}

// ConfigHashMetrics takes a config hash and returns a decimal value for use in metrics.
// The decimal value is the last 4 characters of the config hash, converted to decimal.
// If the config hash is too short, or if there is an error converting the hash to decimal,
// an error is returned.
func ConfigHashMetrics(hash string) (int64, error) {
VinozzZ marked this conversation as resolved.
Show resolved Hide resolved
// get last 4 characters of config hash
if len(hash) < 4 {
return 0, fmt.Errorf("config hash is too short: %s", hash)
}
suffix := hash[len(hash)-4:]
CfgDecimal, err := strconv.ParseInt(suffix, 16, 64)
if err != nil {
return 0, fmt.Errorf("error converting config hash to decimal: %v", err)
}

return CfgDecimal, nil
}
26 changes: 26 additions & 0 deletions config/configLoadHelpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"strings"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func Test_formatFromFilename(t *testing.T) {
Expand Down Expand Up @@ -127,3 +129,27 @@ func Test_loadMemsize(t *testing.T) {
})
}
}

func Test_ConfigHashMetrics(t *testing.T) {
testcases := []struct {
name string
hash string
expected int64
hasError bool
}{
{name: "valid hash", hash: "7f1237f7db723f4e874a7a8269081a77", expected: 6775},
VinozzZ marked this conversation as resolved.
Show resolved Hide resolved
{name: "invalid length", hash: "1a8", hasError: true},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
result, err := ConfigHashMetrics(tc.hash)
if tc.hasError {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tc.expected, result)
}
})
}
}
2 changes: 1 addition & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestReload(t *testing.T) {

ch := make(chan interface{}, 1)

c.RegisterReloadCallback(func() {
c.RegisterReloadCallback(func(cfgHash, ruleHash string) {
close(ch)
})

Expand Down
9 changes: 5 additions & 4 deletions config/file_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type fileConfig struct {
rulesConfig *V2SamplerConfig
rulesHash string
opts *CmdEnv
callbacks []func()
callbacks []ConfigReloadCallback
errorCallback func(error)
done chan struct{}
ticker *time.Ticker
Expand Down Expand Up @@ -412,7 +412,7 @@ func NewConfig(opts *CmdEnv, errorCallback func(error)) (Config, error) {
os.Exit(0)
}

cfg.callbacks = make([]func(), 0)
cfg.callbacks = make([]ConfigReloadCallback, 0)
cfg.errorCallback = errorCallback

if cfg.mainConfig.General.ConfigReloadInterval > 0 {
Expand Down Expand Up @@ -451,8 +451,9 @@ func (f *fileConfig) monitor() {
f.rulesConfig = cfg.rulesConfig
f.rulesHash = cfg.rulesHash
f.mux.Unlock() // can't defer -- routine never ends, and callbacks will deadlock

for _, cb := range f.callbacks {
cb()
cb(cfg.mainHash, cfg.rulesHash)
}
}
}
Expand All @@ -469,7 +470,7 @@ func (f *fileConfig) Stop() {
}
}

func (f *fileConfig) RegisterReloadCallback(cb func()) {
func (f *fileConfig) RegisterReloadCallback(cb ConfigReloadCallback) {
f.mux.Lock()
defer f.mux.Unlock()

Expand Down
6 changes: 3 additions & 3 deletions config/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// MockConfig will respond with whatever config it's set to do during
// initialization
type MockConfig struct {
Callbacks []func()
Callbacks []ConfigReloadCallback
IsAPIKeyValidFunc func(string) bool
GetCollectorTypeErr error
GetCollectorTypeVal string
Expand Down Expand Up @@ -99,11 +99,11 @@ func (m *MockConfig) ReloadConfig() {
defer m.Mux.RUnlock()

for _, callback := range m.Callbacks {
callback()
callback("", "")
}
}

func (m *MockConfig) RegisterReloadCallback(callback func()) {
func (m *MockConfig) RegisterReloadCallback(callback ConfigReloadCallback) {
m.Mux.Lock()
m.Callbacks = append(m.Callbacks, callback)
m.Mux.Unlock()
Expand Down
2 changes: 1 addition & 1 deletion logger/honeycomb.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (h *HoneycombLogger) readResponses() {
}
}

func (h *HoneycombLogger) reloadBuilder() {
func (h *HoneycombLogger) reloadBuilder(cfgHash, ruleHash string) {
h.Debug().Logf("reloading config for Honeycomb logger")
// preserve log level
h.level = h.Config.GetLoggerLevel()
Expand Down
2 changes: 1 addition & 1 deletion metrics/legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (h *LegacyMetrics) Start() error {
return nil
}

func (h *LegacyMetrics) reloadBuilder() {
func (h *LegacyMetrics) reloadBuilder(cfgHash, ruleHash string) {
h.Logger.Debug().Logf("reloading config for honeycomb metrics reporter")
mc := h.Config.GetLegacyMetricsConfig()
h.libhClient.Close()
Expand Down
2 changes: 1 addition & 1 deletion transmit/transmit.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (d *DefaultTransmission) Start() error {
return nil
}

func (d *DefaultTransmission) reloadTransmissionBuilder() {
func (d *DefaultTransmission) reloadTransmissionBuilder(cfgHash, ruleHash string) {
d.Logger.Debug().Logf("reloading transmission config")
upstreamAPI, err := d.Config.GetHoneycombAPI()
if err != nil {
Expand Down
Loading