Skip to content

Commit ce17955

Browse files
Pangjipingclaude
andauthored
feat(telemetry): fall back to HOST_IP and /etc/hostinfo for OTLP endpoint (#963)
When neither OTEL_EXPORTER_OTLP_METRICS_ENDPOINT nor OTEL_EXPORTER_OTLP_ENDPOINT is set, resolve the node IP from the HOST_IP env var, then from /etc/hostinfo, and point the OTLP/HTTP exporter at <node-ip>:4318 over plaintext. Lets execd and egress emit metrics in environments where only a node IP is available, without requiring callers to template the full endpoint URL. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 4995407 commit ce17955

1 file changed

Lines changed: 58 additions & 2 deletions

File tree

  • components/internal/telemetry

components/internal/telemetry/init.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package telemetry
1818
import (
1919
"context"
2020
"errors"
21+
"net"
2122
"os"
2223
"strings"
2324

@@ -38,6 +39,14 @@ type Config struct {
3839
RegisterMetrics func() error
3940
}
4041

42+
const (
43+
envOTLPMetricsEndpoint = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"
44+
envOTLPEndpoint = "OTEL_EXPORTER_OTLP_ENDPOINT"
45+
envHostIP = "HOST_IP"
46+
otlpHTTPPort = "4318"
47+
hostInfoPath = "/etc/hostinfo"
48+
)
49+
4150
// Init sets a noop TracerProvider, optionally MeterProvider with OTLP HTTP exporter.
4251
// Shutdown must be called on exit.
4352
func Init(ctx context.Context, cfg Config) (shutdown func(context.Context) error, err error) {
@@ -58,7 +67,7 @@ func Init(ctx context.Context, cfg Config) (shutdown func(context.Context) error
5867
)
5968

6069
if metricsEnabled() {
61-
mexp, err := otlpmetrichttp.New(ctx)
70+
mexp, err := otlpmetrichttp.New(ctx, metricsClientOptions()...)
6271
if err != nil {
6372
return nil, err
6473
}
@@ -100,8 +109,55 @@ func buildResource(ctx context.Context, serviceName string, extra []attribute.Ke
100109
return resource.New(ctx, opts...)
101110
}
102111

112+
// Endpoint precedence: OTEL_EXPORTER_OTLP_*_ENDPOINT -> HOST_IP -> /etc/hostinfo.
103113
func metricsEnabled() bool {
104-
return firstEndpoint(os.Getenv("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"), os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT")) != ""
114+
if otlpEndpointFromEnv() != "" {
115+
return true
116+
}
117+
_, ok := resolveNodeIP()
118+
return ok
119+
}
120+
121+
func metricsClientOptions() []otlpmetrichttp.Option {
122+
if otlpEndpointFromEnv() != "" {
123+
return nil
124+
}
125+
ip, ok := resolveNodeIP()
126+
if !ok {
127+
return nil
128+
}
129+
return []otlpmetrichttp.Option{
130+
otlpmetrichttp.WithEndpoint(net.JoinHostPort(ip, otlpHTTPPort)),
131+
otlpmetrichttp.WithInsecure(),
132+
}
133+
}
134+
135+
func otlpEndpointFromEnv() string {
136+
return firstEndpoint(os.Getenv(envOTLPMetricsEndpoint), os.Getenv(envOTLPEndpoint))
137+
}
138+
139+
func resolveNodeIP() (string, bool) {
140+
if ip := strings.TrimSpace(os.Getenv(envHostIP)); ip != "" && net.ParseIP(ip) != nil {
141+
return ip, true
142+
}
143+
return readHostInfoIP(hostInfoPath)
144+
}
145+
146+
func readHostInfoIP(path string) (string, bool) {
147+
data, err := os.ReadFile(path)
148+
if err != nil {
149+
return "", false
150+
}
151+
for _, line := range strings.Split(string(data), "\n") {
152+
line = strings.TrimSpace(line)
153+
if line == "" {
154+
continue
155+
}
156+
if net.ParseIP(line) != nil {
157+
return line, true
158+
}
159+
}
160+
return "", false
105161
}
106162

107163
func firstEndpoint(primary, fallback string) string {

0 commit comments

Comments
 (0)