Skip to content

Grafana Tempo Service Graph Not Showing Edges Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about Grafana Tempo Service Graph Not Showing Edges Fix. We cover key concepts, practical examples, and best practices.

Your Grafana Tempo service graph shows nodes (services) but no edges between them β€” the span metrics are not generated, the service graph processor is not configured, or spans lack the required span.kind attribute for client-server relationships.

The Problem

# Tempo config missing service graph processor
distributor:
  receivers:
    otlp: ...

ingester: ...
compactor: ...

# No metrics_generator section

The service graph requires the metrics generator to process span pairs and compute edges. Without it, Tempo stores traces but never generates the relationship data.

Step-by-Step Fix

1. Enable the metrics generator

# tempo.yaml
metrics_generator:
  processor:
    service_graphs:
      enabled: true
    span_metrics:
      enabled: true
  registry:
    collection_interval: 15s
  storage:
    path: /var/tempo/generator/wal
    remote_write:
      - url: http://prometheus:9090/api/v1/write

2. Ensure spans have span.kind attribute

# Application code β€” set span.kind correctly
from opentelemetry import trace
from opentelemetry.trace import SpanKind

tracer = trace.get_tracer(__name__)

def make_request():
    # Client span β€” creates outgoing edge
    with tracer.start_as_current_span("http-call", kind=SpanKind.CLIENT):
        http.get("http://service-b/api")

# In Service B:
def handle_request():
    # Server span β€” creates incoming edge
    with tracer.start_as_current_span("handle-request", kind=SpanKind.SERVER):
        process()

3. Configure remote write target

metrics_generator:
  processor:
    service_graphs:
      enabled: true
    span_metrics:
      enabled: true
  registry:
    collection_interval: 15s
  storage:
    path: /var/tempo/generator/wal
    remote_write:
      - url: http://prometheus:9090/api/v1/write
        send_native_histograms: true
      - url: http://mimir:9009/api/v1/push

4. Query service graph metrics in Prometheus

// Request rate between services
sum(rate(traces_service_graph_request_total{job="tempo"}[5m])) by (client, server)

// Error rate between services
sum(rate(traces_service_graph_request_failed_total{job="tempo"}[5m])) by (client, server)

// Request duration between services
histogram_quantile(0.99,
  sum(rate(traces_service_graph_request_duration_seconds_bucket{job="tempo"}[5m])) by (le, client, server)
)

5. View in Grafana

# Install the service graph dashboard
# Grafana β†’ Dashboards β†’ Import β†’ 13402 (Tempo Service Graph)

# Or build a custom panel:
# Data source: Prometheus
# Query: traces_service_graph_request_total
# Panel type: Node Graph

Expected output:

Service Graph:
  payment-service ──HTTP POST──→ order-service (120 req/s, 0.5% err)
       β”‚                              β”‚
       β”‚                         SQL  β”‚
       β–Ό                              β–Ό
  user-service ──gRPC──→ inventory-service

Prevention Tips

  • Enable metrics_generator with service_graphs and span_metrics processors
  • Set span.kind to CLIENT and SERVER on all inter-service calls
  • Configure remote_write to a Prometheus-compatible store
  • Use auto-instrumentation which sets span.kind automatically
  • Verify span kind with TraceQL: { span.span.kind = 2 } (2=CLIENT, 3=SERVER)

Common Mistakes with tempo service graph

  1. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  2. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
  3. Using head and tail instead of pattern matching, causing runtime errors on empty lists

These mistakes appear frequently in real-world GRAFANA code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What span kind values are needed for service graphs?

CLIENT (kind=2) on the caller side, SERVER (kind=3) on the callee side. Internal spans (kind=1) and producer/consumer (kind=4/5) do not create service graph edges. Only CLIENT-SERVER pairs generate edges.

Why does my service graph show only one service?

Either: (1) only one service is instrumented, (2) all spans have the same span kind (e.g., all INTERNAL), or (3) cross-service calls use messaging (queue-based) instead of HTTP/gRPC. For messaging, use PRODUCER and CONSUMER kinds.

How long does it take for service graph data to appear?

The metrics generator processes spans with a collection interval (default 15s). After that, data is sent to Prometheus via remote write. Allow 30-60 seconds from trace ingestion to service graph visibility.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro