Skip to content

Commit d71b981

Browse files
authored
Merge pull request #10 from jshufro/jms/traces
Add support for otlp tracing
2 parents 872a753 + 009de11 commit d71b981

9 files changed

Lines changed: 506 additions & 161 deletions

File tree

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,13 @@ clean:
6464
docker rmi remote-signer-dirk-interop-dependencies
6565
rm -f remote-signer-dirk-interop
6666
rm -f coverage.out
67+
68+
.PHONY: release
69+
release: version.txt
70+
docker build . -t ghcr.io/jshufro/remote-signer-dirk-interop:$(shell cat version.txt)
71+
docker push ghcr.io/jshufro/remote-signer-dirk-interop:$(shell cat version.txt)
72+
73+
.PHONY: release-latest
74+
release-latest:
75+
docker tag ghcr.io/jshufro/remote-signer-dirk-interop:$(shell cat version.txt) ghcr.io/jshufro/remote-signer-dirk-interop:latest
76+
docker push ghcr.io/jshufro/remote-signer-dirk-interop:latest

config.example.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ ssl:
2323
# Optional: root CA for verifying Dirk servers (omit to use system pool)
2424
root_ca: "/path/to/ca.crt"
2525

26+
# Optional: otlp trace recipient config
27+
otlp:
28+
trace_recipient: "localhost:4317"
29+
# Whether to use TLS for the trace recipient
30+
# Defaults to true
31+
secure: true
32+
# Optional: hostname override for the trace recipient
33+
# Defaults to the hostname of the machine
34+
hostname_override: "my-machine"
35+
# Optional: service instance ID override for the trace recipient
36+
# Defaults to the hostname
37+
service_instance_id_override: "my-service"
2638
# Optional: network is either mainnet, holesky, hoodi, or sepolia
2739
# Alternatively, set network to a 0x-prefixed hex string representing the genesis fork version
2840
# of your custom network (e.g. 0x10000910 would be hoodi)

config/config.go

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package config
22

33
import (
4+
"crypto/x509"
45
"encoding/hex"
56
"fmt"
7+
"log/slog"
8+
"os"
69
"strings"
710
"time"
811

912
"github.com/spf13/afero"
1013
"github.com/spf13/viper"
14+
15+
tlsprovider "github.com/jshufro/remote-signer-dirk-interop/pkg/tls"
1116
)
1217

1318
// Config holds application configuration.
@@ -30,8 +35,18 @@ type Config struct {
3035
RootCA string `mapstructure:"root_ca"` // optional
3136
RefreshThreshold time.Duration `mapstructure:"refresh_threshold"`
3237
RefreshRetry time.Duration `mapstructure:"refresh_retry"`
38+
39+
CertPool *x509.CertPool `mapstructure:"-"`
40+
TLSProvider tlsprovider.TLSProvider `mapstructure:"-"`
3341
}
3442

