Implementing Distributed Tracing with OpenTelemetry in React Native and Fastify

This blog post explores the implementation of distributed tracing using OpenTelemetry in a React Native client and a Fastify server, comparing it with Sentry.

Blog cover image
2101050's avatar
2101050
6 views

Implementing Distributed Tracing with OpenTelemetry in React Native and Fastify

In today's microservices-driven architecture, understanding the flow of requests across different services is crucial. Distributed tracing provides this visibility, and OpenTelemetry is a powerful tool to achieve it. In this blog post, we'll explore how to implement distributed tracing using OpenTelemetry in a React Native client and a Fastify server. We'll also compare OpenTelemetry with Sentry, another popular monitoring tool, to help you decide which is best for your needs.

Introduction to OpenTelemetry

OpenTelemetry is an open-source observability framework for cloud-native software. It provides a set of APIs, libraries, agents, and instrumentation to capture and export metrics, logs, and traces. OpenTelemetry supports multiple languages and can export data to various backends like Jaeger, Zipkin, and Prometheus.

Setting Up OpenTelemetry

React Native (Client)

  1. Install Dependencies

    First, install the necessary OpenTelemetry packages:

    Bash
    1npm install @opentelemetry/api @opentelemetry/sdk-trace-web @opentelemetry/exporter-trace-otlp-http 2
  2. Initialize OpenTelemetry

    Configure OpenTelemetry to export traces to your backend:

    Javascript
    1import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'; 2import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; 3import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; 4import { ZoneContextManager } from '@opentelemetry/context-zone'; 5 6const provider = new WebTracerProvider(); 7const exporter = new OTLPTraceExporter({ 8 url: 'http://your-fastify-server:4318/v1/traces', 9}); 10 11provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); 12provider.register({ 13 contextManager: new ZoneContextManager(), 14}); 15 16const tracer = provider.getTracer('react-native-app'); 17
  3. Create Spans

    Manually create spans to trace operations:

    Javascript
    1import { trace } from '@opentelemetry/api'; 2 3const span = trace.getTracer('react-native-app').startSpan('fetch-data'); 4span.setAttribute('user.id', '123'); 5 6fetch('http://your-fastify-server/api/data') 7 .then(() => span.end()) 8 .catch((error) => { 9 span.recordException(error); 10 span.end(); 11 }); 12

Fastify (Server)

  1. Install Dependencies

    Install the necessary OpenTelemetry packages for Node.js:

    Bash
    1npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http 2
  2. Initialize OpenTelemetry

    Set up OpenTelemetry to export traces from the server:

    Javascript
    1const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); 2const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); 3const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); 4const { registerInstrumentations } = require('@opentelemetry/instrumentation'); 5const { FastifyInstrumentation } = require('@opentelemetry/instrumentation-fastify'); 6 7const provider = new NodeTracerProvider(); 8const exporter = new OTLPTraceExporter({ 9 url: 'http://otel-collector:4318/v1/traces', 10}); 11 12provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); 13provider.register(); 14 15registerInstrumentations({ 16 instrumentations: [new FastifyInstrumentation()], 17}); 18

Deploying OpenTelemetry Collector

To centralize and manage trace data, deploy an OpenTelemetry Collector:

Yaml
1services: 2 otel-collector: 3 image: otel/opentelemetry-collector 4 ports: 5 - "4318:4318" 6 volumes: 7 - ./otel-config.yaml:/etc/otel-config.yaml 8 command: ["--config=/etc/otel-config.yaml"] 9

otel-config.yaml:

Yaml
1receivers: 2 otlp: 3 protocols: 4 http: 5 endpoint: 0.0.0.0:4318 6 7exporters: 8 logging: 9 logLevel: debug 10 jaeger: 11 endpoint: "jaeger:14250" 12 tls: 13 insecure: true 14 15service: 16 pipelines: 17 traces: 18 receivers: [otlp] 19 exporters: [logging, jaeger] 20

