Cross-Signal Correlation
This cookbook shows how to correlate data across logs, traces, and metrics in IceGate to quickly move from an alert to a root cause.
Warning
This guide uses the Loki API (fully implemented) and the Tempo API (retrieval and search available; TraceQL supported, unimplemented features return 501). The Prometheus API is NOT implemented - every route returns 501 except /-/ready; use LogQL metric queries as an alternative for log-based metrics.
How Correlation Works
IceGate stores all observability signals in Apache Iceberg tables with shared fields that enable cross-signal linking:
| Field | Present In | Purpose |
|---|---|---|
trace_id |
logs, spans | Links logs to the trace they belong to |
span_id |
logs, spans | Links logs to a specific span |
service_name |
logs, spans, metrics | Identifies the originating service |
tenant_id |
all tables | Isolates data per tenant |
timestamp |
all tables | Time correlation |
Workflow: Alert → Logs → Traces → Root Cause
1. Detect an Issue via Log Metrics
Use LogQL to detect error spikes:
# Error rate per service over the last hour
curl -G http://localhost:3100/loki/api/v1/query_range \
--data-urlencode 'query=sum by (service_name) (rate({severity_text="ERROR"}[5m]))' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
--data-urlencode 'step=300' \
-H "X-Scope-OrgID: my-tenant"
2. Investigate Error Logs
Drill into the failing service:
# Get error logs from the affected service
curl -G http://localhost:3100/loki/api/v1/query_range \
--data-urlencode 'query={service_name="order-service", severity_text="ERROR"}' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
--data-urlencode 'limit=50' \
-H "X-Scope-OrgID: my-tenant"
The response includes log entries with trace_id in the attributes:
{
"streams": [{
"stream": {
"service_name": "order-service",
"severity_text": "ERROR"
},
"values": [
["1704068100000000000", "Payment timeout for order ORD-789"],
["1704068200000000000", "Database connection pool exhausted"]
]
}]
}
3. Find Logs with a Specific Trace ID
Search for all logs associated with a request:
# Find logs by trace ID
curl -G http://localhost:3100/loki/api/v1/query_range \
--data-urlencode 'query={service_name=~".+"} |= "5B8EFFF798038103D269B633813FC60C"' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
-H "X-Scope-OrgID: my-tenant"
This returns logs from all services that participated in the same trace - showing the complete request path.
4. Retrieve the Full Trace
Use the trace ID to get the complete span tree via the Tempo API:
curl http://localhost:3200/api/traces/5B8EFFF798038103D269B633813FC60C \
-H "X-Scope-OrgID: my-tenant"
The response shows the request's journey through all services with timing for each span.
5. Find Slow Operations
Search for traces with high latency:
curl -G http://localhost:3200/api/search \
--data-urlencode 'tags=service.name=order-service' \
--data-urlencode 'minDuration=1s' \
--data-urlencode 'limit=10' \
-H "X-Scope-OrgID: my-tenant"
Grafana Cross-Signal Navigation
Link Logs → Traces
Configure Grafana to make trace IDs in log results clickable:
# grafana/provisioning/datasources/icegate.yaml
apiVersion: 1
datasources:
- name: IceGate Logs
type: loki
access: proxy
url: http://icegate-query:3100
jsonData:
httpHeaderName1: X-Scope-OrgID
derivedFields:
- datasourceUid: icegate-tempo
matcherRegex: '"trace_id":"([a-fA-F0-9]+)"'
name: TraceID
url: '$${__value.raw}'
secureJsonData:
httpHeaderValue1: my-tenant
uid: icegate-loki
- name: IceGate Traces
type: tempo
access: proxy
url: http://icegate-query:3200
jsonData:
httpHeaderName1: X-Scope-OrgID
tracesToLogs:
datasourceUid: icegate-loki
tags: ['service.name']
mappedTags: [{ key: 'service.name', value: 'service_name' }]
mapTagNamesEnabled: true
filterByTraceID: true
secureJsonData:
httpHeaderValue1: my-tenant
uid: icegate-tempo
With this configuration:
- In Explore > Loki: trace IDs in log lines become clickable links to the trace view
- In Explore > Tempo: each span shows a "Logs for this span" button that filters logs by trace and span ID
Build a Correlation Dashboard
Create a dashboard with linked panels:
Error rate panel (Loki, Time series):
sum by (service_name) (rate({severity_text="ERROR"}[5m]))
Error logs panel (Loki, Logs):
{severity_text="ERROR"}
Enable derived fields for trace ID linking.
Trace search panel (Tempo, Table): Filter by service name and minimum duration.
API-Level Correlation Patterns
Find All Signals for a Request
Given a trace ID, retrieve data from both APIs:
# 1. Get the trace (all spans)
curl http://localhost:3200/api/traces/5B8EFFF798038103D269B633813FC60C \
-H "X-Scope-OrgID: my-tenant"
# 2. Get all logs for this trace
curl -G http://localhost:3100/loki/api/v1/query_range \
--data-urlencode 'query={service_name=~".+"} |= "5B8EFFF798038103D269B633813FC60C"' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
-H "X-Scope-OrgID: my-tenant"
Correlate by Time Window
When you don't have a trace ID, correlate by timestamp:
# 1. Find the error time window
curl -G http://localhost:3100/loki/api/v1/query_range \
--data-urlencode 'query=count_over_time({severity_text="ERROR"}[1m])' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
--data-urlencode 'step=60' \
-H "X-Scope-OrgID: my-tenant"
# 2. Search traces in the same time window
curl -G http://localhost:3200/api/search \
--data-urlencode 'tags=service.name=order-service' \
--data-urlencode 'start=1704068100' \
--data-urlencode 'end=1704068200' \
-H "X-Scope-OrgID: my-tenant"
Correlate by Service
Find all signals for a specific service:
# Logs from the service
curl -G http://localhost:3100/loki/api/v1/query_range \
--data-urlencode 'query={service_name="order-service"}' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
-H "X-Scope-OrgID: my-tenant"
# Traces from the service
curl -G http://localhost:3200/api/search \
--data-urlencode 'tags=service.name=order-service' \
--data-urlencode 'start=1704067200' \
--data-urlencode 'end=1704070800' \
-H "X-Scope-OrgID: my-tenant"
# Labels for the service
curl http://localhost:3100/loki/api/v1/label/service_name/values \
-H "X-Scope-OrgID: my-tenant"
Best Practices
- Always include trace context in logs: Configure OpenTelemetry SDKs to inject
trace_idandspan_idinto log records automatically - Use consistent service names: The
service.nameresource attribute should match across logs, traces, and metrics for the same service - Set timestamp ranges: Always specify
startandendin queries to enable Iceberg partition pruning - Start broad, then narrow: Begin with error rate metrics, filter to specific error logs, then follow trace IDs to the root cause
Next Steps
- Set up centralized logging for your microservices
- Configure end-to-end tracing with instrumentation examples
- Review the data model for field details