<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>article Manual Instrumentation with Splunk Observability Cloud: How to Instrument Backend Applications in Community Blog</title>
    <link>https://community.splunk.com/t5/Community-Blog/Manual-Instrumentation-with-Splunk-Observability-Cloud-How-to/ba-p/752186</link>
    <description>&lt;P&gt;Manual instrumentation is an invaluable observability tool. In this series, we dig into manual instrumentation to see how we can use it to easily build out observability from scratch. In our first post, &lt;A href="https://community.splunk.com/t5/Community-Blog/Manual-Instrumentation-with-Splunk-Observability-Cloud-The-What/ba-p/751816" target="_blank"&gt;Manual Instrumentation with Splunk Observability Cloud: The What and Why&lt;/A&gt;, we learned about what manual instrumentation is and why you need it. In this post, we'll look at a real, un-instrumented full-stack application and go step-by-step through the process of manually instrumenting its backend, commit by commit.&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;Preface: SDK-based Automatic Instrumentation&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;Before we jump in, we want to call out that while we will be using manual instrumentation to create custom telemetry data, we’ll also be using &lt;A href="https://opentelemetry.io/docs/languages/" target="_blank"&gt;OpenTelemetry’s SDK-based automatic instrumentation&lt;/A&gt; to hook into our web framework, HTTP requests, and database so we don’t have to manually create spans for framework operations.&amp;nbsp;&lt;/P&gt;&lt;P&gt;A true &lt;A href="https://help.splunk.com/en/splunk-observability-cloud/manage-data/available-data-sources/supported-integrations-in-splunk-observability-cloud/apm-instrumentation/instrumentation-methods" target="_blank"&gt;zero-code&lt;/A&gt; example of automatic instrumentation would require no code changes, but since zero-code auto-instrumentation doesn’t exist &lt;SPAN&gt;(yet) &lt;/SPAN&gt;for our application’s &lt;A href="https://elixir-lang.org/" target="_blank"&gt;Elixir&lt;/A&gt; backend, we’ll use SDK-based automatic instrumentation for framework operations and full manual instrumentation for our business logic instrumentation.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;Example Application Overview&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;GitHub repository: &lt;/STRONG&gt;&lt;A href="https://github.com/splunk/evangelism-public/tree/main/manual-instrumentation" target="_blank"&gt;https://github.com/splunk/evangelism-public/tree/main/manual-instrumentation&lt;/A&gt;&lt;/P&gt;&lt;P&gt;Our un-instrumented example application is called Worms in Space. It consists of a &lt;A href="https://react.dev/" target="_blank"&gt;React&lt;/A&gt; frontend with an Elixir backend and provides a full &lt;A href="https://graphql.org/" target="_blank"&gt;GraphQL&lt;/A&gt; API. Worms in Space allows customers (who happen to be worms) to schedule spacewalks in… space.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Space worms can use the UI or GraphQL API to:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;View available time slots&lt;/LI&gt;&lt;LI&gt;Schedule space walks during predefined or custom time slots&lt;/LI&gt;&lt;LI&gt;View all scheduled space walks&lt;/LI&gt;&lt;LI&gt;Cancel space walks&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Here’s what the frontend UI looks like:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_0-1756155301408.jpeg" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40066i8F8800A65AFEB791/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_0-1756155301408.jpeg" alt="CaitlinHalla_0-1756155301408.jpeg" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;And here you can interact with the GraphQL API via &lt;A href="https://github.com/graphql/graphiql/tree/main/packages/graphiql#readme" target="_blank"&gt;GraphiQL&lt;/A&gt;:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_1-1756155301410.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40065i62156F2FB7280FE9/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_1-1756155301410.png" alt="CaitlinHalla_1-1756155301410.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;If you'd like to follow along on GitHub commit-by-commit, check out the GitHub repository, otherwise, you can read on to follow each commit here.&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;Backend Instrumentation Implementation&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;Again, our example application is an Elixir backend with a GraphQL API for scheduling spacewalks. Even if you aren’t using Elixir or GraphQL, you can still use the following general steps as a guide to instrument your own backend application:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Add the necessary OpenTelemetry dependencies&lt;/LI&gt;&lt;LI&gt;Configure OpenTelemetry&lt;/LI&gt;&lt;LI&gt;Initialize instrumentation&lt;/LI&gt;&lt;LI&gt;Add custom telemetry data&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Let's walk through each of these steps commit-by-commit to instrument our Worms in Space backend.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;Step 1: Add OpenTelemetry Dependencies&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Git commit:&lt;/STRONG&gt; &lt;A href="https://github.com/splunk/evangelism-public/commit/5f926245" target="_blank"&gt;5f926245&lt;/A&gt;&lt;/P&gt;&lt;P&gt;The first thing we need to do within our backend application is add the OpenTelemetry dependencies to our dependency file, in our case our &lt;FONT face="andale mono,times"&gt;mix.exs&lt;/FONT&gt; file:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_2-1756155301412.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40064i52B7FE47C9496994/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_2-1756155301412.png" alt="CaitlinHalla_2-1756155301412.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;The list of dependencies can be found in the OpenTelemetry Language APIs &amp;amp; SDKs doc under the &lt;A href="https://opentelemetry.io/docs/languages/erlang/getting-started/#dependencies" target="_blank"&gt;Elixir/Erlang dependencies section&lt;/A&gt;. Since we’re using the core OpenTelemetry SDK, we’ll need to include OpenTelemetry, the OpenTelemetry API, and the OpenTelemetry exporter. Our Elixir application is using &lt;A href="https://www.phoenixframework.org/" target="_blank"&gt;Phoenix&lt;/A&gt; for HTTP requests, so to auto-instrument our controllers, plugs, and requests, we’ll need to include the OpenTelemetry dependency for Phoenix. Phoenix uses &lt;A href="https://github.com/ninenines/cowboy" target="_blank"&gt;Cowboy&lt;/A&gt; as its default HTTP server, so we’ll also include the OpenTelemetry Cowboy dependency so we can low-level HTTP requests. Our application uses &lt;A href="https://github.com/elixir-ecto/ecto" target="_blank"&gt;Ecto&lt;/A&gt; for database interactions, so we’ll include the OpenTelemetry Ecto dependency, and then &amp;nbsp;GraphQL operations in Elixir are resolved via &lt;A href="https://github.com/absinthe-graphql/absinthe" target="_blank"&gt;Absinthe&lt;/A&gt;, so we’ll need the OpenTelemetry Absinthe dependency, as well. Finally, the &lt;A href="https://opentelemetry.io/docs/specs/otel/protocol/exporter/" target="_blank"&gt;OTLP exporter&lt;/A&gt; is required for sending telemetry data to Splunk Observability Cloud.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;Step 2: Configure OpenTelemetry SDK and OTLP Exporter&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Git commit:&lt;/STRONG&gt; &lt;A href="https://github.com/splunk/evangelism-public/commit/e45ee707" target="_blank"&gt;e45ee707&lt;/A&gt;&lt;/P&gt;&lt;P&gt;Next, we configure the &lt;A href="https://opentelemetry.io/docs/languages/php/sdk/" target="_blank"&gt;OpenTelemetry SDK&lt;/A&gt; in our &lt;FONT face="andale mono,times"&gt;config/runtime.exs&lt;/FONT&gt; file:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_3-1756155301419.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40069i9FC8018641B1D042/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_3-1756155301419.png" alt="CaitlinHalla_3-1756155301419.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;This configuration establishes our service identity, sets up the batch processor for efficient trace export, and configures the OTLP exporter to send traces directly to Splunk Observability Cloud.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Note: &lt;/STRONG&gt;in this current configuration, we are directly sending out telemetry data to our Splunk Observability Cloud backend. In most cases, you would want to set up an &lt;A href="https://opentelemetry.io/docs/collector/" target="_blank"&gt;OpenTelemetry Collector&lt;/A&gt; to collect, process, and export telemetry data to your observability backend. In a subsequent post, we’ll look at how we can update our current configuration to use the OpenTelemetry Collector for increased resilience, flexibility, and processing capabilities.&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;Step 3: Initialize Instrumentation Components in Application&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Git commit:&lt;/STRONG&gt; &lt;A href="https://github.com/splunk/evangelism-public/commit/f7113fec" target="_blank"&gt;f7113fec&lt;/A&gt;&lt;/P&gt;&lt;P&gt;We next initialize the automatic instrumentations in our &lt;FONT face="andale mono,times"&gt;application.ex&lt;/FONT&gt; startup code:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_4-1756155301423.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40067i6E9C1D2019435AC9/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_4-1756155301423.png" alt="CaitlinHalla_4-1756155301423.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Notes on this setup:&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Cowboy Setup initializes the foundational HTTP server instrumentation&lt;/LI&gt;&lt;LI&gt;Phoenix Adapter setup ensures correct integration with Phoenix's HTTP server&lt;/LI&gt;&lt;LI&gt;Setup order matters. Initialize instrumentation libraries before your application starts accepting requests&lt;/LI&gt;&lt;LI&gt;Include logging to help verify configuration at startup&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;This setup initializes the dependencies referenced in the first commit in Step 1 and provides immediate visibility into HTTP requests, database queries, and GraphQL operations without any code changes. Every HTTP endpoint, database query, and resolver will automatically generate traces.&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;Step 4: Add Custom Spans for Business Logic&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Git commit:&lt;/STRONG&gt; &lt;A href="https://github.com/splunk/evangelism-public/commit/9278ef62" target="_blank"&gt;9278ef62&lt;/A&gt;&lt;/P&gt;&lt;P&gt;While SDK-based automatic instrumentation covers the framework layers, we need to add custom spans to capture our application’s unique business logic. We do this by setting attributes on specific spans within our create function heads in our &lt;FONT face="andale mono,times"&gt;resolvers.ex&lt;/FONT&gt; file so that every time a spacewalk is created, custom telemetry data with specified attributes is exported to Splunk Observability Cloud:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_5-1756155301426.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40068i152CA7A4C86483B0/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_5-1756155301426.png" alt="CaitlinHalla_5-1756155301426.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Note:&lt;/STRONG&gt; I’ve collapsed this method for brevity, but the full method and file can be viewed on GitHub in the &lt;A href="https://github.com/splunk/evangelism-public/blob/main/manual-instrumentation/worms_in_space/lib/worms_in_space_web/api/resolvers/resolvers.ex#L46" target="_blank"&gt;manual-instrumentation/worms_in_space/lib/worms_in_space_web/api/resolvers/resolvers.ex&lt;/A&gt; file.&lt;/P&gt;&lt;P&gt;These custom spans provide deep visibility into our spacewalk scheduling business logic, including success/failure rates, scheduling types, and performance metrics for critical operations. Some of the most common attributes to include in manual instrumentation are things like customer level or user ID and can be configured based on your unique business use-cases.&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;Environment Configuration&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;Finally, we set our environment variables for deployment flexibility:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_6-1756155301428.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40070i897370D8F913FCFC/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_6-1756155301428.png" alt="CaitlinHalla_6-1756155301428.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;This configuration allows seamless deployment across development, staging, and production environments while maintaining complete trace context and correlation.&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;What You'll See in Splunk Observability Cloud&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;With this instrumentation in place in just four commits, we immediately gain visibility into:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Complete request flows from HTTP request to database query with timing and status&lt;/LI&gt;&lt;LI&gt;GraphQL operation performance with query names and execution time&amp;nbsp;&amp;nbsp;&lt;/LI&gt;&lt;LI&gt;Database query analysis including SQL statements and execution time&lt;/LI&gt;&lt;LI&gt;Custom business metrics like the ones we added around spacewalks&lt;/LI&gt;&lt;LI&gt;Error tracking with full stack traces and contextual attributes&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Going into Splunk Observability Cloud, we can visit the service overview of our Worms in Space backend in &lt;A href="https://www.splunk.com/en_us/products/apm-application-performance-monitoring.html" target="_blank"&gt;Splunk Application Performance Monitoring&lt;/A&gt;. Here we can see valuable service metrics, &lt;A href="https://help.splunk.com/en/splunk-observability-cloud/monitor-application-performance/manage-services-spans-and-traces-in-splunk-apm/view-dependencies-among-your-services-in-the-service-map" target="_blank"&gt;Service Map&lt;/A&gt;, &lt;A href="https://help.splunk.com/en/splunk-observability-cloud/monitor-application-performance/analyze-services-with-span-tags-and-metricsets/analyze-service-performance-with-tag-spotlight" target="_blank"&gt;Tag Spotlight&lt;/A&gt;, errors, and traces:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_7-1756155301434.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40072i41F91D2FCFD506CF/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_7-1756155301434.png" alt="CaitlinHalla_7-1756155301434.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;If we open the traces from this view, we can see long running traces:&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_8-1756155301440.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40071i34B0B8CE80509690/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_8-1756155301440.png" alt="CaitlinHalla_8-1756155301440.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;We can open one of those long running traces, and then we can select a span to view the custom attributes that we manually instrumented earlier:&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="CaitlinHalla_9-1756155301446.png" style="width: 999px;"&gt;&lt;img src="https://community.splunk.com/t5/image/serverpage/image-id/40073iA93BB26515CADA98/image-size/large?v=v2&amp;amp;px=999" role="button" title="CaitlinHalla_9-1756155301446.png" alt="CaitlinHalla_9-1756155301446.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;Manual instrumentation success &lt;img class="lia-deferred-image lia-image-emoji" src="https://community.splunk.com/html/@65BA3226083A896B6028D25D1309E0A8/emoticons/1f389.png" alt=":party_popper:" title=":party_popper:" /&gt;.&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;Wrap Up&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;In just four commits, we've transformed our un-instrumented Elixir backend into a fully observable service. The combination of automatic instrumentation for framework operations and manual instrumentation via custom spans for business logic provides complete visibility into application performance and behavior.&lt;/P&gt;&lt;P&gt;When issues arise at 2 AM, we’ll now know exactly which spacewalk scheduling operation failed, how long database queries are taking, and whether the problem is in our business logic or our infrastructure. This level of observability transforms mysterious production issues into clearly diagnosed problems with obvious solutions so space worms can seamlessly schedule their spacewalks at any time.&lt;/P&gt;&lt;P&gt;Join us in our next post to follow along, step-by-step, as we manually instrument the &lt;SPAN&gt;React-powered &lt;/SPAN&gt;frontend of our Worms in Space &lt;SPAN&gt;application&lt;/SPAN&gt;.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Ready to &lt;SPAN&gt;add context to&lt;/SPAN&gt; your own backend&lt;SPAN&gt; apps&lt;/SPAN&gt;? Start with &lt;A href="https://opentelemetry.io/docs/languages/" target="_blank"&gt;OpenTelemetry's documentation on Language APIs and SDKs&lt;/A&gt;, and use &lt;A href="https://www.splunk.com/en_us/download/o11y-cloud-free-trial.html" target="_blank"&gt;Splunk Observability Cloud's 14-day free trial&lt;/A&gt; to easily visualize your telemetry data in one unified backend platform.&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;Resources&lt;/FONT&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;A href="https://community.splunk.com/t5/Community-Blog/Manual-Instrumentation-with-Splunk-Observability-Cloud-The-What/ba-p/751816" target="_blank"&gt;Manual Instrumentation with Splunk Observability Cloud: The What and Why&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;&lt;A href="https://help.splunk.com/en/splunk-observability-cloud/get-started/splunk-observability-cloud-overview/splunk-observability-cloud-overview" target="_blank"&gt;Splunk Observability Cloud Overview&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;&lt;A href="https://opentelemetry.io/docs/languages/" target="_blank"&gt;OpenTelemetry Language APIs &amp;amp; SDKs&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Thu, 28 Aug 2025 16:00:00 GMT</pubDate>
    <dc:creator>CaitlinHalla</dc:creator>
    <dc:date>2025-08-28T16:00:00Z</dc:date>
    <item>
      <title>Manual Instrumentation with Splunk Observability Cloud: How to Instrument Backend Applications</title>
      <link>https://community.splunk.com/t5/Community-Blog/Manual-Instrumentation-with-Splunk-Observability-Cloud-How-to/ba-p/752186</link>
      <description>&lt;P&gt;In this series, we're exploring manual instrumentation. We first looked at what manual instrumentation is and why you might use it.&lt;/P&gt;&lt;P&gt;In this post, we'll check out how we can implement manual instrumentation in the backend of our full-stack application. In just four commits, we'll take an un-instrumented code base from zero to full observability with OpenTelemetry and Splunk Observability Cloud.&lt;/P&gt;</description>
      <pubDate>Thu, 28 Aug 2025 16:00:00 GMT</pubDate>
      <guid>https://community.splunk.com/t5/Community-Blog/Manual-Instrumentation-with-Splunk-Observability-Cloud-How-to/ba-p/752186</guid>
      <dc:creator>CaitlinHalla</dc:creator>
      <dc:date>2025-08-28T16:00:00Z</dc:date>
    </item>
  </channel>
</rss>

