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 incoordimap.flow.run_id)
- Good:
- Low Cardinality: Ensure
coordimap.flow.nameandcoordimap.flow.stepare 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.nameordb.namespacedb.operation(select,insert,update,delete,read, orwrite)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, orconsume)
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 eTypeScript 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.nameorcoordimap.flow.stepfields. Usecoordimap.flow.run_idor 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/extracthelper functions over queue exchanges or HTTP call headers). If traces break, Coordimap cannot construct complete logical flow paths.
Related Guides
eBPF Flows Configuration
Configure the Coordimap eBPF flows datasource to capture runtime network traffic with interface selection, deployment mode, external mappings, and crawl intervals.
Configuration
Configure the Coordimap AWS Flow Logs data source with the right scope_id, S3 log settings, AWS credentials, and crawl intervals for network flow ingestion.