<?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: Modulis</title>
    <description>The latest articles on DEV Community by Modulis (@modulis).</description>
    <link>https://dev.to/modulis</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4225709%2F24670ac1-26b5-47e2-aa22-3c3999656a62.png</url>
      <title>DEV Community: Modulis</title>
      <link>https://dev.to/modulis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/modulis"/>
    <language>en</language>
    <item>
      <title>OpenTelemetry with Next.js, Node.js and Kubernetes: A Practical Production Setup</title>
      <dc:creator>Modulis</dc:creator>
      <pubDate>Thu, 05 Nov 2026 11:46:17 +0000</pubDate>
      <link>https://dev.to/modulis/opentelemetry-with-nextjs-nodejs-and-kubernetes-a-practical-production-setup-cl7</link>
      <guid>https://dev.to/modulis/opentelemetry-with-nextjs-nodejs-and-kubernetes-a-practical-production-setup-cl7</guid>
      <description>&lt;p&gt;When a production issue occurs, finding the actual cause can be harder than fixing it.&lt;/p&gt;

&lt;p&gt;A request might start in a Next.js frontend, pass through multiple Node.js services, hit a database, and eventually fail somewhere along the way.&lt;/p&gt;

&lt;p&gt;You might have logs in one place, traces in another, and error reports somewhere else.&lt;/p&gt;

&lt;p&gt;Without proper instrumentation and correlation, debugging becomes a manual exercise.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;OpenTelemetry (OTel)&lt;/strong&gt; becomes useful.&lt;/p&gt;

&lt;p&gt;OpenTelemetry provides a vendor-neutral way to collect traces, metrics, and logs from your applications. Once your applications are instrumented, you can change telemetry backends without rewriting your instrumentation.&lt;/p&gt;

&lt;p&gt;In this guide, we'll set up OpenTelemetry for a practical production stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js frontend&lt;/li&gt;
&lt;li&gt;Node.js / Express backend&lt;/li&gt;
&lt;li&gt;Distributed tracing&lt;/li&gt;
&lt;li&gt;Logs connected to traces&lt;/li&gt;
&lt;li&gt;Kubernetes OpenTelemetry Collector&lt;/li&gt;
&lt;li&gt;Filtering and sensitive-data scrubbing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you'll have a foundation for understanding what's happening across your services.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start with consistent service naming
&lt;/h2&gt;

&lt;p&gt;Before installing any packages, establish consistent naming across your services.&lt;/p&gt;

&lt;p&gt;OpenTelemetry uses resource attributes to describe which service is generating telemetry.&lt;/p&gt;

&lt;p&gt;Here are four attributes worth configuring:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;service.name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;checkout-api&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Identifies the service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;service.namespace&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;storefront&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Groups related services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;service.version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.42.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Connects errors with deployments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deployment.environment.name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;production&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Separates production and staging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Set these through environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OTEL_SERVICE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;checkout-api

&lt;span class="nv"&gt;OTEL_RESOURCE_ATTRIBUTES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;service.namespace&lt;span class="o"&gt;=&lt;/span&gt;storefront,service.version&lt;span class="o"&gt;=&lt;/span&gt;1.42.0,deployment.environment.name&lt;span class="o"&gt;=&lt;/span&gt;production

&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://otel-collector.observability.svc.cluster.local:4318

&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http/protobuf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A useful practice:&lt;/strong&gt; Set &lt;code&gt;service.version&lt;/code&gt; to your Git SHA or release tag through your CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;When an error starts appearing after a deployment, you'll have a much easier time connecting the incident to the relevant release.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Instrument your Next.js application
&lt;/h2&gt;

&lt;p&gt;Next.js supports OpenTelemetry through its instrumentation file.&lt;/p&gt;

&lt;p&gt;One straightforward approach is using &lt;code&gt;@vercel/otel&lt;/code&gt;. Despite the package name, it also works when running Next.js on your own infrastructure.&lt;/p&gt;

