Coordimap
Configuration

OpenTelemetry Flows & Tracing

Instrument your codebase with OpenTelemetry traces to map live service dependencies, business flows, and historical flow steps inside Coordimap.

Mapping Your Live System with OpenTelemetry and Coordimap

Coordimap supports rebuilding your system's live topology, business flows, and service relationships using OpenTelemetry trace spans as real-world evidence.

Rather than treating tracing as a passive tool for querying individual spans, Coordimap intercepts standard trace headers, processes span structures, and generates visual dependency diagrams that track changes historically.

When to Use OpenTelemetry Ingestion

Use OpenTelemetry tracing for Coordimap when you want to:

  • Visualize logical business flows: Connect multi-service user journeys (like a checkout or user signup flow) into interactive step-by-step maps.
  • Establish dependency relationships: Auto-discover database, queue, external service, and RPC interactions without manual curation.
  • Track live execution paths: Identify how requests actually propagate across services during runtime.

OpenTelemetry complements eBPF network flows

While Coordimap's flows data source captures raw network packets via eBPF, OpenTelemetry adds logical domain-first visibility. It maps exactly which business process (e.g., checkout.place_order) triggered the underlying database write or service call.


The Coordimap Attribute Contract

Coordimap relies on several standard OpenTelemetry semantic attributes alongside some Coordimap-specific attributes to stitch together its logical and physical topology maps.

Every span that should participate in Coordimap flow mapping should include these attributes where possible:

Prop

Type

Flow Naming Guidelines

  • Logical Names: Use stable names representing business operations rather than technical classes or file paths.
    • Good: checkout.place_order, billing.generate_invoice, inventory.reconcile_stock
    • Bad: handler, process, doWork, checkout.order.12345 (dynamic IDs belong in coordimap.flow.run_id)
  • Low Cardinality: Ensure coordimap.flow.name and coordimap.flow.step are stable across runs and do not contain dynamic user IDs or entity UUIDs.

Dependency Attributes & Relation Inference

Coordimap parses trace metadata to infer architectural relationships automatically. Ensure your spans leverage standard OpenTelemetry semantic conventions for downstream dependencies:

1. Database Operations (Infers reads / writes relations)

To map database topology correctly, your spans should set:

  • db.system (e.g., postgresql, mysql, mongodb, redis)
  • db.name or db.namespace
  • db.operation (select, insert, update, delete, read, or write)
  • db.sql.table (table name or collection when safe and available)

2. Messaging Operations (Infers publishes / consumes relations)

To map asynchronous queues and pub/sub structures:

  • messaging.system (e.g., nats, kafka, sqs, rabbitmq)
  • messaging.destination.name (subject, topic, queue name, or routing key)
  • messaging.operation (publish, send, receive, process, or consume)

3. Outbound Calls (Infers calls relations)

To connect microservice-to-microservice calls over HTTP, RPC, or SDKs:

  • peer.service (preferred stable target service identifier)
  • server.address (host or service address)
  • rpc.service (RPC service name)
  • http.host (HTTP host header)

Language Integration Patterns

Here is how you can instrument a simple business step using OpenTelemetry APIs within your codebase.

Go Implementation Example

package checkout

import (
	"context"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/trace"
)

var tracer = otel.Tracer("checkout-service")

func ProcessOrder(ctx context.Context, orderID string, requestID string) error {
	// Start an active span
	ctx, span := tracer.Start(ctx, "checkout.process_order", trace.WithSpanKind(trace.SpanKindInternal))
	defer span.End()

	// Assign Coordimap specific attributes
	span.SetAttributes(
		attribute.String("service.name", "checkout-service"),
		attribute.String("coordimap.flow.name", "checkout.place_order"),
		attribute.String("coordimap.flow.step", "checkout.process_order"),
		attribute.String("coordimap.flow.run_id", requestID),
		attribute.String("entity.type", "order"),
		attribute.String("entity.id", orderID),
	)

	// Execute business logic...
	if err := validateCart(ctx); err != nil {
		// Record error and update span status
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
		return err
	}

	return nil
}

Python Implementation Example

import logging
from opentelemetry import trace
from opentelemetry.trace import SpanKind, StatusCode

tracer = trace.get_tracer("checkout-service")

def process_order(order_id: str, request_id: str):
    # Start active span
    with tracer.start_as_current_span("checkout.process_order", kind=SpanKind.INTERNAL) as span:
        span.set_attribute("service.name", "checkout-service")
        span.set_attribute("coordimap.flow.name", "checkout.place_order")
        span.set_attribute("coordimap.flow.step", "checkout.process_order")
        span.set_attribute("coordimap.flow.run_id", request_id)
        span.set_attribute("entity.type", "order")
        span.set_attribute("entity.id", order_id)

        try:
            validate_cart()
        except Exception as e:
            # Handle error and mark span status
            span.record_exception(e)
            span.set_status(StatusCode.ERROR, str(e))
            raise e

TypeScript Implementation Example

import { trace, SpanKind, SpanStatusCode } from "@opentelemetry/api";

const tracer = trace.getTracer("checkout-service");

async function processOrder(orderId: string, requestId: string): Promise<void> {
  await tracer.startActiveSpan(
    "checkout.process_order",
    { kind: SpanKind.INTERNAL },
    async (span) => {
      span.setAttribute("service.name", "checkout-service");
      span.setAttribute("coordimap.flow.name", "checkout.place_order");
      span.setAttribute("coordimap.flow.step", "checkout.process_order");
      span.setAttribute("coordimap.flow.run_id", requestId);
      span.setAttribute("entity.type", "order");
      span.setAttribute("entity.id", orderId);

      try {
        await validateCart();
      } catch (error: any) {
        // Record failure
        span.recordException(error);
        span.setStatus({
          code: SpanStatusCode.ERROR,
          message: error.message,
        });
        throw error;
      } finally {
        span.end();
      }
    }
  );
}

Anti-Patterns

  • Dynamic Flow/Step Names: Do not put dynamic values (such as order IDs, user IDs, or dates) inside the coordimap.flow.name or coordimap.flow.step fields. Use coordimap.flow.run_id or other contextual attributes instead.
  • Spanning Everything: Avoid tracing every helper function. Focus on service ingress/egress, critical business execution boundaries, and downstream database/messaging calls.
  • Orphaned Spans: Ensure trace context is propagated correctly across network limits (e.g., using inject/extract helper functions over queue exchanges or HTTP call headers). If traces break, Coordimap cannot construct complete logical flow paths.

On this page