Skip to content

Commit f2fc876

Browse files
committed
Refactor and clean up config parsing.
- Use koanf and cleaner type funcs (String() instead of StringVar()) in flags. - Add support for loading one or more TOML config files that enable certain config to be overridden in certain contexts. - Add new `--topic=source:target` flag for easy deployment of the app in environments where all config is shared except for topics, a common usecase.
1 parent 511e9f3 commit f2fc876

File tree

3 files changed

+43
-22
lines changed

3 files changed

+43
-22
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.21
55
require (
66
github.com/knadh/koanf/parsers/toml v0.1.0
77
github.com/knadh/koanf/providers/file v0.1.0
8+
github.com/knadh/koanf/providers/posflag v0.1.0
89
github.com/knadh/koanf/v2 v2.0.1
910
github.com/spf13/pflag v1.0.5
1011
github.com/twmb/franz-go v1.15.4

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ github.com/knadh/koanf/parsers/toml v0.1.0 h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6OD
1212
github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18=
1313
github.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf3ODrc//Lp+c=
1414
github.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=
15+
github.com/knadh/koanf/providers/posflag v0.1.0 h1:mKJlLrKPcAP7Ootf4pBZWJ6J+4wHYujwipe7Ie3qW6U=
16+
github.com/knadh/koanf/providers/posflag v0.1.0/go.mod h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0=
1517
github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g=
1618
github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus=
1719
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=

main.go

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import (
99
"net/http"
1010
"os"
1111
"os/signal"
12+
"strings"
1213
"syscall"
1314
"time"
1415

1516
"github.com/VictoriaMetrics/metrics"
1617
"github.com/knadh/koanf/parsers/toml"
1718
"github.com/knadh/koanf/providers/file"
19+
"github.com/knadh/koanf/providers/posflag"
1820
"github.com/knadh/koanf/v2"
1921
flag "github.com/spf13/pflag"
2022
)
@@ -31,52 +33,68 @@ func main() {
3133
os.Exit(0)
3234
}
3335

34-
var (
35-
configPath string
36-
mode string
37-
stopAtEnd bool
38-
filterPaths []string
39-
)
40-
f.StringVar(&configPath, "config", "config.toml", "Path to the TOML configuration file")
41-
f.StringVar(&mode, "mode", "single", "single/failover")
42-
f.BoolVar(&stopAtEnd, "stop-at-end", false, "Stop relay at the end of offsets")
43-
f.StringSliceVar(&filterPaths, "filter", []string{}, "Path to filter providers. Can specify multiple values.")
44-
f.Bool("version", false, "Current version of the build")
36+
f.StringSlice("config", []string{"config.toml"}, "path to one or more config files (will be merged in order)")
37+
f.String("mode", "single", "single | failover")
38+
f.Bool("stop-at-end", false, "stop relay at the end of offsets")
39+
f.StringSlice("filter", []string{}, "path to one or more filter providers")
40+
f.StringSlice("topic", []string{}, "one or more source:target topic names. Setting this overrides [topics] in the config file.")
41+
f.Bool("version", false, "show current version of the build")
4542

4643
if err := f.Parse(os.Args[1:]); err != nil {
4744
log.Fatalf("error loading flags: %v", err)
4845
}
4946

47+
ko := koanf.New(".")
48+
if err := ko.Load(posflag.Provider(f, ".", ko), nil); err != nil {
49+
log.Fatalf("error reading flag config: %v", err)
50+
}
51+
5052
// Version flag.
51-
if ok, _ := f.GetBool("version"); ok {
53+
if ko.Bool("version") {
5254
fmt.Println(buildString)
5355
os.Exit(0)
5456
}
5557

56-
if stopAtEnd && mode == ModeFailover {
58+
if ko.Bool("stop-at-end") && ko.String("mode") == ModeFailover {
5759
log.Fatalf("`--stop-at-end` cannot be used with `failover` mode")
5860
}
5961

60-
// Load the config file.
61-
ko := koanf.New(".")
62-
log.Printf("reading config: %s", configPath)
63-
if err := ko.Load(file.Provider(configPath), toml.Parser()); err != nil {
64-
log.Fatalf("error reading config: %v", err)
62+
// Load one or more config files. Keys in each subsequent file is merged
63+
// into the previous file's keys.
64+
for _, f := range ko.Strings("config") {
65+
log.Printf("reading config from %s", f)
66+
if err := ko.Load(file.Provider(f), toml.Parser()); err != nil {
67+
log.Fatalf("error reading config: %v", err)
68+
}
6569
}
6670

6771
var cfg Config
6872
if err := ko.Unmarshal("", &cfg); err != nil {
6973
log.Fatalf("error marshalling application config: %v", err)
7074
}
7175

72-
// setup logger
76+
// If there are topics in the commandline flags, override the ones read from the file.
77+
if topics := ko.Strings("topic"); len(topics) > 0 {
78+
mp := map[string]string{}
79+
for _, t := range topics {
80+
split := strings.Split(t, ":")
81+
if len(split) != 2 {
82+
log.Fatalf("invalid topic '%s'. Should be in the format 'source:target'", t)
83+
}
84+
85+
mp[split[0]] = split[1]
86+
}
87+
cfg.Topics = mp
88+
}
89+
90+
// Initialized the structured logger.
7391
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
7492
AddSource: false,
7593
Level: cfg.App.LogLevel,
7694
}))
7795

78-
// setup filter providers
79-
filters, err := initFilterProviders(filterPaths, ko, logger)
96+
// Load the optional filter providers.
97+
filters, err := initFilterProviders(ko.Strings("filter"), ko, logger)
8098
if err != nil {
8199
log.Fatalf("error initializing filter provider: %v", err)
82100
}
@@ -153,7 +171,7 @@ func main() {
153171
lagThreshold: cfg.App.LagThreshold,
154172
maxReqTime: cfg.App.MaxRequestDuration,
155173

156-
stopAtEnd: stopAtEnd,
174+
stopAtEnd: ko.Bool("stop-at-end"),
157175
srcOffsets: make(map[string]map[int32]int64),
158176
destOffsets: destOffsets.KOffsets(),
159177

0 commit comments

Comments
 (0)