&lt;p&gt;Install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @vercel/otel @opentelemetry/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an &lt;code&gt;instrumentation.ts&lt;/code&gt; file in your project root (or inside &lt;code&gt;src/&lt;/code&gt; if your application uses that directory).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;registerOTel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vercel/otel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;registerOTel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OTEL_SERVICE_NAME&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides instrumentation for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incoming requests&lt;/li&gt;
&lt;li&gt;Server-side rendering&lt;/li&gt;
&lt;li&gt;Route handlers&lt;/li&gt;
&lt;li&gt;Server-side fetch calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exporter uses the standard &lt;code&gt;OTEL_EXPORTER_OTLP_*&lt;/code&gt; environment variables configured earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add custom spans
&lt;/h3&gt;

&lt;p&gt;Automatic instrumentation is useful, but sometimes you need additional context around specific business operations.&lt;/p&gt;

&lt;p&gt;For example, consider a recommendation service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tracer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web-frontend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getRecommendations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startActiveSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getRecommendations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app.recommendation.source&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ml-service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchRecommendations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recordException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="kd"&gt;as &lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a custom span around the operation and records exceptions when something goes wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Avoid adding sensitive or high-cardinality values such as raw user IDs to span attributes unless there is a justified reason and appropriate data handling.&lt;/p&gt;

&lt;p&gt;Also remember that server-side instrumentation and browser-side tracing are separate concerns. Edge runtime instrumentation has limitations, so consider your runtime requirements when designing the setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Instrument your Node.js / Express API
&lt;/h2&gt;

&lt;p&gt;For a Node.js service, the OpenTelemetry Node SDK and auto-instrumentation packages provide a practical starting point.&lt;/p&gt;

&lt;p&gt;They can automatically instrument supported libraries such as HTTP clients, Express, database clients, Redis and gRPC.&lt;/p&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  @opentelemetry/sdk-node &lt;span class="se"&gt;\&lt;/span&gt;
  @opentelemetry/api &lt;span class="se"&gt;\&lt;/span&gt;
  @opentelemetry/auto-instrumentations-node &lt;span class="se"&gt;\&lt;/span&gt;
  @opentelemetry/exporter-trace-otlp-http &lt;span class="se"&gt;\&lt;/span&gt;
  @opentelemetry/exporter-metrics-otlp-http &lt;span class="se"&gt;\&lt;/span&gt;
  @opentelemetry/sdk-metrics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an &lt;code&gt;instrumentation.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NodeSDK&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/sdk-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getNodeAutoInstrumentations&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/auto-instrumentations-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;OTLPTraceExporter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/exporter-trace-otlp-http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;OTLPMetricExporter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/exporter-metrics-otlp-http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;PeriodicExportingMetricReader&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/sdk-metrics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeSDK&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;traceExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OTLPTraceExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;

  &lt;span class="na"&gt;metricReader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PeriodicExportingMetricReader&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OTLPMetricExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;exportIntervalMillis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;

  &lt;span class="na"&gt;instrumentations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;getNodeAutoInstrumentations&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@opentelemetry/instrumentation-fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SIGTERM&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Load instrumentation before your application
&lt;/h3&gt;

&lt;p&gt;This is one of the most important implementation details.&lt;/p&gt;

&lt;p&gt;OpenTelemetry auto-instrumentation needs to initialize before the application modules load. Otherwise, it might not correctly hook into Express, database clients or other libraries.&lt;/p&gt;

&lt;p&gt;For a CommonJS application, start your service like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--require&lt;/span&gt; ./instrumentation.js server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "--require", "./instrumentation.js", "server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a zero-code approach, the auto-instrumentation package can also register itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--require&lt;/span&gt; @opentelemetry/auto-instrumentations-node/register server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using ES modules (&lt;code&gt;"type": "module"&lt;/code&gt;), check the OpenTelemetry JavaScript documentation for the appropriate ESM loader configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Connect logs with traces
&lt;/h2&gt;

&lt;p&gt;Collecting traces and logs independently is useful.&lt;/p&gt;

&lt;p&gt;Connecting them is much more powerful.&lt;/p&gt;

&lt;p&gt;Imagine an API request that takes several seconds to complete.&lt;/p&gt;

&lt;p&gt;Your trace tells you which operation was slow, but your application logs might contain the actual error or business context.&lt;/p&gt;

&lt;p&gt;The goal is to have every relevant log line carry the &lt;code&gt;trace_id&lt;/code&gt; of the request that generated it.&lt;/p&gt;

