Skip to content

Commit 6dae152

Browse files
authored
feat(otel): add support for open telemetry traces and instrumentation (#46)
1 parent d6b883d commit 6dae152

16 files changed

Lines changed: 520 additions & 67 deletions

File tree

cmd/main.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ import (
2323
"golang.org/x/net/http2/h2c"
2424
"golang.org/x/sync/errgroup"
2525

26+
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
27+
2628
"github.com/akash-network/rpc-proxy/internal/block"
2729
"github.com/akash-network/rpc-proxy/internal/config"
2830
"github.com/akash-network/rpc-proxy/internal/halt"
2931
"github.com/akash-network/rpc-proxy/internal/metrics"
32+
proxyotel "github.com/akash-network/rpc-proxy/internal/otel"
3033
"github.com/akash-network/rpc-proxy/internal/proxy"
3134
"github.com/akash-network/rpc-proxy/internal/seed"
3235
"github.com/spf13/cobra"
@@ -121,6 +124,14 @@ func NewRootCmd(v *viper.Viper) *cobra.Command {
121124
rootCmd.PersistentFlags().String("metrics.path", "/metrics", "Path to expose metrics on")
122125
rootCmd.PersistentFlags().String("metrics.service-name", "", "Service name for metrics labeling (defaults to HOSTNAME env var)")
123126

127+
// OpenTelemetry configuration
128+
rootCmd.PersistentFlags().Bool("otel.enabled", false, "Enable OpenTelemetry tracing")
129+
rootCmd.PersistentFlags().String("otel.exporter-type", "grpc", "OTLP exporter type (grpc or http)")
130+
rootCmd.PersistentFlags().String("otel.endpoint", "", "OTLP collector endpoint")
131+
rootCmd.PersistentFlags().Bool("otel.insecure", false, "Use insecure connection to OTLP collector")
132+
rootCmd.PersistentFlags().String("otel.service-name", "", "Service name for tracing (defaults to metrics service name or HOSTNAME)")
133+
rootCmd.PersistentFlags().Float64("otel.sample-rate", 0.1, "Trace sampling rate (0.0 to 1.0, e.g. 0.1 = 10%)")
134+
124135
// Configuration file support
125136
rootCmd.PersistentFlags().StringP("config", "c", "", "config file (default is $HOME/.akash-proxy/config.yaml)")
126137

@@ -130,6 +141,13 @@ func NewRootCmd(v *viper.Viper) *cobra.Command {
130141
func runProxy(cfg config.Config) error {
131142
log := slog.New(slog.NewJSONHandler(os.Stdout, nil))
132143

144+
// Initialize OpenTelemetry tracing
145+
otelShutdown, err := proxyotel.Init(context.Background(), cfg.OTEL, cfg.Metrics.ServiceName)
146+
if err != nil {
147+
return fmt.Errorf("initializing OpenTelemetry: %w", err)
148+
}
149+
defer otelShutdown(context.Background())
150+
133151
var metricsServer *http.Server
134152
if cfg.Metrics.Enabled {
135153
// Determine service name from flag or HOSTNAME environment variable
@@ -174,7 +192,6 @@ func runProxy(cfg config.Config) error {
174192
blockTime := 6 * time.Second
175193

176194
var haltDetector *halt.Detector
177-
var err error
178195
if cfg.Halt.Enabled {
179196
haltDetector, err = newHaltDetector(cfg.Halt, log)
180197
if err != nil {
@@ -362,7 +379,7 @@ func prepareRestAndRPCServer(log *slog.Logger, cfg config.Config, rpcProxyHandle
362379

363380
srv := &http.Server{
364381
Addr: cfg.Server.Listen,
365-
Handler: cors.WithCorsMiddleware(corsHeaders, m),
382+
Handler: otelhttp.NewHandler(cors.WithCorsMiddleware(corsHeaders, m), "akash-proxy"),
366383
TLSConfig: am.TLSConfig(),
367384
ReadTimeout: cfg.Server.Timeouts.Read,
368385
IdleTimeout: cfg.Server.Timeouts.Idle,
@@ -384,7 +401,7 @@ func prepareGRPCServer(log *slog.Logger, cfg config.Config, p *proxy.GRPCProxy)
384401
}
385402

386403
mux := http.NewServeMux()
387-
mux.Handle("/", cors.WithCorsMiddleware(corsHeaders, p))
404+
mux.Handle("/", otelhttp.NewHandler(cors.WithCorsMiddleware(corsHeaders, p), "akash-proxy-grpc"))
388405

389406
// Start HTTP/2.0 server.
390407
grpcServer := &http.Server{

deploy/docker-compose.yml

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
1-
version: '3.8'
2-
31
services:
42
prometheus:
53
image: prom/prometheus:latest
6-
container_name: prometheus
74
ports:
85
- "9090:9090"
96
volumes:
107
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
118
command:
129
- '--config.file=/etc/prometheus/prometheus.yml'
10+
- '--web.enable-remote-write-receiver'
11+
networks:
12+
- monitoring
13+
restart: unless-stopped
14+
15+
tempo:
16+
image: grafana/tempo:latest
17+
ports:
18+
- "3200:3200" # Tempo HTTP API
19+
- "4317:4317" # OTLP gRPC
20+
- "4318:4318" # OTLP HTTP
21+
volumes:
22+
- ./tempo/tempo.yml:/etc/tempo/tempo.yml
23+
command:
24+
- '-config.file=/etc/tempo/tempo.yml'
25+
depends_on:
26+
- prometheus
27+
networks:
28+
- monitoring
1329
restart: unless-stopped
1430

1531
grafana:
1632
image: grafana/grafana:latest
17-
container_name: grafana
1833
ports:
1934
- "3000:3000"
2035
volumes:
@@ -23,4 +38,13 @@ services:
2338
environment:
2439
- GF_SECURITY_ADMIN_PASSWORD=admin
2540
- GF_USERS_ALLOW_SIGN_UP=false
26-
restart: unless-stopped
41+
depends_on:
42+
- prometheus
43+
- tempo
44+
networks:
45+
- monitoring
46+
restart: unless-stopped
47+
48+
networks:
49+
monitoring:
50+
driver: bridge

deploy/grafana/provisioning/datasources/prometheus.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ apiVersion: 1
22

33
datasources:
44
- name: Prometheus
5+
uid: prometheus
56
type: prometheus
67
access: proxy
78
url: http://prometheus:9090
89
isDefault: true
9-
editable: false
10+
editable: false
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
apiVersion: 1
2+
3+
datasources:
4+
- name: Tempo
5+
type: tempo
6+
access: proxy
7+
url: http://tempo:3200
8+
isDefault: false
9+
editable: false
10+
jsonData:
11+
nodeGraph:
12+
enabled: true
13+
serviceMap:
14+
datasourceUid: prometheus
15+
tracesToLogsV2:
16+
datasourceUid: ""
17+
tracesToMetrics:
18+
datasourceUid: prometheus

deploy/prometheus/prometheus.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@ global:
22
scrape_interval: 15s
33
evaluation_interval: 15s
44

5+
remote_write: []
6+
57
scrape_configs:
68
- job_name: 'rpc-proxy'
79
static_configs:
8-
- targets: ['host.docker.internal:4000']
10+
- targets: ['host.docker.internal:4000']
911
labels:
1012
service: 'rpc-proxy'
13+
14+
- job_name: 'tempo'
15+
static_configs:
16+
- targets: ['tempo:3200']

deploy/tempo/tempo.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
stream_over_http_enabled: true
2+
3+
server:
4+
http_listen_port: 3200
5+
6+
distributor:
7+
receivers:
8+
otlp:
9+
protocols:
10+
grpc:
11+
endpoint: "0.0.0.0:4317"
12+
http:
13+
endpoint: "0.0.0.0:4318"
14+
15+
metrics_generator:
16+
storage:
17+
path: /var/tempo/generator/wal
18+
remote_write:
19+
- url: http://prometheus:9090/api/v1/write
20+
processor:
21+
service_graphs:
22+
dimensions:
23+
- service.name
24+
span_metrics:
25+
dimensions:
26+
- service.name
27+
28+
storage:
29+
trace:
30+
backend: local
31+
local:
32+
path: /var/tempo/traces
33+
wal:
34+
path: /var/tempo/wal
35+
36+
overrides:
37+
defaults:
38+
metrics_generator:
39+
processors:
40+
- service-graphs
41+
- span-metrics

go.mod

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/akash-network/rpc-proxy
22

3-
go 1.24.0
3+
go 1.25.0
44

55
require (
66
github.com/cometbft/cometbft v0.38.12
@@ -9,11 +9,17 @@ require (
99
github.com/prometheus/client_model v0.6.1
1010
github.com/spf13/cobra v1.9.1
1111
github.com/spf13/viper v1.19.0
12-
github.com/stretchr/testify v1.10.0
13-
golang.org/x/crypto v0.32.0
14-
golang.org/x/net v0.34.0
15-
golang.org/x/sync v0.10.0
16-
google.golang.org/grpc v1.70.0
12+
github.com/stretchr/testify v1.11.1
13+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0
14+
go.opentelemetry.io/otel v1.43.0
15+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0
16+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0
17+
go.opentelemetry.io/otel/sdk v1.43.0
18+
go.opentelemetry.io/otel/trace v1.43.0
19+
golang.org/x/crypto v0.49.0
20+
golang.org/x/net v0.52.0
21+
golang.org/x/sync v0.20.0
22+
google.golang.org/grpc v1.80.0
1723
)
1824

1925
require (
@@ -35,6 +41,7 @@ require (
3541
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
3642
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
3743
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
44+
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
3845
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3946
github.com/cockroachdb/errors v1.11.3 // indirect
4047
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect
@@ -68,6 +75,8 @@ require (
6875
github.com/go-kit/kit v0.12.0 // indirect
6976
github.com/go-kit/log v0.2.1 // indirect
7077
github.com/go-logfmt/logfmt v0.6.0 // indirect
78+
github.com/go-logr/logr v1.4.3 // indirect
79+
github.com/go-logr/stdr v1.2.2 // indirect
7180
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
7281
github.com/gogo/googleapis v1.4.1 // indirect
7382
github.com/gogo/protobuf v1.3.2 // indirect
@@ -77,11 +86,13 @@ require (
7786
github.com/google/btree v1.1.3 // indirect
7887
github.com/google/flatbuffers v24.12.23+incompatible // indirect
7988
github.com/google/go-cmp v0.7.0 // indirect
89+
github.com/google/uuid v1.6.0 // indirect
8090
github.com/gorilla/handlers v1.5.1 // indirect
8191
github.com/gorilla/mux v1.8.0 // indirect
8292
github.com/gorilla/websocket v1.5.3 // indirect
8393
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
8494
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
95+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
8596
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
8697
github.com/hashicorp/go-hclog v1.5.0 // indirect
8798
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@@ -116,7 +127,7 @@ require (
116127
github.com/prometheus/common v0.62.0 // indirect
117128
github.com/prometheus/procfs v0.15.1 // indirect
118129
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
119-
github.com/rogpeppe/go-internal v1.12.0 // indirect
130+
github.com/rogpeppe/go-internal v1.14.1 // indirect
120131
github.com/rs/cors v1.11.1 // indirect
121132
github.com/rs/zerolog v1.33.0 // indirect
122133
github.com/sagikazarmark/locafero v0.4.0 // indirect
@@ -134,15 +145,19 @@ require (
134145
github.com/zondax/ledger-go v0.14.3 // indirect
135146
go.etcd.io/bbolt v1.4.0-alpha.1 // indirect
136147
go.opencensus.io v0.24.0 // indirect
148+
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
149+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
150+
go.opentelemetry.io/otel/metric v1.43.0 // indirect
151+
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
137152
go.uber.org/multierr v1.10.0 // indirect
138153
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
139-
golang.org/x/sys v0.30.0 // indirect
140-
golang.org/x/term v0.28.0 // indirect
141-
golang.org/x/text v0.21.0 // indirect
154+
golang.org/x/sys v0.42.0 // indirect
155+
golang.org/x/term v0.41.0 // indirect
156+
golang.org/x/text v0.35.0 // indirect
142157
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
143-
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
144-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250122153221-138b5a5a4fd4 // indirect
145-
google.golang.org/protobuf v1.36.5 // indirect
158+
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
159+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
160+
google.golang.org/protobuf v1.36.11 // indirect
146161
gopkg.in/ini.v1 v1.67.0 // indirect
147162
gopkg.in/yaml.v3 v3.0.1 // indirect
148163
gotest.tools/v3 v3.5.1 // indirect

0 commit comments

Comments
 (0)