From Zipkin
Migrating from Zipkin to Sematext Tracing¶
This guide helps you migrate from Zipkin to Sematext Tracing while preserving your existing instrumentation and gaining advanced observability features.
Migration Overview¶
Sematext Tracing uses OpenTelemetry, which has excellent Zipkin compatibility, making migration smooth:
Current: Application → Zipkin Client → Zipkin Server → Zipkin Storage
New: Application → OpenTelemetry SDK → Sematext Agent → Sematext Cloud
Why Migrate to Sematext?¶
Advantages over self-hosted Zipkin:
- Managed Service: No server maintenance, scaling, or storage management
- Integrated Observability: Combine tracing with logs, metrics, and alerts in one platform
- Advanced Analytics: Service maps (coming soon), performance analysis, and anomaly detection
- OpenTelemetry Standard: Future-proof with industry-standard instrumentation
- Cost Efficiency: Built-in sampling, retention policies, and optimization tools
- Better Performance: Optimized ingestion and query performance
Migration Strategies¶
Strategy 1: Parallel Migration (Recommended)¶
Gradually migrate while keeping Zipkin as backup:
- Setup: Deploy Sematext alongside existing Zipkin
- Dual Sending: Configure apps to send traces to both systems
- Validation: Compare data quality and completeness
- Switch Over: Gradually move services to Sematext only
- Cleanup: Decommission Zipkin infrastructure
Strategy 2: Direct Migration¶
Quick migration for smaller deployments:
- Preparation: Set up Sematext infrastructure
- Service Groups: Migrate related services together
- Validate: Ensure trace continuity across service boundaries
- Complete: Switch remaining services
Pre-Migration Assessment¶
Document Current Setup¶
- [ ] Service Inventory: List all services sending traces to Zipkin
- [ ] Instrumentation Review: Document libraries and custom instrumentation
- [ ] Sampling Configuration: Note current sampling rates and strategies
- [ ] Dependencies: Identify dashboards, alerts, or tools using Zipkin data
- [ ] Storage Requirements: Estimate current trace volume and retention needs
Zipkin Configuration Audit¶
Review your current Zipkin setup:
# Example Zipkin client configuration
zipkin.base-url=http://zipkin:9411
zipkin.service-name=my-service
zipkin.sender.type=web
zipkin.sampler.probability=0.1
Step-by-Step Migration¶
Step 1: Sematext Infrastructure Setup¶
-
Create Tracing Apps:
- Create Sematext Tracing Apps for your services
- Organize by business domain or team ownership
- Save the Tracing App tokens
-
Deploy Sematext Agent:
- Install Sematext Agent on your infrastructure
- Enable OpenTelemetry support
- Verify agent is receiving traces on ports 4337 (gRPC) and 4338 (HTTP)
Step 2: Application Migration by Language¶
Java Applications¶
Current Zipkin Setup:
// Spring Boot with Zipkin
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
// Application properties
spring.zipkin.base-url=http://zipkin:9411
spring.application.name=my-service
spring.sleuth.sampler.probability=0.1
New OpenTelemetry Setup:
Auto-Instrumentation (Recommended):
# Download OpenTelemetry agent
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
# Replace Zipkin configuration
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=my-service \
-Dotel.exporter.otlp.endpoint=http://localhost:4338 \
-Dotel.exporter.otlp.protocol=http/protobuf \
-Dotel.traces.sampler=traceidratio \
-Dotel.traces.sampler.arg=0.1 \
-jar my-application.jar
Spring Boot Migration:
<!-- Remove Zipkin dependencies -->
<!-- Add OpenTelemetry -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
<version>1.32.0-alpha</version>
</dependency>
# application.yml
otel:
service:
name: my-service
exporter:
otlp:
endpoint: http://localhost:4338
protocol: http/protobuf
traces:
sampler:
probability: 0.1
Python Applications¶
Current Zipkin Setup:
from py_zipkin.zipkin import zipkin_span
@zipkin_span(service_name='my-service', span_name='operation')
def my_function():
# Your code here
pass
New OpenTelemetry Setup:
# Install OpenTelemetry packages
pip install opentelemetry-distro[otlp]
opentelemetry-bootstrap -a install
# Environment configuration
export OTEL_SERVICE_NAME=my-service
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4338
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_TRACES_SAMPLER=traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1
# Run with auto-instrumentation
opentelemetry-instrument python my_app.py
Manual migration:
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
@tracer.start_as_current_span("operation")
def my_function():
# Your code here - very similar to Zipkin
span = trace.get_current_span()
span.set_attribute("custom.tag", "value")
Node.js Applications¶
Current Zipkin Setup:
const zipkin = require('zipkin');
const {BatchRecorder} = require('zipkin');
const {HttpLogger} = require('zipkin-transport-http');
const recorder = new BatchRecorder({
logger: new HttpLogger({
endpoint: 'http://zipkin:9411/api/v2/spans'
})
});
const tracer = new zipkin.Tracer({
ctxImpl: new zipkin.ExplicitContext(),
recorder,
localServiceName: 'my-service'
});
New OpenTelemetry Setup:
// Install packages
// npm install @opentelemetry/auto-instrumentations-node @opentelemetry/sdk-node
// tracing.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'my-service',
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
// Environment variables
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4338';
process.env.OTEL_EXPORTER_OTLP_PROTOCOL = 'http/protobuf';
// Run: node -r ./tracing.js my-app.js
Go Applications¶
Current Zipkin Setup:
import (
"github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
)
reporter := zipkinhttp.NewReporter("http://zipkin:9411/api/v2/spans")
tracer, err := zipkin.NewTracer(
reporter,
zipkin.WithLocalEndpoint(&zipkin.Endpoint{
ServiceName: "my-service",
}),
)
New OpenTelemetry Setup:
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/semconv/v1.17.0/httpconv"
)
ctx := context.Background()
// Create OTLP exporter
exporter, err := otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint("http://localhost:4338"),
)
// Create tracer provider
tp := trace.NewTracerProvider(
trace.WithBatcher(exporter),
trace.WithResource(resource.NewWithAttributes(
semconv.ServiceNameKey.String("my-service"),
)),
trace.WithSampler(trace.TraceIDRatioBased(0.1)),
)
otel.SetTracerProvider(tp)
tracer := tp.Tracer("my-service")
Step 3: Configuration Migration¶
Sampling Migration¶
Zipkin Sampling:
# Zipkin probability sampling (10%)
zipkin.sampler.probability=0.1
# Zipkin counting sampler (every 10th trace)
zipkin.sampler.rate=10
OpenTelemetry Sampling:
# Probability sampling equivalent
export OTEL_TRACES_SAMPLER=traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1
# Always sample (for development)
export OTEL_TRACES_SAMPLER=always_on
# Custom sampling in code
sampler = TraceIdRatioBasedSampler(ratio=0.1)
Tag Migration¶
Zipkin Tags:
OpenTelemetry Attributes:
span.setAttribute("http.method", "GET");
span.setAttribute("user.id", "12345");
span.setStatus(StatusCode.ERROR, "Operation failed");
Step 4: Dual Export Configuration¶
Run both systems in parallel during migration:
Application-Level Dual Export (Recommended):
# Python example
from opentelemetry.exporter.zipkin.proto.http import ZipkinExporter
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# Zipkin exporter (keep temporarily during migration)
zipkin_exporter = ZipkinExporter(
endpoint="http://zipkin:9411/api/v2/spans"
)
# Sematext Agent OTLP endpoint (already running)
otlp_exporter = OTLPSpanExporter(
endpoint="http://localhost:4338/v1/traces" # Sematext Agent HTTP endpoint for traces
)
# Add both to tracer provider
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(BatchSpanProcessor(zipkin_exporter))
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
Note: Since Sematext Agent already accepts OTLP traffic (ports 4337 for gRPC, 4338 for HTTP for traces), you don't need an additional OpenTelemetry Collector. The application can send traces directly to Sematext Agent while maintaining the Zipkin export during migration.
Alternative: Feature Flag Approach
# Use feature flags to switch between systems
if feature_flag.is_enabled("use_sematext"):
exporter = OTLPSpanExporter(endpoint="http://localhost:4338/v1/traces")
else:
exporter = ZipkinExporter(endpoint="http://zipkin:9411/api/v2/spans")
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
Step 5: Data Validation¶
Compare Key Metrics Between Systems:
-
Service Coverage:
- Verify all Zipkin services appear in Sematext
- Check operation names and counts
- Validate service dependencies
-
Trace Quality:
- Compare span counts per trace
- Verify custom tags/attributes
- Check error trace capture
-
Volume and Sampling:
- Validate trace ingestion rates
- Confirm sampling is working correctly
- Monitor for data loss or duplication
Validation Script Example:
import requests
from datetime import datetime, timedelta
# Compare trace counts between systems
def compare_trace_counts():
end_time = datetime.now()
start_time = end_time - timedelta(hours=1)
# Zipkin query
zipkin_url = f"http://zipkin:9411/api/v2/traces?serviceName=my-service&start={start_time}&end={end_time}"
zipkin_traces = requests.get(zipkin_url).json()
# Sematext query (via API)
sematext_traces = query_sematext_traces("my-service", start_time, end_time)
print(f"Zipkin traces: {len(zipkin_traces)}")
print(f"Sematext traces: {len(sematext_traces)}")
# Allow for some variance due to timing differences
variance = abs(len(zipkin_traces) - len(sematext_traces))
if variance / len(zipkin_traces) > 0.05: # 5% tolerance
print("WARNING: Significant difference in trace counts!")
Step 6: Dashboard and Alert Migration¶
Export Zipkin Queries:
- Document important Zipkin UI searches and filters
- Note any custom dashboards built on Zipkin APIs
- List existing alerting rules
Create Sematext Equivalents:
- Tracing Overview - Your primary dashboard for service health insights and performance monitoring
- Traces Explorer - Search and filter traces to find specific issues
- Trace Details View - Drill down into individual traces with waterfall visualization
- Span Details Panel - Examine detailed span attributes
- Set up performance alerts for key metrics
- Configure anomaly detection for proactive monitoring
Common Migration Challenges¶
Challenge 1: B3 Propagation Headers¶
Issue: Zipkin uses B3 propagation headers that differ from OpenTelemetry's W3C standard
Solution: Configure OpenTelemetry to support B3 headers during migration:
from opentelemetry.propagators.b3 import B3MultiFormat, B3SingleFormat
from opentelemetry.propagators.composite import CompositePropagator
from opentelemetry.propagate import set_global_textmap
# Support both B3 and W3C headers during transition
propagator = CompositePropagator([
B3MultiFormat(),
B3SingleFormat(),
TraceContextTextMapPropagator(),
])
set_global_textmap(propagator)
Challenge 2: Custom Zipkin Annotations¶
Issue: Zipkin's timeline annotations don't directly map to OpenTelemetry
Solution: Convert annotations to events:
// Zipkin annotations
span.annotate("cs"); // Client send
span.annotate("cr"); // Client receive
// OpenTelemetry events
span.addEvent("client.send");
span.addEvent("client.receive");
// Or use semantic conventions
span.setSpanKind(SpanKind.CLIENT);
Challenge 3: Different Span Timing¶
Issue: Zipkin and OpenTelemetry may calculate durations differently
Solution: Validate timing accuracy and adjust if needed:
# Ensure consistent timing in manual instrumentation
import time
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("operation") as span:
start_time = time.time()
# Your operation
do_work()
duration_ms = (time.time() - start_time) * 1000
span.set_attribute("duration.manual", duration_ms)
Post-Migration Optimization¶
Performance Tuning¶
- Batch Configuration: Optimize export batch sizes for your traffic volume
- Sampling Strategies: Use advanced sampling for cost optimization
- Attribute Filtering: Remove unnecessary tags to reduce costs
Advanced Features¶
Explore Sematext features not available in Zipkin:
- Service dependency maps
- Anomaly detection and alerts
- Cross-system correlation (logs, metrics, traces)
- Performance baselines and SLA monitoring
Rollback Strategy¶
Prepare for potential rollback:
- Dual System Operation: Keep Zipkin running until fully validated
- Feature Flags: Implement toggles to switch between exporters
- Load Balancer Rules: Quick DNS/proxy changes for rollback
- Data Export: Backup critical trace data before Zipkin decommission
Migration Checklist Template¶
Week 1: Setup and Pilot¶
- [ ] Assess current Zipkin deployment (1 day)
- [ ] Create Sematext Tracing Apps and install agents (1 day)
- [ ] Select 2-3 pilot services and configure dual export (2-3 days)
- [ ] Validate data quality and test basic features (1-2 days)
Week 2: Full Migration¶
- [ ] Migrate remaining services in planned order
- [ ] Complete dashboard and alert setup
- [ ] Monitor system performance
- [ ] Train team on Sematext features
Week 3: Optimization and Cleanup¶
- [ ] Optimize sampling and performance settings
- [ ] Decommission Zipkin infrastructure
- [ ] Implement advanced Sematext features
- [ ] Document new processes
Troubleshooting Common Issues¶
Missing Traces¶
Symptoms: Traces appear in Zipkin but not Sematext
Solutions:
- Check OTLP exporter configuration
- Verify Sematext Agent connectivity
- Review sampling configuration
- Check for export errors in application logs
Performance Impact¶
Symptoms: Increased latency after migration
Solutions:
- Optimize batch processor settings
- Review sampling rates
- Check network connectivity to Sematext Agent
- Monitor resource usage on agent hosts
Context Propagation Issues¶
Symptoms: Broken trace chains between services
Solutions:
- Ensure all services use compatible propagation
- Configure B3 header support during transition
- Verify service-to-service communication headers
- Test trace propagation end-to-end
Support Resources¶
- Migration Help: Contact support@sematext.com for assistance
- Documentation: Review OpenTelemetry SDK guides
- Troubleshooting: Check the tracing troubleshooting guide
- Best Practices: Follow cost optimization strategies