&lt;p&gt;For example, with Pino:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pino&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pino&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pino&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cartSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout started&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the appropriate OpenTelemetry log instrumentation and request context, the resulting log record can include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkout started"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cartSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4bf92f..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"span_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"00f067..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two practical ways to collect these logs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Continue writing logs to stdout and let a log collector, such as the OpenTelemetry Collector's &lt;code&gt;filelog&lt;/code&gt; receiver, collect them.&lt;/li&gt;
&lt;li&gt;Export logs directly through OTLP from the SDK.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Either approach can work.&lt;/p&gt;

&lt;p&gt;The important part is maintaining trace context so that you can move from a trace to its corresponding logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Deploy an OpenTelemetry Collector on Kubernetes
&lt;/h2&gt;

&lt;p&gt;Your applications can export telemetry directly to a backend.&lt;/p&gt;

&lt;p&gt;However, putting an OpenTelemetry Collector between your applications and the backend gives you much better control over the telemetry pipeline.&lt;/p&gt;

&lt;p&gt;A Collector allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter noisy health-check traffic.&lt;/li&gt;
&lt;li&gt;Remove sensitive attributes before export.&lt;/li&gt;
&lt;li&gt;Batch telemetry.&lt;/li&gt;
&lt;li&gt;Retry exports when a backend becomes temporarily unavailable.&lt;/li&gt;
&lt;li&gt;Change telemetry backends without modifying every application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Kubernetes deployments, you can use the OpenTelemetry Helm chart or OpenTelemetry Operator.&lt;/p&gt;

&lt;p&gt;The following is a starting configuration using the &lt;code&gt;otelcol-contrib&lt;/code&gt; distribution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Collector configuration
&lt;/h3&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;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;memory_limiter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;check_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1s&lt;/span&gt;
    &lt;span class="na"&gt;limit_percentage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
    &lt;span class="na"&gt;spike_limit_percentage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;

  &lt;span class="na"&gt;filter/healthchecks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;error_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ignore&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;span&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attributes["url.path"]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/healthz"'&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;attributes["url.path"]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"/readyz"'&lt;/span&gt;

  &lt;span class="na"&gt;attributes/scrub&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http.request.header.authorization&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http.request.header.cookie&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user.email&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hash&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;enduser.id&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hash&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;send_batch_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8192&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&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;otlphttp&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;https://YOUR-OTLP-BACKEND:4318&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;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="s"&gt;memory_limiter&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;filter/healthchecks&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;attributes/scrub&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;batch&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;otlphttp&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;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;memory_limiter&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;batch&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;otlphttp&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="s"&gt;memory_limiter&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;attributes/scrub&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;batch&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;otlphttp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the exporter endpoint with your actual backend endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this configuration matters
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Memory limiter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Helps protect the Collector from excessive memory usage. It should be placed early in each pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health-check filtering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Removes &lt;code&gt;/healthz&lt;/code&gt; and &lt;code&gt;/readyz&lt;/code&gt; spans from the trace pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sensitive-data scrubbing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Removes authorization and cookie headers and hashes selected user attributes before export.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch processing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Groups telemetry records before exporting them.&lt;/p&gt;

&lt;p&gt;One important consideration: filtering and scrubbing policies should be reviewed against your application's actual data and security requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional improvements
&lt;/h3&gt;

&lt;p&gt;Once the basic setup is working, consider adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tail sampling to retain important error and slow traces while sampling healthy traffic.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;k8sattributes&lt;/code&gt; processor to enrich telemetry with Kubernetes pod, namespace and deployment metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These additions can help make the telemetry pipeline more useful as your infrastructure grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Verify that your instrumentation works
&lt;/h2&gt;

&lt;p&gt;Don't assume that a running Collector means your instrumentation is correct.&lt;/p&gt;

