Key Concepts on OpenTelemetry for Rust

Tirslen Pather
5 min readOct 31, 2023

Setting up OpenTelemetry with Rust is a relatively simple process, but through my research, the resources around it are minimal. In this blog, I’ll share my experience with instrumenting Rust with OpenTelemetry and explore some “gaps” in the OpenTelemetry documentation.

I have been writing Rust for just under a year. Jumping to it from primarily writing in JS and Golang was a no-brainer. The benefits of Rust make sense, but it comes with the caveat of having a steeper learning curve than other languages. I will not be delving into Rust and all its fantastic benefits as this blog aims to advocate the use of OpenTelemetry in Rust applications and not why you should switch to Rust. (You should switch to Rust anyway tho)

Most articles I’ve read (and there aren’t many) about Rust and OpenTelemetry have always focused on quickly instrumenting Rust applications and pointing them to a SaaS observability solution. The apps generally focus on showcasing the product features or how quickly you can send data to their systems. Still, they rarely delve into the crates, best practices and why you should do it.

Meeting up with other Rust developers at meetups/conferences, I’ve narrowed it down to a few possibilities.

  • Not knowing what OpenTelemetry is.
  • With Rust’s enhanced safety, speed and concurrency, do you need to instrument your code? A few questioned whether adding the libraries to instrument their code was even worth it. With the majority responding with “Why should we?”.
  • Lack of documentation to follow.OpenTelemetry documentation around Rust could be better. The documentation around instrumentation and adoption of OpenTelemetry flourishes for more mature languages. If we head over to https://opentelemetry.io/docs/ and open the instrumentation tab, there is so much documentation around Go, Java, and JavaScript, and it even covers Erlang/Elixer. Instead, for Rust, we’re met with a fun page….
  • As you can see, it’s fantastic. In typical Rust fashion, here are the crates and go figure it out yourself.
  • No automatic instrumentation? Observability providers often package and provide libraries that instrument your code for you, making the process as easy as requiring the library, and we’re good to go for interpreted languages like JS, Java and Python. Compiled languages require much more effort, generally with you needing to specify where your instrumentation should be and what to capture.

The TL;DR of OpenTelemetry

OpenTelemetry (OTEL) is an Observability framework designed to capture telemetry data from your applications, such as metrics logs and traces. OTEL provides a vendor-agnostic set of APIs, SDKs, integrations and a collector service for your telemetry. OTEL returns ownership to the user as you control the telemetry you generate without being confined to a vendor’s format or tool.

Let’s look at key concepts of OpenTelemetry.

OpenTelemetry Signals

  • The contextual information that’s passed between spans
  • OpenTelemetry Baggage can propagate contextual information, such as a user ID, across multiple spans between multiple services. This is useful when the contextual information is only accessible from one service, but you want it attached to every span in a trace.
  • Take note that there are some caveats when using baggage. The context is stored within HTTP headers and would be exposed to anyone who can inspect your network packets.

OpenTelemetry Instrumentation:

  • Semantic Conventions: defines a standard naming convention for common telemetry types, such as application names, HTTP calls etc.
  • APIs: Defines the telemetry to be generated, metrics, logs and traces.
  • SDK: Language-specific implementations of the OpenTelmetry APIs
  • OpenTelemetry Protocol (OTLP): Protocol used to send data to Obeservability backends
  • Cross Service Propagators: Propagators transfer data between different services and processes.
  • Resource Detectors: represents the entity producing telemetry as resource attributes

OpenTelemetry Collector:

  • Receivers: Defines how the collector ingests data: push or pull
  • Processors: Defines how data is processed before it is exported
  • Exporters: Defines how you send data to your Obeservability backend: push or pull

If you want to explore more, look at OpenTelemetry Concepts Documentation.

OpenTelemetry Support for Rust, what’s available?

You have two main sources of information for Rust + OpenTelemetry. As mentioned before, the OTEL documentation only covers a little, so I primarily used the crates + resources available from GitHub.

  1. https://opentelemetry.io/docs/instrumentation/rust/
  2. https://github.com/open-telemetry/opentelemetry-rust

There are many crates available for Rust + OpenTelemetry. I’ll only explore a few crates in this blog.

  • opentelemetry-otlp
  • tracing (not an OTEL crate)
  • tracing-opentelemetry
  • If you’ve been writing Rust for some time, you’ll be quite familiar with the tracing library. If you’re already using it, it’s relatively straightforward to implement OpenTelemetry. The tracing-opentelemetry crate provides a straightforward way to create a subscriber that connects spans from multiple systems into a trace that emits them to an OTEL compatible tracing backend for visualisation.

Check out OpenTelemetry Rust GitHub for more crates.

Now you know what OpenTelemetry is and what’s available. Why should you use it?

The shortest answer: there is no “perfect” application.

With that said, I’m not talking about simple applications or your typical ‘hello world’ here.

External factors, like network latency, CPU, memory or third-party APIs, can affect your application’s performance. Your Rust app may be perfect, performant and error-free, but you can’t have 100% confidence that external factors can’t impact your application. OpenTelemetry instrumentation allows you to trace your application’s requests and add context and metadata to your spans, showing you the entire flow of what is occurring.

Benefits of OpenTelemetry:

  • Improved performance: Adding tracing to your applications will highlight bottlenecks or areas of code that can be optimized
  • Faster debugging: Viewing trace data in an observability backend can help you identify potential bugs, race conditions, and issues caused by upstream/downstream services.
  • Monitoring: Tracing implementation is critical to ensuring your applications run stable in production by providing real-time insights into issues.
  • Deeper Visibility: Tracing can provide deep links across many microservices, highlighting connections between systems you didn’t know existed.
  • Standardised format to collect metrics, logs and traces
  • Ownership of where the instrumentation lies
  • Flexibility to include and exclude relevant metadata, traces, spans

Summary

In this blog post, we explore the core concepts of OpenTelemetry and their benefits. Head to the next blog to see how we can implement them in Rust

Feel free to like, share and comment to help increase the visibility of OpenTelemetry for Rust!

Originally published at https://tirslo.hashnode.dev.

--

--

Tirslen Pather

I'm an advocate for Opensource and all things tech! Focusing on DevOps/SRE, IaC, IoT. Security and Opensource.