43+
OTLP struct {
44+
TraceRecipient string `mapstructure:"trace_recipient"`
45+
Secure bool `mapstructure:"secure"`
46+
HostnameOverride string `mapstructure:"hostname_override"`
47+
ServiceInstanceIDOverride string `mapstructure:"service_instance_id_override"`
48+
} `mapstructure:"otlp"`
49+
3550
Metrics struct {
3651
ListenAddress string `mapstructure:"listen_address"`
3752
ListenPort uint16 `mapstructure:"listen_port"`
@@ -40,12 +55,57 @@ type Config struct {
4055
// Network is either mainnet or hoodi
4156
Network string `mapstructure:"network"`
4257
genesisForkVersion []byte
58+
59+
Log *slog.Logger
60+
ParsedLogLevel slog.Level
4361
}
4462

45-
func (c *Config) Populate(v *viper.Viper) error {
46-
if err := v.Unmarshal(c); err != nil {
63+
func (c *Config) populate(v *viper.Viper) error {
64+
if c == nil {
65+
return fmt.Errorf("unmarshaling config: nil config")
66+
}
67+
err := v.Unmarshal(c)
68+
if err != nil {
4769
return fmt.Errorf("unmarshaling config: %w", err)
4870
}
71+
72+
c.SSL.CertPool, err = x509.SystemCertPool()
73+
if err != nil {
74+
return fmt.Errorf("failed to get system cert pool: %w", err)
75+
}
76+
77+
if c.SSL.RootCA != "" {
78+
rootCABytes, err := os.ReadFile(c.SSL.RootCA)
79+
if err != nil {
80+
return fmt.Errorf("failed to read root CA: %w", err)
81+
}
82+
c.SSL.CertPool.AppendCertsFromPEM(rootCABytes)
83+
}
84+
85+
c.ParsedLogLevel = parseLogLevel(c.LogLevel)
86+
if c.LogFormat == "json" {
87+
c.Log = slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
88+
Level: c.ParsedLogLevel,
89+
}))
90+
} else {
91+
c.Log = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
92+
Level: c.ParsedLogLevel,
93+
}))
94+
}
95+
96+
return nil
97+
}
98+
99+
func (c *Config) initClientTLS() error {
100+
tlsProvider := tlsprovider.NewTLSProvider(c.SSL.Cert, c.SSL.PrivKey)
101+
tlsProvider.SetThreshold(c.SSL.RefreshThreshold)
102+
tlsProvider.SetRetry(c.SSL.RefreshRetry)
103+
tlsProvider.SetLogger(c.Log)
104+
105+
if err := tlsProvider.LoadCertificate(); err != nil {
106+
return fmt.Errorf("failed to load certificate: %w", err)
107+
}
108+
c.SSL.TLSProvider = tlsProvider
49109
return nil
50110
}
51111

@@ -62,6 +122,7 @@ func newViper(fs afero.Fs) *viper.Viper {
62122
v.SetDefault("listen_address", "0.0.0.0")
63123
v.SetDefault("listen_port", 9090)
64124
v.SetDefault("network", "mainnet")
125+
v.SetDefault("otlp.secure", true)
65126
return v
66127

67128
}
@@ -78,20 +139,24 @@ func Load(cfgFile string, fs afero.Fs) (*Config, error) {
78139
}
79140

80141
cfg := &Config{}
81-
if err := cfg.Populate(v); err != nil {
142+
if err := cfg.populate(v); err != nil {
82143
return nil, fmt.Errorf("populating config: %w", err)
83144
}
84145

85-
if err := cfg.Validate(); err != nil {
146+
if err := cfg.validate(); err != nil {
86147
return nil, fmt.Errorf("validating config: %w", err)
87148
}
88149

150+
if err := cfg.initClientTLS(); err != nil {
151+
return nil, fmt.Errorf("loading tls credentials: %w", err)
152+
}
153+
89154
return cfg, nil
90155
}
91156

92157
// Validate performs basic validation of the configuration and returns an error
93158
// if any required fields are missing or invalid.
94-
func (c *Config) Validate() error {
159+
func (c *Config) validate() error {
95160
if len(c.Dirk.Endpoints) == 0 {
96161
return fmt.Errorf("at least one dirk endpoint is required")
97162
}
@@ -142,3 +207,18 @@ func (c *Config) setGenesisForkVersion() error {
142207
func (c *Config) GenesisForkVersion() []byte {
143208
return c.genesisForkVersion
144209
}
210+
211+
func parseLogLevel(level string) slog.Level {
212+
switch level {
213+
case "debug":
214+
return slog.LevelDebug
215+
case "info":
216+
return slog.LevelInfo
217+
case "warn":
218+
return slog.LevelWarn
219+
case "error":
220+
return slog.LevelError
221+
}
222+
fmt.Fprintf(os.Stderr, "invalid log level %s, defaulting to info\n", level)
223+
return slog.LevelInfo
224+
}

0 commit comments

Comments
 (0)