Visualizing Traces

Use Jaeger to visualize the traces by accessing http://localhost:16686.

Comparing OpenTelemetry and Sentry

FeatureOpenTelemetrySentry
Distributed Tracing✅ Native support✅ Requires Performance Monitoring
Cross-Language Support✅ Extensive (JS/Node/Go/Python, etc.)✅ Limited in some languages
Data Export Flexibility✅ Export to Jaeger/Zipkin/Prometheus, etc.❌ Only to Sentry backend
Error Monitoring❌ Requires additional setup✅ Strong error capture and stack trace
Performance OverheadLowMedium (due to error and performance data)
Integration ComplexityHigh (requires Collector/Exporter setup)Low (easy integration)
Best Use CaseDistributed systems needing flexible backendError monitoring and simple performance analysis

Conclusion

Choose OpenTelemetry if:

  • You need comprehensive distributed tracing across services.
  • You want flexibility in exporting data to various backends.
  • You require support for multiple languages.

Choose Sentry if:

  • Your primary focus is on error monitoring and frontend performance.
  • You prefer a straightforward setup with minimal infrastructure maintenance.
  • You need an out-of-the-box UI and alerting capabilities.

Combined Approach

For a robust solution, consider using both OpenTelemetry for distributed tracing and Sentry for error monitoring:

Javascript
1// Fastify integration with Sentry and OpenTelemetry 2const Sentry = require('@sentry/node'); 3const { SentrySpanProcessor } = require('@sentry/opentelemetry-node'); 4 5Sentry.init({ 6 dsn: 'YOUR_SENTRY_DSN', 7 integrations: [new Sentry.Integrations.Http({ tracing: true })], 8 tracesSampleRate: 1.0, 9}); 10 11provider.addSpanProcessor(new SentrySpanProcessor(Sentry)); 12

By leveraging both tools, you can achieve comprehensive observability, combining the strengths of distributed tracing and error monitoring.


In summary, OpenTelemetry and Sentry each have their strengths and are suited to different use cases. By understanding your specific needs and the capabilities of each tool, you can make an informed decision on which to implement in your architecture.undefinedundefined

Recommended Articles

Discover more articles you might find interesting

Implementing LangGraph REST API with FastAPI
Technical Insights

Implementing LangGraph REST API with FastAPI

This guide provides a comprehensive implementation plan for building a LangGraph REST API using FastAPI, covering environment setup, agent definitions, endpoint creation, testing, and deployment.

2101050
Jun 18
153
Read More
DeepSite v2 Practical Guide
Technical Insights

DeepSite v2 Practical Guide

A comprehensive guide to DeepSite v2, covering its features, installation, and advanced workflows.

2101050
Jun 21
112
Read More
Fastify OpenTelemetry: Logging, Metrics, and Tracing in Practice
Technical Insights

Fastify OpenTelemetry: Logging, Metrics, and Tracing in Practice

Learn how to implement logging, metrics, and tracing in Fastify using OpenTelemetry.

2101050
Jul 11
106
Read More
Creating Diverse Logo Designs with Flux Model and ComfyUI
Technical Insights

Creating Diverse Logo Designs with Flux Model and ComfyUI

Learn to leverage the Flux model and ComfyUI for unique logo designs through effective prompts and examples.

2101050
Jan 10
93
Read More
Formatting Dates in TypeScript to UTC
Technical Insights

Formatting Dates in TypeScript to UTC

A guide on how to format dates in TypeScript to the specific format YYYY-MM-DDTHH:mm:ss+00:00.

2101050
Dec 19
83
Read More
Implementing a Custom Chat Model with LangChain
Technical Insights

Implementing a Custom Chat Model with LangChain

This guide provides a comprehensive blueprint for creating a custom chat model by subclassing LangChain's BaseChatModel, including configuration, method overrides, and error handling.

2101050
Jun 17
78
Read More