<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Itay Oved</title>
    <description>The latest articles on DEV Community by Itay Oved (@itay_from_lawrence).</description>
    <link>https://dev.to/itay_from_lawrence</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3471157%2Fcdb0d2b0-60e4-4067-9439-92c994e3ec95.png</url>
      <title>DEV Community: Itay Oved</title>
      <link>https://dev.to/itay_from_lawrence</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/itay_from_lawrence"/>
    <language>en</language>
    <item>
      <title>OpenTelemetry OpAMP: Getting Started Guide</title>
      <dc:creator>Itay Oved</dc:creator>
      <pubDate>Mon, 06 Oct 2025 13:55:18 +0000</pubDate>
      <link>https://dev.to/itay_from_lawrence/opentelemetry-opamp-getting-started-guide-2gne</link>
      <guid>https://dev.to/itay_from_lawrence/opentelemetry-opamp-getting-started-guide-2gne</guid>
      <description>&lt;p&gt;So you instrumented your application with OpenTelemetry. &lt;/p&gt;

&lt;p&gt;You send all your data to a collector and deploy to production.&lt;/p&gt;

&lt;p&gt;You now have a single collector for all your telemetry needs. Life is good.&lt;/p&gt;

&lt;p&gt;Then things get complicated: you want to collect host metrics using OpenTelemetry, so you deploy another type of collector to each host in your environment. &lt;/p&gt;

&lt;p&gt;Now you have two types of collectors running - life is still good.&lt;/p&gt;

&lt;p&gt;Then one night you wake up gripped by sudden horror; cold sweat, heart racing. &lt;/p&gt;

&lt;p&gt;You just had a nightmare of purple dogs and your APM bill. You decide that enough is enough. &lt;/p&gt;

&lt;p&gt;You want to sample your span data.&lt;/p&gt;

&lt;p&gt;Now you need new types of collectors: a load-balancing collector and a tail-sampling collector. At this point, you have four different types of collectors running in your infrastructure. &lt;/p&gt;

&lt;p&gt;Life is not as good as it used to be.&lt;/p&gt;

&lt;p&gt;Suddenly, something breaks - a config fails, a collector restarts because some configuration needs updating, but you have four types of collectors, each with hundreds of instances, all running huge, complex YAML configurations that no one understands. &lt;/p&gt;

&lt;p&gt;What do you do?&lt;/p&gt;

&lt;p&gt;This is where OpAMP (Open Agent Management Protocol) comes in. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is OpenTelemetry OpAMP?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/specs/opamp/" rel="noopener noreferrer"&gt;OpAMP&lt;/a&gt; is a protocol created by the OpenTelemetry community to help manage large fleets of OTel agents. &lt;/p&gt;

&lt;p&gt;OpAMP is primarily a specification, but it also defines and provides an implementation pattern for how agents can communicate remotely and support features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remote configuration
&lt;/li&gt;
&lt;li&gt;Status reporting
&lt;/li&gt;
&lt;li&gt;Agent telemetry
&lt;/li&gt;
&lt;li&gt;Secure agent updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how does OpAMP work?&lt;/p&gt;

&lt;p&gt;There are two components: the server and a client. They communicate via HTTP or WebSocket and exchange messages in two formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server sends a ServerToAgent message.
&lt;/li&gt;
&lt;li&gt;The agent sends an AgentToServer message.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ServerToAgent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bytes&lt;/span&gt; &lt;span class="na"&gt;instance_uid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ServerErrorResponse&lt;/span&gt; &lt;span class="na"&gt;error_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AgentRemoteConfig&lt;/span&gt; &lt;span class="na"&gt;remote_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ConnectionSettingsOffers&lt;/span&gt; &lt;span class="na"&gt;connection_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Beta]&lt;/span&gt;
  &lt;span class="n"&gt;PackagesAvailable&lt;/span&gt; &lt;span class="na"&gt;packages_available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Beta]&lt;/span&gt;
  &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AgentIdentification&lt;/span&gt; &lt;span class="na"&gt;agent_identification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ServerToAgentCommand&lt;/span&gt; &lt;span class="na"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Beta]&lt;/span&gt;
  &lt;span class="n"&gt;CustomCapabilities&lt;/span&gt; &lt;span class="na"&gt;custom_capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Development]&lt;/span&gt;
  &lt;span class="n"&gt;CustomMessage&lt;/span&gt; &lt;span class="na"&gt;custom_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Development]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;AgentToServer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;bytes&lt;/span&gt; &lt;span class="na"&gt;instance_uid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;sequence_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AgentDescription&lt;/span&gt; &lt;span class="na"&gt;agent_description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ComponentHealth&lt;/span&gt; &lt;span class="na"&gt;health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;EffectiveConfig&lt;/span&gt; &lt;span class="na"&gt;effective_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;RemoteConfigStatus&lt;/span&gt; &lt;span class="na"&gt;remote_config_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;PackageStatuses&lt;/span&gt; &lt;span class="na"&gt;package_statuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AgentDisconnect&lt;/span&gt; &lt;span class="na"&gt;agent_disconnect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ConnectionSettingsRequest&lt;/span&gt; &lt;span class="na"&gt;connection_settings_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Development]&lt;/span&gt;
  &lt;span class="n"&gt;CustomCapabilities&lt;/span&gt; &lt;span class="na"&gt;custom_capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Development]&lt;/span&gt;
  &lt;span class="n"&gt;CustomMessage&lt;/span&gt; &lt;span class="na"&gt;custom_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Status: [Development]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without getting too nerdy about the protocol spec, this is a flexible structure that also allows us to implement custom functionality with OpAMP.&lt;/p&gt;

&lt;p&gt;So we have a protocol that defines how agents and servers can talk to each other. How does it integrate with OpenTelemetry today?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How OpAMP fits OpenTelemetry today&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;First up is the &lt;code&gt;opamp-go&lt;/code&gt; implementation &lt;a href="https://github.com/open-telemetry/opamp-go" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This is an implementation of the OpAMP spec for both clients and servers, and the examples include a server with a basic UI that we’ll use for this guide.&lt;/p&gt;

&lt;p&gt;Ok, we have a server. How do we use it with an existing OTel Collector?&lt;/p&gt;

&lt;p&gt;You can integrate OpAMP with the OTel Collector in three increasing levels of capability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpAMP Extension (read‑only)&lt;/li&gt;
&lt;li&gt;OpAMP Supervisor (full remote management)&lt;/li&gt;
&lt;li&gt;OpAMP Bridge (for the OpenTelemetry k8s Operator. Beyond this guide, and we'll create a dedicated guide)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll walk through 1 and 2, step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To follow along, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker - For running containerized collectors&lt;/li&gt;
&lt;li&gt;Go (1.19 or later) - To run the OpAMP server example&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it! Let's dive into the first integration method.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The OpAMP Extension (read-only)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The OpenTelemetry Collector supports extensions (e.g., the health check extension), and the community created the OpAMP extension. &lt;/p&gt;

&lt;p&gt;By nature, extensions have limited capabilities: the OpAMP extension cannot update the collector’s installed packages or its configuration - it’s “read-only” for OpAMP. &lt;/p&gt;

&lt;p&gt;It’s useful for status reporting and sending the collector’s config to the OpAMP server. That’s basically it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7v2934w1kbrxj3fywwn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7v2934w1kbrxj3fywwn.png" alt="OpAMP Extension showing read-only communication with OpAMP server" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get started, we’ll use the contrib Docker image &lt;code&gt;otel/opentelemetry-collector-contrib&lt;/code&gt; for the Collector, and we’ll clone the &lt;a href="https://github.com/open-telemetry/opamp-go" rel="noopener noreferrer"&gt;opamp-go repo&lt;/a&gt; and run the example server locally.&lt;/p&gt;

&lt;p&gt;Set up the OpAMP server:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git clone https://github.com/open-telemetry/opamp-go.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd opamp-go/internal/examples/server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;go run main.go&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This starts an OpAMP server listening on localhost:4320 for OpAMP agents. &lt;/p&gt;

&lt;p&gt;Navigate to localhost:4321 to see the agents page (it will be empty at first).&lt;/p&gt;

&lt;p&gt;Now let’s set up an OTel Collector with a basic configuration for the OpAMP extension.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a folder named &lt;code&gt;opamp-extension&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a file named &lt;code&gt;config.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add any collector config you want to test. In this example, we'll use a simple config with an OTLP receiver and a console (debug) exporter.&lt;/li&gt;
&lt;li&gt;Add the opamp extension in the extensions section.&lt;/li&gt;
&lt;li&gt;Set the server address (ws endpoint) to &lt;code&gt;host.docker.internal:4320&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This works on Docker Desktop for Mac/Windows. On Linux, you may need to use &lt;code&gt;172.17.0.1:4320&lt;/code&gt;, or add &lt;code&gt;--add-host=host.docker.internal:host-gateway&lt;/code&gt; to your docker run command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Add the extension to the service extensions array.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;protocols&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;grpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0:4317&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0:4318&lt;/span&gt;

&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;verbosity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;detailed&lt;/span&gt;

&lt;span class="na"&gt;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;opamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ws&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ws://host.docker.internal:4320/v1/opamp&lt;/span&gt;
    &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;reports_effective_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opamp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;traces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's run our collector using Docker&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; otelcol-opamp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/config.yaml:/etc/otelcol-contrib/config.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  otel/opentelemetry-collector-contrib:latest &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/etc/otelcol-contrib/config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your collector should now be running and reporting to the OpAMP server. &lt;/p&gt;

&lt;p&gt;Go back to the agents page to see it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtkfyqrw6q51gtr0a6u0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmtkfyqrw6q51gtr0a6u0.png" alt="OpAMP server showing connected agents" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll see the collector and the config we set up, running and reporting to OpAMP. This is a good start, but it doesn’t provide all the capabilities we need for production.&lt;/p&gt;

&lt;p&gt;This leads us to the second method.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The OpAMP Supervisor (full remote control)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To enable the OTel Collector’s advanced remote management capabilities without changing the collector itself, the community introduced a “supervisor” process. &lt;/p&gt;

&lt;p&gt;Instead of managing the otelcol process directly, the supervisor wraps it: you start the supervisor, and it starts (and manages) the collector process. &lt;/p&gt;

&lt;p&gt;This pattern gives us great power (which comes, of course, with great responsibility): you can update config, download new packages, stop/restart the process, pull its stdout logs and send them anywhere, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjp41k6rypamom1zyfrmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjp41k6rypamom1zyfrmz.png" alt="OpAMP Supervisor providing full remote management capabilities" width="800" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thankfully, the supervisor has a dedicated Docker image, so setup is straightforward. &lt;/p&gt;

&lt;p&gt;To make it even easier, we’ll create a custom container that includes both the supervisor and the collector.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a folder named &lt;code&gt;opamp-supervisor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a new file named &lt;code&gt;Dockerfile&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;otel/opentelemetry-collector-opampsupervisor:latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;supervisor&lt;/span&gt;

&lt;span class="c"&gt;# Get OpenTelemetry collector&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;otel/opentelemetry-collector-contrib:latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;otel&lt;/span&gt;

&lt;span class="c"&gt;# Final stage&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest&lt;/span&gt;

&lt;span class="c"&gt;# Copy from builder - use the correct source path&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=supervisor /usr/local/bin/opampsupervisor ./opampsupervisor&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; supervisor.yaml .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; collector.yaml .&lt;/span&gt;

&lt;span class="c"&gt;# Copy from OpenTelemetry&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=otel /otelcol-contrib /otelcol-contrib&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 4317 4318&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["./opampsupervisor", "--config", "supervisor.yaml"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a file named &lt;code&gt;supervisor.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the supervisor config.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ws://host.docker.internal:4320/v1/opamp&lt;/span&gt;
  &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;insecure_skip_verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;insecure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;reports_effective_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;reports_own_metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;reports_own_logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;reports_health&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;accepts_remote_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;reports_remote_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;executable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/otelcol-contrib&lt;/span&gt;
  &lt;span class="na"&gt;config_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/collector.yaml&lt;/span&gt;

&lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/opamp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note, we’re enabling more capabilities than with the OpAMP extension.&lt;/p&gt;

&lt;p&gt;Create a sample collector config similar to before, but without the OpAMP extension (since the supervisor manages it).&lt;/p&gt;

&lt;p&gt;Let’s build and run our new Docker container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; opamp-supervisor &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker run &lt;span class="nt"&gt;-d&lt;/span&gt; opamp-supervisor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit the agents page again. You should see the new “supervised” agent.&lt;/p&gt;

&lt;p&gt;Now let’s modify the collector’s config remotely.&lt;/p&gt;

&lt;p&gt;We’ll add a new exporter and include it in the pipeline. In the “Additional Configuration” editor, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost:4317&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;insecure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;traces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The supervisor will attempt to merge this with the existing collector config.&lt;br&gt;&lt;br&gt;
In this case, we’re adding a new OTLP exporter that sends traces to localhost:4317.&lt;/p&gt;

&lt;p&gt;Refresh the agent page - you should see the agent’s effective config now includes the new OTLP exporter in the traces pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24msucogf80evj3ytkcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24msucogf80evj3ytkcl.png" alt="Adding OTLP exporter endpoint in OpAMP server" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyy4avcbk8luo26arsd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyyy4avcbk8luo26arsd5.png" alt="OTLP receivers configuration in effective config" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, you’ve used the supervisor to change the running collector: you added an OTLP exporter, merged it into the traces pipeline, and saw the effective config reflect the update in the agents page. &lt;/p&gt;

&lt;p&gt;From here, you can iterate the same way - add receivers and exporters, tweak processors - directly from the OpAMP server UI and watch the Supervisor apply changes safely. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why OpAMP?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Back to your awful and vivid nightmare, when you go from one collector to many - different types, hundreds of instances, frequent changes - keeping configs aligned, knowing what’s actually running and what breaks gets extremely challenging. &lt;/p&gt;

&lt;p&gt;That’s the core win of OpAMP: centralized, remote control of many collectors with one workflow. &lt;/p&gt;

&lt;p&gt;One place to see agents, their health, and their effective config, and to safely roll changes across the fleet from a single UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Lawrence makes it better&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In this guide, we stuck to the OpenTelemetry available UI. While it’s a great way to understand the concept of OpAMP, in real-world scenarios, you’ll want a more advanced set of capabilities.&lt;/p&gt;

&lt;p&gt;Lawrence helps teams configure, visualize, test, and troubleshoot complex OpenTelemetry deployments at scale. &lt;/p&gt;

&lt;p&gt;We’re currently in private beta, so if you’re migrating to OpenTelemetry, need to manage a fleet of OTel agents, need advice on OpenTelemetry (we know our stuff), or need a hug, &lt;a href="https://getlawrence.com/" rel="noopener noreferrer"&gt;reach out here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>observability</category>
      <category>devops</category>
      <category>opamp</category>
    </item>
    <item>
      <title>The 67-Second OpenTelemetry Problem</title>
      <dc:creator>Itay Oved</dc:creator>
      <pubDate>Wed, 03 Sep 2025 14:01:00 +0000</pubDate>
      <link>https://dev.to/itay_from_lawrence/the-67-second-opentelemetry-problem-e0b</link>
      <guid>https://dev.to/itay_from_lawrence/the-67-second-opentelemetry-problem-e0b</guid>
      <description>&lt;p&gt;In 1950, a Formula One pit stop took 67 seconds. Mechanics wrestled with jacks and fuel cans while the driver sat still, powerless. That was normal.&lt;/p&gt;

&lt;p&gt;By the 1980s, the best crews had cut it to under 10 seconds.&lt;/p&gt;

&lt;p&gt;Then came 1993. Michael Schumacher’s Benetton team unveiled a radical refueling system. Normally, a pit stop meant losing ground. Schumacher went in second and came out first.&lt;/p&gt;

&lt;p&gt;For the first time, the pit lane had decided the race.&lt;/p&gt;

&lt;p&gt;Today, Red Bull can change four tires in 1.82 seconds. Faster than a blink (well, maybe two).&lt;/p&gt;

&lt;p&gt;In a sport built on speed, the greatest edge came not from the car at all, but from reimagining what could happen in the garage.&lt;/p&gt;

&lt;p&gt;OpenTelemetry adoption feels a lot like those 1950s pit stops.&lt;/p&gt;

&lt;p&gt;Painfully slow, full of wasted motion, and accepted as normal. Most teams know the standard is inevitable, but they still find themselves stuck in the garage instead of back on track.&lt;/p&gt;

&lt;p&gt;The problems fall into three patterns. Projects often drag on for a long time before the first trace appears. The concepts feel like a foreign language. And even when the data shows up, momentum has already drained away.&lt;/p&gt;

&lt;h2&gt;
  
  
  67 Seconds Pit Stops
&lt;/h2&gt;

&lt;p&gt;Getting started with OpenTelemetry is notoriously slow. Projects are scoped in months, sometimes years. It feels less like a rollout and more like sitting in the pit lane while everyone else keeps racing.&lt;/p&gt;

&lt;p&gt;Decision fatigue hits immediately. Do you try zero-instrumentation or wire everything in manually? Which propagator, which exporter, which SDK version? Every service, every language adds another fork in the road. The OpenTelemetry ecosystem offers dozens of choices before you write a single line of code.&lt;/p&gt;

&lt;p&gt;Teams spend weeks just picking the right combination of components and only discover if they chose correctly much later, when production traffic is already flowing.&lt;/p&gt;

&lt;p&gt;The work is upside down. Instead of shipping instrumentation, devs spend weeks learning concepts and debugging basics. Dozens of lines of YAML later, there’s still nothing to show for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Foreign Language
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry concepts seem simple on paper. Context propagation, span processors, exporters. Straightforward steps to collect and move data.&lt;/p&gt;

&lt;p&gt;In reality, when you try to implement them, it's like learning a new language from scratch.&lt;/p&gt;

&lt;p&gt;You need to understand the subtleties of each component, how they interact, and how to troubleshoot when things go sideways.&lt;/p&gt;

&lt;p&gt;This learning curve creates a significant barrier to adoption. Only a few experts can navigate OpenTelemetry. The rest of us wait, guess, or sit in a dark room reading the docs.&lt;/p&gt;

&lt;p&gt;Copy a snippet, pray to the observability gods, move on.&lt;/p&gt;

&lt;p&gt;The frustration is compounded by the fact that every language stack has its unique quirks. A solution that works well in Java might not work in Go. Python requires a different approach altogether. Scattered documentation, examples that don't work in real life, and the same questions get asked online - "I got OpenTelemetry to work. But why was it so complicated?”&lt;/p&gt;

&lt;p&gt;More time spent decoding the language of OTel than shipping value with it.&lt;/p&gt;

&lt;p&gt;Telemetry that takes months to explain is telemetry nobody uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Out of Fuel
&lt;/h2&gt;

&lt;p&gt;Most OpenTelemetry projects ignite with high hopes. Imagine a world with one standard - free from vendor lock-in, with a clear view of complex systems. The entire team rallies behind this vision at the outset.&lt;/p&gt;

&lt;p&gt;But the spark doesn’t last. Early enthusiasm gives way to long debugging sessions and recurring setbacks. Critical decisions pile up like unpaid bills, and the rollout starts to feel less like progress and more like maintenance.&lt;/p&gt;

&lt;p&gt;By the time data finally arrives, the thrill - as the great B.B. King would say - is gone.&lt;/p&gt;

&lt;p&gt;The coverage is patchy, the instrumentation inconsistent, and the results underwhelm. The company that was energized at the start is now second-guessing whether the effort was worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Winning the Race
&lt;/h2&gt;

&lt;p&gt;Slow adoption doesn’t just waste time; it damages OpenTelemetry itself.&lt;/p&gt;

&lt;p&gt;Once a rollout drags, people stop blaming the process and start blaming the standard. “We tried OTel and it didn’t work.” That reputation sticks (and sucks).&lt;/p&gt;

&lt;p&gt;The result is a graveyard of half-instrumented services. Different SDK versions, configs nobody understands, dashboards nobody trusts. Some teams quietly fall back to vendor agents because at least those give them data.&lt;/p&gt;

&lt;p&gt;The tragedy is that OTel isn’t broken - the way most companies adopt it is. But every failed attempt chips away at confidence, and adoption debt spreads fast.&lt;/p&gt;

&lt;p&gt;Pit stops used to lose you the race. Today, they win it.&lt;/p&gt;

&lt;p&gt;In 1950, what was supposed to keep the car in the race looked like wasted time in the garage. The teams that learned how to turn that dead time into an advantage were the ones pulling ahead.&lt;/p&gt;

&lt;p&gt;OpenTelemetry is your pit stop - use it to win.&lt;/p&gt;

&lt;h2&gt;
  
  
  67 → 1.82 (this is marketing stuff now)
&lt;/h2&gt;

&lt;p&gt;What if OpenTelemetry adoption looked more like Red Bull's pit crew? Automated, instant, light work, smooth learning curve. &lt;a href="https://getlawrence.com/" rel="noopener noreferrer"&gt;Lawrence&lt;/a&gt; provides developer tools to automatically install, maintain, and troubleshoot OpenTelemetry at scale. So you don't wait 67 seconds while others keep racing. Get into the &lt;a href="https://getlawrence.com/" rel="noopener noreferrer"&gt;private beta&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>observability</category>
      <category>devops</category>
      <category>sre</category>
      <category>opentelemetry</category>
    </item>
  </channel>
</rss>