&lt;p&gt;Generate some application traffic and check the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Every service appears with its actual &lt;code&gt;service.name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[ ] A request through Next.js and the API appears as one distributed trace.&lt;/li&gt;
&lt;li&gt;[ ] Log lines contain the same &lt;code&gt;trace_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[ ] Health-check spans are filtered out.&lt;/li&gt;
&lt;li&gt;[ ] Authorization headers and raw emails are not present in exported span attributes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common problems
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;What to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unknown_service&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Service name missing&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;OTEL_SERVICE_NAME&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No Express or database spans&lt;/td&gt;
&lt;td&gt;Instrumentation loaded too late&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;--require&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traces split between services&lt;/td&gt;
&lt;td&gt;Context propagation failure&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;traceparent&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increasing telemetry costs&lt;/td&gt;
&lt;td&gt;High-cardinality attributes&lt;/td&gt;
&lt;td&gt;Remove unnecessary IDs and full URLs from metric attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data missing during shutdown&lt;/td&gt;
&lt;td&gt;SDK not flushed&lt;/td&gt;
&lt;td&gt;Call &lt;code&gt;sdk.shutdown()&lt;/code&gt; on SIGTERM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collector restarts&lt;/td&gt;
&lt;td&gt;Memory pressure&lt;/td&gt;
&lt;td&gt;Configure &lt;code&gt;memory_limiter&lt;/code&gt; early in pipelines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If traces are breaking between services, check whether the outgoing request is using an instrumented client and whether an intermediate proxy is preserving the &lt;code&gt;traceparent&lt;/code&gt; header.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. What happens after OpenTelemetry is configured?
&lt;/h2&gt;

&lt;p&gt;At this point, you have established the telemetry foundation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your applications emit traces and metrics.&lt;/li&gt;
&lt;li&gt;Logs carry trace context.&lt;/li&gt;
&lt;li&gt;The Collector filters and processes telemetry.&lt;/li&gt;
&lt;li&gt;Sensitive attributes are handled before export.&lt;/li&gt;
&lt;li&gt;Your backend receives correlated signals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But collecting telemetry is only one part of production debugging.&lt;/p&gt;

&lt;p&gt;When an incident occurs, engineers still need to connect the relevant error, trace, logs, user session and deployment context to understand what actually happened.&lt;/p&gt;

&lt;p&gt;This is where having correlated engineering signals becomes valuable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting your OpenTelemetry setup to Modulis
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://modulis.ai" rel="noopener noreferrer"&gt;Modulis&lt;/a&gt; is an engineering intelligence and incident-resolution platform built on OpenTelemetry.&lt;/p&gt;

&lt;p&gt;It runs inside your own cloud and correlates production errors, traces, logs, session replays and Git metadata.&lt;/p&gt;

&lt;p&gt;Once your application is instrumented, you can connect your Collector to the Modulis OTLP endpoint provided during setup.&lt;/p&gt;

&lt;p&gt;Add the following resource attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OTEL_RESOURCE_ATTRIBUTES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;modulis.application&lt;span class="o"&gt;=&lt;/span&gt;storefront,service.namespace&lt;span class="o"&gt;=&lt;/span&gt;storefront,service.version&lt;span class="o"&gt;=&lt;/span&gt;1.42.0,deployment.environment.name&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;modulis.application&lt;/code&gt; isn't configured, Modulis falls back to &lt;code&gt;service.namespace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the telemetry connected, Modulis brings the related engineering context together. Its AI resolution workflow uses your own model key to identify likely root causes and open PR-ready fixes for your engineers to review and merge.&lt;/p&gt;

&lt;p&gt;The deployment runs in your own cloud, and AI resolution uses your own model key.&lt;/p&gt;

&lt;p&gt;You can explore the platform at &lt;a href="https://modulis.ai" rel="noopener noreferrer"&gt;modulis.ai&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry provides a solid foundation for understanding what happens across distributed applications.&lt;/p&gt;

&lt;p&gt;For teams running Next.js, Node.js and Kubernetes, a well-configured setup can make production debugging considerably more structured.&lt;/p&gt;

&lt;p&gt;Start with consistent resource attributes, instrument your applications, connect logs to traces, and introduce a Collector to control the telemetry pipeline.&lt;/p&gt;

&lt;p&gt;Most importantly, verify the entire request path instead of assuming that individual services are correctly instrumented.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collecting telemetry is the first step. Making it useful during an actual production incident is the real goal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Original implementation guide: &lt;a href="https://modulis.ai/blog/opentelemetry-nextjs-nodejs-setup-guide/" rel="noopener noreferrer"&gt;https://modulis.ai/blog/opentelemetry-nextjs-nodejs-setup-guide/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>devops</category>
      <category>kubernetes</category>
      <category>node</category>
    </item>
  </channel>
</rss>
