Skip to content

Conversation

@xBlaz3kx
Copy link
Contributor

@xBlaz3kx xBlaz3kx commented Dec 6, 2025

Initial OpenTelemetry support (config, init, http API tracing).

Useful for complex scenario debugging (instead of relying solely on logs).

Ran it with the following compose:

version: '3.8'

services:
  # LGTM Stack - Single container with Loki, Grafana, Tempo, Mimir
  lgtm:
    image: grafana/otel-lgtm:latest
    hostname: lgtm
    ports:
      - "3000:3000"   # Grafana UI
      - "4317:4317"   # OTLP gRPC receiver
      - "4318:4318"   # OTLP HTTP receiver
    networks:
      - observability

  evcc:
    build:
      context: .
      dockerfile: Dockerfile
    command: [ "--config", "/etc/evcc/evcc.yaml" ]
    ports:
      - "7070:7070"   # evcc Web UI
    volumes:
      - ./evcc.yaml:/etc/evcc/evcc.yaml:ro
    depends_on:
      - lgtm
    networks:
      - observability

networks:
  observability:
    driver: bridge

This section should also be added to evcc.yaml

otel:
  enabled: true # enable OpenTelemetry
  endpoint: "lgtm:4317"  # OTLP endpoint (gRPC)
  protocol: "grpc"             # "grpc" or "http"
  insecure: true              # Set to true for insecure connections

@andig andig added enhancement New feature or request needs documentation Triggers issue creation in evcc-io/docs labels Dec 6, 2025
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • The Config.Protocol comment says gRPC is the default, but Init currently uses cfg.Protocol directly and will treat an empty string as an error; either default protocol := cfg.Protocol; if protocol == "" { protocol = "grpc" } or update the comment/config to reflect that it’s required.
  • The Config.Headers field is defined but never used when constructing the OTLP exporters; if you intend to support custom headers (for auth, tenancy, etc.), plumb these into otlptracegrpc.New / otlptracehttp.New, or remove the field for now to avoid confusion.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `Config.Protocol` comment says gRPC is the default, but `Init` currently uses `cfg.Protocol` directly and will treat an empty string as an error; either default `protocol := cfg.Protocol; if protocol == "" { protocol = "grpc" }` or update the comment/config to reflect that it’s required.
- The `Config.Headers` field is defined but never used when constructing the OTLP exporters; if you intend to support custom headers (for auth, tenancy, etc.), plumb these into `otlptracegrpc.New` / `otlptracehttp.New`, or remove the field for now to avoid confusion.

## Individual Comments

### Comment 1
<location> `util/otel/otel.go:44-45` </location>
<code_context>
+	var exporter sdktrace.SpanExporter
+	var err error
+
+	// Default to grpc if protocol not specified
+	protocol := cfg.Protocol
+	switch protocol {
+	case "grpc":
</code_context>

<issue_to_address>
**issue (bug_risk):** The protocol comment and implementation diverge; empty protocol currently fails instead of defaulting to gRPC.

Because `protocol := cfg.Protocol` goes straight into the `switch`, an empty string will fall into `default` and return an error, effectively making `Protocol` mandatory whenever otel is enabled. To match the comment, initialize a default first, e.g.:

```go
actionProtocol := cfg.Protocol
if actionProtocol == "" {
    actionProtocol = "grpc"
}
```

Also consider using the resolved value (e.g., `actionProtocol`) in the final log line instead of the raw config field.
</issue_to_address>

### Comment 2
<location> `util/otel/otel.go:28` </location>
<code_context>
+	Endpoint string `json:"endpoint"`
+	Protocol string `json:"protocol"` // "grpc" or "http"
+	Insecure bool   `json:"insecure"`
+	Headers  map[string]string
+}
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Configured OTLP headers are accepted but never applied to the exporters.

The `Headers` field is exposed on `Config` but never used when creating the gRPC/HTTP exporters. If it’s meant for auth/metadata, it should be passed into the exporter options (e.g., `otlptracegrpc.WithHeaders(cfg.Headers)` / `otlptracehttp.WithHeaders(cfg.Headers)`). Otherwise, consider removing it from `Config` to avoid a misleading, no-op setting.

Suggested implementation:

```golang
 // Config holds OpenTelemetry configuration
type Config struct {
	Enabled  bool              `json:"enabled"`
	Endpoint string            `json:"endpoint"`
	Protocol string            `json:"protocol"` // "grpc" or "http"
	Insecure bool              `json:"insecure"`
	Headers  map[string]string `json:"headers,omitempty"`

```

```golang
	opts := []otlptracegrpc.Option{
		otlptracegrpc.WithEndpoint(cfg.Endpoint),
	}

	if len(cfg.Headers) > 0 {
		opts = append(opts, otlptracegrpc.WithHeaders(cfg.Headers))
	}

```

```golang
	opts := []otlptracehttp.Option{
		otlptracehttp.WithEndpoint(cfg.Endpoint),
	}

	if len(cfg.Headers) > 0 {
		opts = append(opts, otlptracehttp.WithHeaders(cfg.Headers))
	}

```

If the option slices for gRPC/HTTP exporters are named differently or constructed inline (e.g., directly in `otlptracegrpc.New` / `otlptracehttp.New` calls), you’ll need to adapt the `SEARCH` patterns accordingly and still ensure that `otlptracegrpc.WithHeaders(cfg.Headers)` and `otlptracehttp.WithHeaders(cfg.Headers)` are appended to the respective option lists whenever `len(cfg.Headers) > 0`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@xBlaz3kx xBlaz3kx force-pushed the feat/observability branch 2 times, most recently from 4686903 to e42339d Compare December 6, 2025 19:38
@andig andig marked this pull request as draft December 6, 2025 20:02
@andig
Copy link
Member

andig commented Dec 8, 2025

+1% binary size and quite some additional dependencies. Apart from being an interesting technology- I'd like to better understand how one would actually utilize this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs documentation Triggers issue creation in evcc-io/docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants