<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Martino Fornasa</title>
  <subtitle>DevOps Consultant | Cloud Native | Technical Blog</subtitle>
  <link href="https://fornasa.it/feed.xml" rel="self" />
  <link href="https://fornasa.it/" />
  <updated>2025-12-05T00:00:00Z</updated>
  <id>https://fornasa.it/</id>
  <author>
    <name>Martino Fornasa</name>
    <email>martino@fornasa.it</email>
  </author>
  <entry>
    <title>OpenTelemetry Incremental Adoption Strategies</title>
    <link href="https://fornasa.it/posts/opentelemetry-incremental-adoption-strategies/" />
    <updated>2025-11-14T00:00:00Z</updated>
    <id>https://fornasa.it/posts/opentelemetry-incremental-adoption-strategies/</id>
    <content type="html">&lt;p&gt;OpenTelemetry is rapidly becoming the de facto standard for telemetry collection. My &lt;em&gt;highly scientific&lt;/em&gt; show-of-hands polls during a couple of public speaking engagements over the last year show steadily rising awareness and adoption.&lt;/p&gt;
&lt;p&gt;OpenTelemetry (OTel) is a framework designed to collect logs, metrics, traces, and other signals. It includes a set of SDKs, semantic conventions, a protocol specification, and an agent called the OpenTelemetry Collector, essentially a modular data pipeline processor. OTel goal is to eliminate vendor lock-in and unify how telemetry is collected and transported.&lt;/p&gt;
&lt;p&gt;On the other hand, OpenTelemetry isn&#39;t a backend, database, or visualization system. Users bring their own Elastic, Grafana, ClickHouse, Datadog, or whatever else fits their stack. The promise is to be able to swap the observability database/console without re-instrumenting everything.&lt;/p&gt;
&lt;p&gt;OpenTelemetry&#39;s main strengths are its vendor-neutral approach, drive toward unified instrumentation, and promise of easy backend switching. However, these benefits come with some limitations: significant complexity, committee-driven evolution, and uneven maturity across components. Integration into existing stacks presents another challenge: while third-party distributions can help, they often introduce bloat and vendor bias, undermining OTel&#39;s core philosophy of neutrality.&lt;/p&gt;
&lt;p&gt;In this post, I will cover three main themes. Feel free to skip to the section that is more relevant to you.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fornasa.it/posts/opentelemetry-incremental-adoption-strategies/#otel-collector&quot;&gt;First&lt;/a&gt;, a brief introduction to the OpenTelemetry collector for those who need it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fornasa.it/posts/opentelemetry-incremental-adoption-strategies/#collection&quot;&gt;Second&lt;/a&gt;, how to plan and implement the collection infrastructure to gather telemetry data and send it to an observability backend.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fornasa.it/posts/opentelemetry-incremental-adoption-strategies/#adoption-patterns&quot;&gt;Third&lt;/a&gt;, some adoption strategies that have worked for me when implementing OpenTelemetry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the TL;DR, jump to &lt;a href=&quot;https://fornasa.it/posts/opentelemetry-incremental-adoption-strategies/#fostering-adoption&quot;&gt;fostering adoption&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;otel-collector&quot; tabindex=&quot;-1&quot;&gt;Part one: The OpenTelemetry collector&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/collector.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;The OpenTelemetry Collector is the agent of the OTel collection infrastructure. It consists of three main building blocks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Receivers&lt;/strong&gt; - Ingest data through 90+ supported mechanisms and protocols. Some receivers open a service to accept connections (such as OTLP protocol endpoints), while others actively fetch data (such as reading log files or consuming from syslogs).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Processors&lt;/strong&gt; - Modify, enrich, filter, or compress data as it flows through the pipelines. A common use case is enriching messages with metadata, such as adding Kubernetes container information (service names, pod labels, etc.).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exporters&lt;/strong&gt; - Send data to backends or forward it to another collector. Many backends natively support the OTLP protocol for direct integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So it&#39;s possible to build multiple pipelines by connecting the building blocks. You can search for available collector components on the &lt;a href=&quot;https://opentelemetry.io/ecosystem/registry/&quot;&gt;OpenTelemetry Registry&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The collector is distributed as a binary or container image. Given the large number of available components, you can build a custom distribution using the OpenTelemetry Collector Builder. However, several pre-built distributions are available: a &lt;strong&gt;core distribution&lt;/strong&gt; with basic essential components, a &lt;strong&gt;contrib distribution&lt;/strong&gt; with a much wider selection of components (not recommended for production use), and a &lt;strong&gt;Kubernetes distribution&lt;/strong&gt; specifically tailored for Kubernetes environments.&lt;/p&gt;
&lt;p&gt;Additionally, many observability vendors offer &lt;strong&gt;third-party distributions&lt;/strong&gt; that bundle a customized OpenTelemetry Collector with vendor-specific tools and configurations optimized for their platform or cloud ecosystem. I generally avoid third-party distributions for several reasons. They can be bloated and overly complex, they don&#39;t align well with an incremental adoption approach (typically the most practical path forward), and they undermine OpenTelemetry&#39;s core benefit of avoiding vendor lock-in. That said, vendor distributions can serve as inspiration to understand how to observe a certain ecosystem.&lt;/p&gt;
&lt;p&gt;The collector is configured using, you guessed it, a YAML file. Here&#39;s a basic example:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;receivers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;token key atrule&quot;&gt;otlp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;token key atrule&quot;&gt;protocols&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;grpc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;token key atrule&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; localhost&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4317&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;token key atrule&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; localhost&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4318&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;processors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;token key atrule&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;exporters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;token key atrule&quot;&gt;otlp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;token key atrule&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; backend&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4317&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;token key atrule&quot;&gt;pipelines&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;token key atrule&quot;&gt;logs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;receivers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;otlp&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;processors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;batch&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;exporters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;otlp&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;collection&quot; tabindex=&quot;-1&quot;&gt;Part two: The collection infrastructure&lt;/h2&gt;
&lt;h3 id=&quot;collecting-data-from-virtual-machines&quot; tabindex=&quot;-1&quot;&gt;Collecting data from virtual machines&lt;/h3&gt;
&lt;p&gt;The typical approach is to put the OTel collector in the VM, with one process per VM. This is not mandatory; for example, an application that is natively instrumented with OTel SDK could send directly to a centralized collector. This may work in simple cases, but a local process offers more capabilities, for example scraping logs files, fetching syslog and getting local metrics. So, having a local collector is recommended for most setups.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/arch-vm.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;The typical datacenter-level architecture uses a centralized collector acting as a gateway that forwards data to the backend(s). Each collector instance can be configured with the appropriate level of resilience. For example, it can buffer telemetry in local storage to handle situations when the backend is unavailable or unable to receive data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/arch.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;In some scenarios, a third hierarchical level makes sense, such as when instrumenting multiple datacenters; such an approach can simplify authentication logic and improve compression efficiency, as well as providing a local storage to increase resiliency to wide-area network failures.&lt;/p&gt;
&lt;h3 id=&quot;resiliency&quot; tabindex=&quot;-1&quot;&gt;Resiliency&lt;/h3&gt;
&lt;p&gt;Resiliency mechanisms can be configured. By default, the sending queue is kept in memory, which can result in data loss during failures.
To increase resiliency, you can also configure file-based storage to keep messages on disk, preventing data loss during network outages or backend issues. Another useful mechanism is batching, which groups messages together to improve compression and throughput. In the present of a highly available Kafka deployment, you can use it to decouple senders and receivers for additional resilience.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Sending queue (in memory) + retry on failure&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;exporters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;otlp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;sending_queue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;queue_size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;retry_on_failure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;initial_interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 5s
      &lt;span class=&quot;token key atrule&quot;&gt;max_interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30s
      &lt;span class=&quot;token key atrule&quot;&gt;max_elapsed_time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 10m &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Sending queue (persisted on disk) + batching&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;sending_queue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;storage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; file_storage
      &lt;span class=&quot;token key atrule&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;infrastructure-as-code-and-monitoring&quot; tabindex=&quot;-1&quot;&gt;Infrastructure-as-Code and monitoring&lt;/h3&gt;
&lt;p&gt;As you need to release and manage a fleet of observability agents, you should use infrastructure as code. Assuming you already have an established IaC tool in place (if not, you have bigger problems to solve first!), use it to install, update, and configure your OpenTelemetry collectors. I&#39;ve successfully used Ansible to configure collectors on virtual machines. For Kubernetes environments, leverage whatever tooling you already have, whether that&#39;s Terraform, Helm, ArgoCD, or other solutions.&lt;/p&gt;
&lt;p&gt;Remember to automate dashboards and alerting configurations as well, not just the collectors themselves.&lt;/p&gt;
&lt;p&gt;You also need to monitor the collection infrastructure itself. The OpenTelemetry collector exports its own telemetry (logs and metrics), allowing to set up alerts for indicators like queue sizes, CPU and memory usage, and HTTP request duration. These metrics can help detect issues such as backpressure or stuck pipelines. The primitives are available, but you&#39;ll need to configure the monitoring yourself.&lt;/p&gt;
&lt;p&gt;There is also an emerging standard called OpAMP (Open Agent Management Protocol), which aims to provide centralized management for observability agent fleets, including monitoring, configuration, and automatic upgrades. OpAMP is implemented in the collector but not enabled by default. While there&#39;s an SDK available for building a server, you&#39;ll need to develop the server-side components yourself. I would approach OpAMP adoption cautiously at this stage.&lt;/p&gt;
&lt;h2 id=&quot;adoption-patterns&quot; tabindex=&quot;-1&quot;&gt;Part three: Adoption patterns&lt;/h2&gt;
&lt;p&gt;Let&#39;s talk about adoption patterns that have helped successful OpenTelemetry implementations in my experience. OTel has two primary approaches for collecting telemetry.&lt;/p&gt;
&lt;p&gt;The first is &lt;strong&gt;collecting existing telemetry&lt;/strong&gt;, which involves gathering telemetry already produced by existing systems or libraries through collector integrations. This approach requires no code changes and is particularly helpful for integrating third-party environments or legacy systems.&lt;/p&gt;
&lt;p&gt;The second is &lt;strong&gt;native instrumentation&lt;/strong&gt;, which means adding the OpenTelemetry SDK directly into application code to generate custom traces, metrics, and logs that flow directly to the collector. This approach also offers zero-code auto-instrumentation options that require no manual code changes. While more complex initially, native instrumentation provides better return on investment in the medium term.&lt;/p&gt;
&lt;h3 id=&quot;a-possible-approach&quot; tabindex=&quot;-1&quot;&gt;A Possible Approach&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step 1: Build the collection infrastructure and collect existing telemetry.&lt;/strong&gt; This approach provides quick coverage across many services and works well for legacy applications or third-party software where code changes aren&#39;t feasible. The main limitations are that structured logs typically require parsing, and achieving proper correlation between telemetry signals can be challenging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step 2: Add native instrumentation using zero-code auto-instrumentation.&lt;/strong&gt; This step leverages the automatic instrumentation capabilities built into language runtimes and popular libraries, providing better telemetry without requiring code modifications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Step 3: Implement code-based native instrumentation.&lt;/strong&gt; This requires modifying application code but enables first-class correlation using &lt;code&gt;span_id&lt;/code&gt; and &lt;code&gt;trace_id&lt;/code&gt;, makes it easier to adopt semantics conventions, and delivers the best long-term return of investment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This phased approach is designed for organizations with existing applications and infrastructure. When starting from scratch, you can be more aggressive and jump directly to native instrumentation from the beginning.&lt;/p&gt;
&lt;h3 id=&quot;collect-existing-telemetry-in-virtual-machines&quot; tabindex=&quot;-1&quot;&gt;Collect existing telemetry in virtual machines&lt;/h3&gt;
&lt;p&gt;The OpenTelemetry collector can be deployed using infrastructure as code on VMs, typically as a &lt;code&gt;systemd&lt;/code&gt; service, or in a container where appropriate. Once deployed, you can collect local log files using the &lt;code&gt;filelog&lt;/code&gt; receiver to parse plain text logs. In this configuration, it is possible to extract fields like timestamp and severity, encoding them according to the OpenTelemetry protocol semantic. Custom field mappings are also available.&lt;/p&gt;
&lt;p&gt;For example, for the following text log:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;2023-06-19 05:20:50 ERROR This is a test error message
2023-06-20 12:50:00 DEBUG This is a test debug message&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;it is possible to use the following collector configuration:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# config.yaml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;receivers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;filelog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; /var/log/myservice/&lt;span class=&quot;token important&quot;&gt;*.log&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;operators&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; regex_parser
        &lt;span class=&quot;token key atrule&quot;&gt;regex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;^(?P&amp;lt;time&gt;&#92;d{4}-&#92;d{2}-&#92;d{2} &#92;d{2}:&#92;d{2}:&#92;d{2}) (?P&amp;lt;sev&gt;[A-Z]*) (?P&amp;lt;msg&gt;.*)$&#39;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;parse_from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; attributes.time
          &lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%Y-%m-%d %H:%M:%S&#39;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;parse_from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; attributes.sev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A similar approach works for JSON log files:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-09-28 20:15:12&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;INFO&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;User logged in successfully&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;u-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;source_ip&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;192.168.1.100&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2025-09-28 20:15:45&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WARN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Password nearing expiration&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;u-123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# config.yaml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;receivers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;filelog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; /var/log/myservice/&lt;span class=&quot;token important&quot;&gt;*.log&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;operators&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; json_parser
        &lt;span class=&quot;token key atrule&quot;&gt;timestamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;parse_from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; attributes.time
          &lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;%Y-%m-%d %H:%M:%S&#39;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;parse_from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; attributes.level&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On Windows, the &lt;code&gt;windowseventslog&lt;/code&gt; receiver collects system logs. On all operating systems, the &lt;code&gt;hostmetrics&lt;/code&gt; receiver gathers VM-level metrics. The following example also demonstrates using a processor to enrich telemetry with additional metadata. Other versions of that processor exist to get metadata for virtual machines in cloud providers.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# config.yaml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;receivers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;windowseventlog/application&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; application
  &lt;span class=&quot;token key atrule&quot;&gt;windowseventlog/system&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token key atrule&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; system

  &lt;span class=&quot;token key atrule&quot;&gt;hostmetrics/all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;collection_interval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 30s
    &lt;span class=&quot;token key atrule&quot;&gt;scrapers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;memory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;filesystem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;


&lt;span class=&quot;token key atrule&quot;&gt;processors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;resourcedetection/system&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;detectors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;system&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;hostname_sources&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;os&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dns&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lookup&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;collect-existing-telemetry-from-kubernetes&quot; tabindex=&quot;-1&quot;&gt;Collect existing telemetry from Kubernetes&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/kube.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;OpenTelemetry provides  tooling for Kubernetes, available as a Helm chart or operator (though I haven&#39;t tested the operator yet). The documentation could be more comprehensive, but the package is generally well done, consisting of two main components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first is a per-node collector deployed as a DaemonSet, which collects container logs and metrics about CPU and memory usage at the container level.&lt;/li&gt;
&lt;li&gt;The second is a per-cluster collector that uses Kubernetes APIs to gather cluster-wide data such as events, resource requests, and other cluster metrics.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A processor is included to enrich messages with metadata to provide context and filtering capabilities.&lt;/p&gt;
&lt;h3 id=&quot;native-instrumentation%3A-zero-code&quot; tabindex=&quot;-1&quot;&gt;Native instrumentation: Zero-code&lt;/h3&gt;
&lt;p&gt;OpenTelemetry zero-code instrumentation (also called auto-instrumentation) automatically captures telemetry data from applications without requiring manual code modifications. The implementation mechanism varies by language and depends on whether the components and libraries you&#39;re using are already supported, so coverage can vary significantly. Currently, auto-instrumentation is available for a subset of languages: .NET, Go, Java, JavaScript, PHP, and Python.&lt;/p&gt;
&lt;p&gt;For example, adding auto-instrumentation to a basic Node.js Express application looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--save&lt;/span&gt; @opentelemetry/api
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--save&lt;/span&gt; @opentelemetry/auto-instrumentations-node

&lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;OTEL_TRACES_EXPORTER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;otlp &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token assign-left variable&quot;&gt;OTEL_SERVICE_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;my-service &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--require&lt;/span&gt; @opentelemetry/auto-instrumentations-node/register app.js&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; express &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;express&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;express&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Listening for requests on http://localhost:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces a trace containing spans generated by both the Express web framework and the Node.js HTTP module. The trace also demonstrates context propagation, with the trace ID being carried across the entire request flow. The following is an excerpt of the generated trace:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;info Traces &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;resource&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;. &lt;span class=&quot;token string&quot;&gt;&quot;service.name&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;my-service&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;resource spans&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;spans&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Resource attributes:
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; host.name: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d01.fornasa.it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; host.arch: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;amd64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; host.id: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;002878404e9747208b6ca9cebc484f92&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; process.pid: Int&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;518406&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; service.name: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;my_app&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; telemetry.sdk.language: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nodejs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; telemetry.sdk.name: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;opentelemetry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; telemetry.sdk.version: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2.1&lt;/span&gt;.0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

ScopeSpans &lt;span class=&quot;token comment&quot;&gt;#0&lt;/span&gt;
ScopeSpans SchemaURL:
InstrumentationScope @opentelemetry/instrumentation-express &lt;span class=&quot;token number&quot;&gt;0.54&lt;/span&gt;.0

Span &lt;span class=&quot;token comment&quot;&gt;#0&lt;/span&gt;
Trace ID       &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; fa24cb81e96176b5614efce4ccf22e89
Parent ID      &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 7350ff8549ac0451
ID             &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 50a309fa91fa761b
Name           &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; request handler - /test
Kind           &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Internal
Start &lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;     &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2025&lt;/span&gt;-10-21 &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;:53:48.282 +0000 UTC
End &lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;       &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2025&lt;/span&gt;-10-21 &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;:53:48.284842068 +0000 UTC
Status code    &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Unset
Status message &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;
Attributes:
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.route: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/test&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; express.name: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/test&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; express.type: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request_handler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

ScopeSpans &lt;span class=&quot;token comment&quot;&gt;#1&lt;/span&gt;
ScopeSpans SchemaURL:
InstrumentationScope @opentelemetry/instrumentation-http &lt;span class=&quot;token number&quot;&gt;0.205&lt;/span&gt;.0

Span &lt;span class=&quot;token comment&quot;&gt;#0&lt;/span&gt;
Trace ID       &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; fa24cb81e96176b5614efce4ccf22e89
Parent ID      &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;
ID             &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 7350ff8549ac0451
Name           &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; GET /test
Kind           &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Server
Start &lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;     &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2025&lt;/span&gt;-10-21 &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;:53:48.28 +0000 UTC
End &lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;       &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2025&lt;/span&gt;-10-21 &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;:53:48.285022049 +0000 UTC
Attributes:
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.url: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;http://localhost:8000/test&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.host: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;localhost:8000&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.method: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;GET&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.status_code: Int&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.status_text: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; http.route: Str&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/test&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The trace can then be sent to a visualization backend (in this case, Clickstack).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/trace1.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Node.Js Redis client is also instrumented:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; redis &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;redis&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; redisClient &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; redis&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
redisClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; redisClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;some_key&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So a Redis call will generate a span, and context propagation will work out of the box&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/trace3.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;Organizations may benefit from developing boilerplate code to configure automatic instrumentation. Given that this configuration is typically consistent across teams, packaging it as a maintained internal library is often the most effective distribution method.&lt;/p&gt;
&lt;p&gt;In the following example, an additional HTTP header is added to the SDK output.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NodeSDK &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@opentelemetry/sdk-node&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getNodeAutoInstrumentations &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@opentelemetry/auto-instrumentations-node&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ConsoleSpanExporter &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@opentelemetry/sdk-trace-node&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; OTLPTraceExporter &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@opentelemetry/exporter-trace-otlp-proto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; OTLPMetricExporter &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@opentelemetry/exporter-metrics-otlp-proto&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; PeriodicExportingMetricReader &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@opentelemetry/sdk-metrics&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sdk &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodeSDK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;traceExporter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OTLPTraceExporter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;http://localhost:4318/v1/traces&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;authorization&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;secret&#39;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;instrumentations&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getNodeAutoInstrumentations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

sdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;native-instrumentation%3A-code-based&quot; tabindex=&quot;-1&quot;&gt;Native instrumentation: Code-based&lt;/h3&gt;
&lt;p&gt;Once both the collection infrastructure and automatic instrumentation are set up, it&#39;s straightforward to enhance telemetry by adding explicit calls. Building on the previous example, I can add spans for three actions (&lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;C&lt;/code&gt;). In JavaScript this works out as follows:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startActiveSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;taskA&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;taskA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startActiveSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;taskB&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;taskB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; tracer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startActiveSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;taskC&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;taskC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in the following trace, where we can see that the context propagation is maintained for the additional spans:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://fornasa.it/img/posts/opentelemetry-incremental-adoption-strategies/trace2.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;fostering-adoption&quot; tabindex=&quot;-1&quot;&gt;Fostering adoption&lt;/h2&gt;
&lt;p&gt;In conclusion, here are some key aspects that are in my opinion crucial in order to foster adoption.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;make sure that developers have easy access to observability consoles&lt;/strong&gt;, &lt;strong&gt;especially for production&lt;/strong&gt;! This seems rather obvious, but this access is surprisingly often blocked or complicated by technical and organizational hurdles.&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;start with automatic instrumentation&lt;/strong&gt;, as it can help get things moving.&lt;/p&gt;
&lt;p&gt;Third, &lt;strong&gt;create internal wrappers&lt;/strong&gt; to abstract OpenTelemetry complexities and ease adoption. Ideally, these should be one-line imports for the most commonly used languages and frameworks.&lt;/p&gt;
&lt;p&gt;Fourth, &lt;strong&gt;develop adapters&lt;/strong&gt; (compatibility layers) for existing instrumentation to convert from current telemetry sources. These adapters must have clear ownership and be actively maintained.&lt;/p&gt;
&lt;p&gt;Finally, consider a &lt;strong&gt;transition period&lt;/strong&gt; with parallel operations, where teams write to both the old and new observability systems.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Migrating from Ingress NGINX to Envoy Gateway: Handling cert-manager integration</title>
    <link href="https://fornasa.it/posts/migrating-ingress-nginx-to-envoy-gateway/" />
    <updated>2025-12-05T00:00:00Z</updated>
    <id>https://fornasa.it/posts/migrating-ingress-nginx-to-envoy-gateway/</id>
    <content type="html">&lt;p&gt;The recent &lt;a href=&quot;https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/&quot;&gt;retirement&lt;/a&gt; of Ingress NGINX led a lot of people (including myself) to consider alternatives. Since we need to migrate anyway, it makes sense to migrate to the newer &lt;a href=&quot;https://gateway-api.sigs.k8s.io/&quot;&gt;Gateway API&lt;/a&gt;, the replacement for the older Ingress API.
This post focuses specifically on migrating TLS certificate management with cert-manager when moving from Ingress NGINX to Envoy Gateway using the Kubernetes Gateway API.&lt;/p&gt;
&lt;p&gt;The Ingress API&#39;s limited expressiveness led to a bunch of non-standard annotations, which were clearly suboptimal and definitely not portable.
It &lt;a href=&quot;https://gateway-api.sigs.k8s.io/guides/migrating-from-ingress/&quot;&gt;turns out&lt;/a&gt; that one of the defining features of Gateway API is the attention to RBAC and multitenancy, by splitting responsibilities that in the Ingress API were more blurred. This allows for more sophisticated RBAC setups, which can accommodate a wider range of organizational complexity.&lt;/p&gt;
&lt;p&gt;For organizations using cert-manager with Ingress NGINX to automate TLS certificates from Let&#39;s Encrypt, this migration has important implications. The Gateway API fundamentally changes how TLS is configured and managed, requiring a rethink of cert-manager integration strategies.&lt;/p&gt;
&lt;p&gt;For this migration, I am using &lt;a href=&quot;https://gateway.envoyproxy.io/&quot;&gt;Envoy Gateway&lt;/a&gt;, an implementation of the Gateway API based on Envoy.&lt;/p&gt;
&lt;h2 id=&quot;scenario-1%3A-using-static-certificates&quot; tabindex=&quot;-1&quot;&gt;Scenario 1: Using static certificates&lt;/h2&gt;
&lt;p&gt;Before moving to cert-manager, let&#39;s look at using static certificates in a Gateway API setting. The TLS setup in Gateway API is done at the &lt;code&gt;Gateway&lt;/code&gt; level, which is the component intended to be managed by cluster operators.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Gateway&lt;/code&gt; object is usually paired to a Load Balancer, either by using a &lt;code&gt;LoadBalancer&lt;/code&gt; type service, using a &lt;code&gt;NodePort&lt;/code&gt; which is then linked to an external load balancer, or by other implementation-specific mechanisms. All of those mechanisms can incur costs and generate complexity, so there&#39;s often a single central &lt;code&gt;Gateway&lt;/code&gt; for the entire cluster.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.networking.k8s.io/v1
&lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Gateway
&lt;span class=&quot;token key atrule&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; test&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gateway
  &lt;span class=&quot;token key atrule&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; default
&lt;span class=&quot;token key atrule&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;gatewayClassName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; test
  &lt;span class=&quot;token key atrule&quot;&gt;listeners&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; http
    &lt;span class=&quot;token key atrule&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; HTTP
    &lt;span class=&quot;token key atrule&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;example.com&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;allowedRoutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;namespaces&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; All &lt;span class=&quot;token comment&quot;&gt;# Restrict this&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https
    &lt;span class=&quot;token key atrule&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; HTTPS
    &lt;span class=&quot;token key atrule&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;example.com&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;allowedRoutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;namespaces&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; All &lt;span class=&quot;token comment&quot;&gt;# Restrict this&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;tls&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Terminate
      &lt;span class=&quot;token key atrule&quot;&gt;certificateRefs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Secret
        &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; example&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand, services to be exposed are defined at the application level using an &lt;code&gt;HTTPRoute&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.networking.k8s.io/v1
&lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; HTTPRoute
&lt;span class=&quot;token key atrule&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; app
  &lt;span class=&quot;token key atrule&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; app
&lt;span class=&quot;token key atrule&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;parentRefs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; test&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gateway
    &lt;span class=&quot;token key atrule&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; default
    &lt;span class=&quot;token key atrule&quot;&gt;sectionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https
  &lt;span class=&quot;token key atrule&quot;&gt;hostnames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; example.com
  &lt;span class=&quot;token key atrule&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; PathPrefix
        &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /
    &lt;span class=&quot;token key atrule&quot;&gt;backendRefs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; app
      &lt;span class=&quot;token key atrule&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main difference that stands out compared to legacy &lt;code&gt;Ingress&lt;/code&gt; is that the hostnames are specified twice: at the &lt;code&gt;Gateway&lt;/code&gt; level (which also handles TLS) and at the &lt;code&gt;HTTPRoute&lt;/code&gt; level, to attach the route to the gateway.&lt;/p&gt;
&lt;h2 id=&quot;scenario-2%3A-using-cert-manager&quot; tabindex=&quot;-1&quot;&gt;Scenario 2: Using cert-manager&lt;/h2&gt;
&lt;p&gt;cert-manager supports the Gateway API and can obtain certificates from Let&#39;s Encrypt (and other certificate issuers). Since TLS is managed at the &lt;code&gt;Gateway&lt;/code&gt; level, cert-manager also integrates at the Gateway level. It is activated using an annotation:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.networking.k8s.io/v1
&lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Gateway
&lt;span class=&quot;token key atrule&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;annotations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; letsencrypt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;prod
&lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;cert-manager looks at the hostnames in the Gateway to request certificates from Let&#39;s Encrypt. The certificate secrets will be populated by cert-manager after the issuing process completes successfully.&lt;/p&gt;
&lt;p&gt;This approach works, but it does not allow self-service provisioning of TLS certificates by application teams, something that was possible with Ingress (although with questionable security, as one application could intercept traffic intended for another). This centralized approach does not scale well in mid-sized organizations using a central Gateway, as every new domain requires cluster operator intervention.&lt;/p&gt;
&lt;p&gt;One alternative would be for each application team to own its own Gateway, but this introduces cost and complexity from setting up dedicated load balancers, public IPs, and additional infrastructure. Currently, the Gateway API does not support a better model for self-service certificate operations.&lt;/p&gt;
&lt;p&gt;In the following sections we will explore a non-standard approach available in Envoy Gateway and a proposed feature that will extend the self-service model to standard Gateway API.&lt;/p&gt;
&lt;h2 id=&quot;scenario-3%3A-self-service-certificates-using-multiple-gateways-and-envoy-gateway-merged-deployments&quot; tabindex=&quot;-1&quot;&gt;Scenario 3: Self-service certificates using multiple Gateways and Envoy Gateway merged deployments&lt;/h2&gt;
&lt;p&gt;One way to implement self-service is to use multiple Gateways, one per application. However, this typically multiplies infrastructure resources (like load balancers) and associated complexity and cost. Envoy Gateway offers a non-standard approach to solve this: the &lt;a href=&quot;https://gateway.envoyproxy.io/docs/tasks/operations/deployment-mode/#merged-gateways-deployment&quot;&gt;merged gateway&lt;/a&gt; deployment mode. Using a custom configuration object, it is possible to serve all Gateways belonging to the same class from a single load balancer:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Custom configuration&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.envoyproxy.io/v1alpha1
&lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; EnvoyProxy
&lt;span class=&quot;token key atrule&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; merged&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;eg
  &lt;span class=&quot;token key atrule&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; envoy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gateway&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;system
&lt;span class=&quot;token key atrule&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;mergeGateways&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.networking.k8s.io/v1
&lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; GatewayClass
&lt;span class=&quot;token key atrule&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; test
&lt;span class=&quot;token key atrule&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;controllerName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.envoyproxy.io/gatewayclass&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;controller
  &lt;span class=&quot;token comment&quot;&gt;# Reference to custom configuration&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;parametersRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gateway.envoyproxy.io
    &lt;span class=&quot;token key atrule&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; EnvoyProxy
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; merged&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;eg
    &lt;span class=&quot;token key atrule&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; envoy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gateway&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;system&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main limitation is that hostnames cannot be shared between different application teams. This could be problematic in some scenarios: For example, when one application serves &lt;code&gt;example.com/app1&lt;/code&gt; and another serves &lt;code&gt;example.com/app2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This approach enables self-service TLS configuration by allowing application teams to manage their own &lt;code&gt;Gateway&lt;/code&gt; objects. However, this is a non-standard approach specific to Envoy Gateway.&lt;/p&gt;
&lt;h2 id=&quot;scenario-4%3A-self-service-using-cert-manager-(not-yet-available)&quot; tabindex=&quot;-1&quot;&gt;Scenario 4: Self-service using cert-manager (not yet available)&lt;/h2&gt;
&lt;p&gt;An &lt;a href=&quot;https://gateway-api.sigs.k8s.io/geps/gep-1713/&quot;&gt;ongoing effort&lt;/a&gt; is underway to introduce a new feature to the Gateway API called &lt;code&gt;ListenerSet&lt;/code&gt;. A &lt;code&gt;ListenerSet&lt;/code&gt; will move hostname configuration outside the Gateway object, which in turn will allow delegating TLS certificate management to application teams in a secure way, thus enabling self-service TLS certificates.&lt;/p&gt;
&lt;p&gt;cert-manager &lt;a href=&quot;https://cert-manager.io/announcements/2025/11/26/ingress-nginx-eol-and-gateway-api/&quot;&gt;plans to support&lt;/a&gt; ListenerSets, with initial alpha support expected by January 2026. Stay tuned. I&#39;ll test it when it becomes available.&lt;/p&gt;
</content>
  </entry>
</feed>