<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Opentelemetry on ESG's</title><link>https://esg.dev/tags/opentelemetry/</link><description>Recent content in Opentelemetry on ESG's</description><generator>Hugo</generator><language>en-ca</language><lastBuildDate>Thu, 03 Sep 2026 12:35:00 -0400</lastBuildDate><atom:link href="https://esg.dev/tags/opentelemetry/index.xml" rel="self" type="application/rss+xml"/><item><title>Exporting OpenTelemetry to Google Cloud with .NET</title><link>https://esg.dev/posts/otlp-exporter-google-cloud-dotnet/</link><pubDate>Thu, 03 Sep 2026 12:35:00 -0400</pubDate><guid>https://esg.dev/posts/otlp-exporter-google-cloud-dotnet/</guid><description>&lt;p&gt;A while back, Google &lt;a href="https://cloud.google.com/blog/products/management-tools/opentelemetry-now-in-google-cloud-observability"&gt;Cloud Trace support for OpenTelemetry Protocol&lt;/a&gt;. This is great news, everyone should support OTLP!&lt;/p&gt;&#10;&lt;p&gt;There&amp;rsquo;s just one issue though. I happen to work with .NET, I could not find anything about it in their &lt;a href="https://docs.cloud.google.com/stackdriver/docs/instrumentation/migrate-to-otlp-endpoints"&gt;documentation&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;So here it is, how to use &lt;a href="https://www.nuget.org/packages/opentelemetry.exporter.opentelemetryprotocol/"&gt;OpenTelemetry.Exporter.OpenTelemetryProtocol&lt;/a&gt; to send traces to Google Cloud.&lt;/p&gt;&#10;&lt;h1 id="prerequisites"&gt;Prerequisites&lt;/h1&gt;&#10;&lt;p&gt;The documentation is already pretty clear on what permissions are needed, so I won&amp;rsquo;t go into that.&lt;/p&gt;&#10;&lt;p&gt;I will also assume that you know:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;How to setup credentials for your service, and that you&amp;rsquo;re already connecting to the platform&lt;/li&gt;&#10;&lt;li&gt;How to setup OpenTelemetry tracing in your application&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h1 id="step-by-step"&gt;Step by step&lt;/h1&gt;&#10;&lt;p&gt;Let&amp;rsquo;s start by making sure we have the required nuget packages:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Google.Apis.Auth&lt;/li&gt;&#10;&lt;li&gt;OpenTelemetry.Exporter.OpenTelemetryProtocol&lt;/li&gt;&#10;&lt;li&gt;OpenTelemetry.Instrumentation.AspNetCore&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Then, we need to setup resources for your service when adding OpenTelemetry to your service collection.&lt;/p&gt;&#10;&lt;p&gt;You will need at minimum:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;The name of your service&lt;/li&gt;&#10;&lt;li&gt;A GCP project ID where to send the traces&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;&#10; &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;&#10; &lt;/button&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.ConfigureResource(resource =&amp;gt; resource&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddService(serviceName: builder.Environment.ApplicationName) &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddAttributes([KeyValuePair.Create&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;object&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;gcp.project_id&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;YOUR PROJECT ID&amp;gt;&amp;#34;&lt;/span&gt;)]))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&lt;p&gt;Finally that, we setup the OTLP exporter, while connecting the Google Credential to set the proper &lt;code&gt;Authorization&lt;/code&gt; header. Use the &lt;code&gt;https://telemetry.googleapis.com&lt;/code&gt; endpoint, and create a DelegatingHandler from the Google credential instance.&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;&#10; &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;&#10; &lt;/button&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.AddOtlpExporter(options =&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.Endpoint = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(&lt;span style="color:#e6db74"&gt;&amp;#34;https://telemetry.googleapis.com&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// This should be the same for most folks&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.HttpClientFactory = () =&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClient(credential.ToDelegatingHandler(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClientHandler())); &lt;span style="color:#75715e"&gt;// A DelegatingHandler requires an inner handler, this is why we have a new HttpClientHandler.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s pretty much it!&lt;/p&gt;&#10;&lt;h1 id="putting-it-all-together"&gt;Putting it all together&lt;/h1&gt;&#10;&lt;p&gt;Here&amp;rsquo;s a complete example.&lt;/p&gt;&#10;&lt;div class="code-block"&gt;&#10; &lt;button class="code-copy" type="button" hidden aria-label="Copy code to clipboard"&gt;&#10; &lt;span class="code-copy-label" aria-hidden="true"&gt;Copy&lt;/span&gt;&#10; &lt;/button&gt;&#10; &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Google.Apis.Auth.OAuth2;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; Google.Apis.Http;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; OpenTelemetry.Resources;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; OpenTelemetry.Trace;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; builder = WebApplication.CreateBuilder(args);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; credential = GoogleCredential.GetApplicationDefault();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; scopedCredential = credential.CreateScoped(&lt;span style="color:#e6db74"&gt;&amp;#34;https://www.googleapis.com/auth/cloud-platform&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// Not purely required, but can be useful to limit the token scopes&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;builder.Services.AddOpenTelemetry()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .ConfigureResource(resource =&amp;gt; resource&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddService(serviceName: builder.Environment.ApplicationName) &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddAttributes([KeyValuePair.Create&amp;lt;&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;object&lt;/span&gt;&amp;gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;gcp.project_id&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;YOUR PROJECT ID&amp;gt;&amp;#34;&lt;/span&gt;)]))&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .WithTracing(tracing =&amp;gt; tracing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddAspNetCoreInstrumentation()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .AddOtlpExporter(options =&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.Endpoint = &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Uri(&lt;span style="color:#e6db74"&gt;&amp;#34;https://telemetry.googleapis.com&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options.HttpClientFactory = () =&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClient(scopedCredential.ToDelegatingHandler(&lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; HttpClientHandler()));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }));&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; app = builder.Build();&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.MapGet(&lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, () =&amp;gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt;);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app.Run();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#10; &lt;/div&gt;&lt;h1 id="troubleshooting"&gt;Troubleshooting&lt;/h1&gt;&#10;&lt;p&gt;Not seeing anything in Google Trace? Enable &lt;a href="https://opentelemetry.io/docs/languages/dotnet/troubleshooting/#self-diagnostics"&gt;OpenTelemetry diagnostics&lt;/a&gt;, the answer is likely in there.&lt;/p&gt;&#10;</description></item></channel></rss>