{"id":30309,"date":"2022-06-17T02:35:33","date_gmt":"2022-06-17T02:35:33","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=30309"},"modified":"2022-12-23T05:52:43","modified_gmt":"2022-12-23T05:52:43","slug":"datadog-setting-up-ecommerce-datadog-observability-katacoda-simplified-steps","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/datadog-setting-up-ecommerce-datadog-observability-katacoda-simplified-steps\/","title":{"rendered":"Datadog &#8211; Setting up Ecommerce Datadog Observability katacoda simplified steps"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\"><\/h4>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"spinning-up-our-legacy-e-commerce-shop\">Step 1 &#8211; Spinning Up Our Legacy E-Commerce Shop<\/h1>\n\n\n\n<p>Our legacy monolith shop uses Ruby on Rails and Spree. We&#8217;ve started to build out a first set of microservices, and these have been added to an initial set of containres.<\/p>\n\n\n\n<p>We use&nbsp;<code>docker-compose<\/code>&nbsp;to bring it up and running. There&#8217;s a prebuilt Rails Docker container image, along with the new Python \/ Flask microservice which handle our Coupon codes and Ads which display in the store.<\/p>\n\n\n\n<p>In this workshop, we&#8217;re going to spin up and instrument our application to see where things are broken, and next, find a few bottlenecks.<\/p>\n\n\n\n<p>We&#8217;ll focus on thinking through what observability might make sense in a real application, and see how setting up observability works in practice.<\/p>\n\n\n\n<p>Our application should be cloned from Github in this scenario, and if we change into the directory, we should be able to start the code with the following:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">$ cd \/ecommerce-observability\n$ POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres  docker-compose up<\/code><\/span><\/pre>\n\n\n<p>Once our images are pulled, we should be able to jump into and view the application within Katacoda:<\/p>\n\n\n\n<p><a href=\"https:\/\/2e652dae321844ddb7f22fd05609a510-167772165-3000-ollie02.environments.katacoda.com\/\" target=\"_blank\" rel=\"noopener\">https:\/\/2e652dae321844ddb7f22fd05609a510-167772165-3000-ollie02.environments.katacoda.com\/<\/a><\/p>\n\n\n\n<p>Try browsing around, and notice the homepage takes an especially long time to load.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.katacoda.com\/burningion\/scenarios\/ecommerce-observability\/assets\/ecommerce\/storedog.png\" alt=\"storedog\"\/><\/figure>\n\n\n\n<p>The first thing we&#8217;ll do is see where that slow load time may be coming from.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><\/h4>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"how-to-grok-an-application-with-datadog\">Step 2 &#8211; How to Grok an Application with Datadog<\/h1>\n\n\n\n<p>Whenever working with new code, it can be daunting to understand a system and how it all interacts together together.<\/p>\n\n\n\n<p>Our Datadog instrumentation allows us to get an immediate insight into what&#8217;s going on with the code.<\/p>\n\n\n\n<p>Let&#8217;s add the Datadog Agent to our&nbsp;<code>docker-compose.yml<\/code>, and begin instrumenting our application:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">  agent:\n    image: <span class=\"hljs-string\">\"datadog\/agent:6.13.0\"<\/span>\n    <span class=\"hljs-attr\">environment<\/span>:\n      - DD_API_KEY\n      - DD_APM_ENABLED=<span class=\"hljs-literal\">true<\/span>\n      - DD_LOGS_ENABLED=<span class=\"hljs-literal\">true<\/span>\n      - DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL=<span class=\"hljs-literal\">true<\/span>\n      - DD_PROCESS_AGENT_ENABLED=<span class=\"hljs-literal\">true<\/span>\n      - DD_TAGS=<span class=\"hljs-string\">'env:ruby-shop'<\/span>\n    <span class=\"hljs-attr\">ports<\/span>:\n      - <span class=\"hljs-string\">\"8126:8126\"<\/span>\n    <span class=\"hljs-attr\">volumes<\/span>:\n      - <span class=\"hljs-regexp\">\/var\/<\/span>run\/docker.sock:<span class=\"hljs-regexp\">\/var\/<\/span>run\/docker.sock:ro\n      - <span class=\"hljs-regexp\">\/proc\/<\/span>:<span class=\"hljs-regexp\">\/host\/<\/span>proc\/:ro\n      - <span class=\"hljs-regexp\">\/sys\/<\/span>fs\/cgroup\/:<span class=\"hljs-regexp\">\/host\/<\/span>sys\/fs\/cgroup:ro\n    <span class=\"hljs-attr\">labels<\/span>:\n      com.datadoghq.ad.logs: <span class=\"hljs-string\">'&#91;{\"source\": \"datadog-agent\", \"service\": \"agent\"}]'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With this, we&#8217;ve added volumes to see the resource usage on our host, along with the Docker socket so we can read the containers running on the host.<\/p>\n\n\n\n<p>We&#8217;ve also added a&nbsp;<code>DD_API_KEY<\/code>, along with enabling logs and the process Agent. Finally, we&#8217;ve opened the port&nbsp;<code>8126<\/code>, where traces get shipped to for collection at the Agent level.<\/p>\n\n\n\n<p>We can now rerun our application with our&nbsp;<code>DD_API_KEY<\/code>&nbsp;with the following command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$ <span class=\"hljs-keyword\">export<\/span> DD_API_KEY=<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">YOUR_API_KEY<\/span>&gt;<\/span>\n$ POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres docker-compose up<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And with that, we should start to see info coming in to Datadog.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><\/h4>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"apm-automatic-instrumentation-with-rails\">Step 3 &#8211; APM Automatic Instrumentation with Rails<\/h1>\n\n\n\n<p>Our code has already been set up with instrumentation from Datadog.<\/p>\n\n\n\n<p>Depending on the language your application runs in, you may have a different process for instrumenting your code. It&#8217;s best to look at the&nbsp;<a href=\"https:\/\/docs.datadoghq.com\/tracing\/setup\/\" rel=\"noreferrer noopener\" target=\"_blank\">documentation<\/a>&nbsp;for your specific language.<\/p>\n\n\n\n<p>In our case, our applications run on&nbsp;<a href=\"https:\/\/docs.datadoghq.com\/tracing\/setup\/ruby\/#rails\" rel=\"noreferrer noopener\" target=\"_blank\">Ruby on Rails<\/a>&nbsp;and Python&#8217;s&nbsp;<a href=\"http:\/\/pypi.datadoghq.com\/trace\/docs\/web_integrations.html#flask\" rel=\"noreferrer noopener\" target=\"_blank\">Flask<\/a>.<\/p>\n\n\n\n<p>We&#8217;ll instrument each language differently.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"installing-the-apm-language-library\">Installing the APM Language Library<\/h2>\n\n\n\n<p>For Ruby on Rails, we need to first add the&nbsp;<code>ddtrace<\/code>&nbsp;Gem to our Gemfile. Take a look at&nbsp;<code>store-frontend\/Gemfile<\/code>&nbsp;in the Katacoda file explorer, and notice we&#8217;ve added the Gem so we can start shipping traces.<\/p>\n\n\n\n<p>Because we plan on also consuming logs from Rails and correlating them with traces, we&#8217;ve also added&nbsp;<code>logging-rails<\/code>&nbsp;and&nbsp;<code>lograge<\/code>. Both of these are documented on the Ruby&nbsp;<a href=\"https:\/\/docs.datadoghq.com\/tracing\/setup\/ruby\/#for-logging-in-rails-applications-using-lograge-recommended\" rel=\"noreferrer noopener\" target=\"_blank\">trace \/ logs<\/a>&nbsp;correlation part of the documentation.<\/p>\n\n\n\n<p>Once these are both added to the list of our application&#8217;s requirements, we must then add a&nbsp;<code>datadog.rb<\/code>&nbsp;to the list of initializers.<\/p>\n\n\n\n<p>You&#8217;ll find the file in&nbsp;<code>store-frontend\/config\/initializers\/<\/code>.<\/p>\n\n\n\n<p>There, we control a few settings:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">Datadog.configure <span class=\"hljs-keyword\">do<\/span> |c|\n  <span class=\"hljs-comment\"># This will activate auto-instrumentation for Rails<\/span>\n  c.<span class=\"hljs-keyword\">use<\/span> :<span class=\"hljs-title\">rails<\/span>, {'<span class=\"hljs-title\">analytics_enabled<\/span>': <span class=\"hljs-title\">true<\/span>, '<span class=\"hljs-title\">service_name<\/span>': '<span class=\"hljs-title\">store<\/span>-<span class=\"hljs-title\">frontend<\/span>'}\n  # <span class=\"hljs-title\">Make<\/span> <span class=\"hljs-title\">sure<\/span> <span class=\"hljs-title\">requests<\/span> \n<span class=\"hljs-title\">are<\/span> <span class=\"hljs-title\">also<\/span> <span class=\"hljs-title\">instrumented<\/span>\n  <span class=\"hljs-title\">c<\/span>.<span class=\"hljs-title\">use<\/span> :<span class=\"hljs-title\">http<\/span>, {'<span class=\"hljs-title\">analytics_enabled<\/span>': <span class=\"hljs-title\">true<\/span>, '<span class=\"hljs-title\">service_name<\/span>': '<span class=\"hljs-title\">store<\/span>-<span class=\"hljs-title\">frontend<\/span>'}\n  <span class=\"hljs-title\">c<\/span>.<span class=\"hljs-title\">tracer<\/span> <span class=\"hljs-title\">hostname<\/span>: '<span class=\"hljs-title\">agent<\/span>'\n<span class=\"hljs-title\">end<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We set&nbsp;<code>analytics_enabled<\/code>&nbsp;to be&nbsp;<code>true<\/code>&nbsp;for both our Rails auto instrumentation, and the&nbsp;<code>http<\/code>&nbsp;instrumentation.<\/p>\n\n\n\n<p>This allows us to use Trace Search and Analytics from within Datadog.<\/p>\n\n\n\n<p>We then set a&nbsp;<code>hostname<\/code>&nbsp;for all our traces to be sent to. Because we set the Datadog Agent to listen on port&nbsp;<code>8126<\/code>, we set this to be the hostname available within our&nbsp;<code>docker-compose<\/code>.<\/p>\n\n\n\n<p>Finally, we set an environment for our traces. This allows us to separate different environments, for example, staging and production.<\/p>\n\n\n\n<p>With this, our Ruby application is instrumented. We&#8217;re also able to continue traces downstream, utilizing Distributed Traces.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"shipping-logs-correlated-with-traces\">Shipping Logs Correlated with Traces<\/h2>\n\n\n\n<p>To ship logs to Datadog, we&#8217;ve got to ensure they&#8217;re converted to JSON format. This allows for filtering by specific parameters within Datadog.<\/p>\n\n\n\n<p>Within our&nbsp;<code>config\/development.rb<\/code>, we see the specific code to ship our logs along with the correlating traces:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">  config.lograge.custom_options = lambda <span class=\"hljs-keyword\">do<\/span> |event|\n    <span class=\"hljs-comment\"># Retrieves trace information for current thread<\/span>\n    correlation = Datadog.tracer.active_correlation\n\n    {\n      <span class=\"hljs-comment\"># Adds IDs as tags to log output<\/span>\n      :dd =&gt; {\n        :trace_id =&gt; correlation.trace_id,\n        :span_id =&gt; correlation.span_id\n      },\n      :ddsource =&gt; &#91;<span class=\"hljs-string\">\"ruby\"<\/span>],\n      :params =&gt; event.payload&#91;:params].reject { |k| %w(controller action).<span class=\"hljs-keyword\">include<\/span>? k }\n    }\n  end<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next, let&#8217;s look at how a Python application is instrumented.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><\/h4>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"apm-automatic-instrumentation-with-python\">Step 4 &#8211; APM Automatic Instrumentation with Python<\/h1>\n\n\n\n<p>Now that we&#8217;ve set up our Ruby on Rails application, we can now instrument our downstream Python services.<\/p>\n\n\n\n<p>Looking at the&nbsp;<a href=\"http:\/\/pypi.datadoghq.com\/trace\/docs\/web_integrations.html#flask\" rel=\"noreferrer noopener\" target=\"_blank\">documentation<\/a>&nbsp;for the Python tracer, we have a utility called&nbsp;<code>ddtrace-run<\/code>.<\/p>\n\n\n\n<p>Wrapping our Python executable in a&nbsp;<code>ddtrace-run<\/code>&nbsp;allows us to spin up a running instance of our application fully instrumented with our tracer.<\/p>\n\n\n\n<p>For supported applications like Flask,&nbsp;<code>ddtrace-run<\/code>&nbsp;dramatically simplifies the process of instrumentation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"instrumenting-the-advertisements-service\">Instrumenting the Advertisements Service<\/h2>\n\n\n\n<p>In our&nbsp;<code>docker-compose.yml<\/code>&nbsp;there&#8217;s a command to bring up our Flask server. If we look, we&#8217;ll see it&#8217;s a:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">flask run --port=5002 --host=0.0.0.0<\/code><\/span><\/pre>\n\n\n<p>Once we install the Python&nbsp;<code>ddtrace<\/code>&nbsp;by adding it to our&nbsp;<code>requirements.txt<\/code>&nbsp;(it should already be there), we edit this command by putting a&nbsp;<code>ddtrace-run<\/code>&nbsp;in front:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">ddtrace-run flask run --port=5002 --host=0.0.0.0<\/code><\/span><\/pre>\n\n\n<p>With this, we&#8217;re ready to configure out application&#8217;s insturmentation.<\/p>\n\n\n\n<p>Automatic instrumentation is done via environment variables in our&nbsp;<code>docker-compose.yml<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">      - DATADOG_SERVICE_NAME=advertisements-service\n      - DATADOG_TRACE_AGENT_HOSTNAME=agent\n      - DD_LOGS_INJECTION=<span class=\"hljs-literal\">true<\/span>\n      - DD_ANALYTICS_ENABLED=<span class=\"hljs-literal\">true<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With this, we&#8217;ve connected and instrumented all of our services to APM.<\/p>\n\n\n\n<p>The last thing we need to add is a&nbsp;<em>label<\/em>&nbsp;to our container, so our logs are shipped with the label of the service, and with the proper language processor:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">    labels:\n      com.datadoghq.ad.logs: <span class=\"hljs-string\">'&#91;{\"source\": \"python\", \"service\": \"ads-service\"}]'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We can repeat the process, and fill out the settings for the&nbsp;<code>discounts-service<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">  discounts:\n    environment:\n      - FLASK_APP=discounts.py\n      - FLASK_DEBUG=<span class=\"hljs-number\">1<\/span>\n      - POSTGRES_PASSWORD\n      - POSTGRES_USER\n      - DATADOG_SERVICE_NAME=discounts-service\n      - DATADOG_TRACE_AGENT_HOSTNAME=agent\n      - DD_LOGS_INJECTION=<span class=\"hljs-literal\">true<\/span>\n      - DD_ANALYTICS_ENABLED=<span class=\"hljs-literal\">true<\/span>\n    <span class=\"hljs-attr\">image<\/span>: <span class=\"hljs-string\">\"burningion\/ecommerce-spree-discounts:latest\"<\/span>\n    <span class=\"hljs-attr\">command<\/span>: ddtrace-run flask run --port=<span class=\"hljs-number\">5001<\/span> --host=<span class=\"hljs-number\">0.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\n    <span class=\"hljs-attr\">ports<\/span>:\n      - <span class=\"hljs-string\">\"5001:5001\"<\/span>\n    <span class=\"hljs-attr\">volumes<\/span>:\n      - <span class=\"hljs-string\">\".\/discounts-service:\/app\"<\/span>\n    <span class=\"hljs-attr\">depends_on<\/span>:\n      - agent\n      - db\n    <span class=\"hljs-attr\">labels<\/span>:\n      com.datadoghq.ad.logs: <span class=\"hljs-string\">'&#91;{\"source\": \"python\", \"service\": \"discounts-service\"}]'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next, let&#8217;s take a closer look at\u00a0<em>why<\/em>\u00a0and\u00a0<em>where<\/em>\u00a0our application may be failing.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><\/h4>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"debugging-our-application-with-apm\">Step 5 &#8211; Debugging Our Application with APM<\/h1>\n\n\n\n<p>Now that we&#8217;ve instrumented all of our code, let&#8217;s spin up some traffic so we can get a better look at what may be happening.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"spinning-up-traffic-for-our-site\">Spinning up Traffic for Our Site<\/h2>\n\n\n\n<p>In our&nbsp;<code>\/ecommerce-observability<\/code>&nbsp;folder, we&#8217;ve got a copy of&nbsp;<a href=\"https:\/\/goreplay.org\/\" rel=\"noreferrer noopener\" target=\"_blank\">GoReplay<\/a>.<\/p>\n\n\n\n<p>We&#8217;ve also got a capture of traffic using GoReplay. Let&#8217;s spin up an infinite loop of that traffic:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">$ .\/gor --input-file-loop --input-file requests_0.gor --output-http <span class=\"hljs-string\">\"http:\/\/localhost:3000\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Once we spin up that traffic with our included observability, we can now take a look at the issues we&#8217;ve come across since the new team rolled out their first microservice, the&nbsp;<code>advertisements-service<\/code>.<\/p>\n\n\n\n<p>Before we began instrumenting with Datadog, there&#8217;d been reports that the new&nbsp;<code>advertisements-service<\/code>&nbsp;broke the website. With the new deployment on staging, the&nbsp;<code>frontend<\/code>&nbsp;team has blamed the&nbsp;<code>ads-service<\/code>&nbsp;team, and the&nbsp;<code>advertisements-service<\/code>&nbsp;team has blamed the ops team.<\/p>\n\n\n\n<p>Now that we&#8217;ve got Datadog and APM instrumented in our code, let&#8217;s see what&#8217;s really been breaking our application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"debugging-an-application-with-datadog\">Debugging an Application with Datadog<\/h2>\n\n\n\n<p>The first place we can check is the Service Map, to get an idea for our current infrastructure and microservice dependencies.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.katacoda.com\/burningion\/scenarios\/ecommerce-observability\/assets\/ecommerce\/service-map.png\" alt=\"Datadog Service Map\"\/><\/figure>\n\n\n\n<p>In doing so, we can tell that we&#8217;ve got two microservices that our frontend calls, a&nbsp;<code>discounts-service<\/code>, along with an&nbsp;<code>advertisements-service<\/code>.<\/p>\n\n\n\n<p>If we click in to view our Service Overview in Datadog, we can see that our API itself isn&#8217;t throwing any errors. The errors must be happening on the frontend.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.katacoda.com\/burningion\/scenarios\/ecommerce-observability\/assets\/ecommerce\/problematic-service.gif\" alt=\"Services List\"\/><\/figure>\n\n\n\n<p>So let&#8217;s take a look at the frontend service, and see if we can find the spot where things are breaking.<\/p>\n\n\n\n<p>If we look into the service, we can see that it&#8217;s been laid out by views. There&#8217;s at least one view that seems to only give errors. Let&#8217;s click into that view and see if a trace from that view can tell us what&#8217;s going on.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.katacoda.com\/burningion\/scenarios\/ecommerce-observability\/assets\/ecommerce\/500-trace-errors.gif\" alt=\"Problematic Traces\"\/><\/figure>\n\n\n\n<p>It seems the problem happens in a template. Let&#8217;s get rid of that part of the template so we can get the site back up and running while figuring out what happened.<\/p>\n\n\n\n<p>Open&nbsp;<code>store-frontend\/app\/views\/spree\/layouts\/spree_application.html.erb<\/code>&nbsp;and delete the line under&nbsp;<code>&lt;div class=\"container\"&gt;<\/code>. It should begin with a&nbsp;<code>&lt;br \/&gt;<\/code>&nbsp;and end with a&nbsp;<code>&lt;\/center&gt;<\/code>.<\/p>\n\n\n\n<p>The banner ads were meant to be put under&nbsp;<code>store-frontend\/app\/views\/spree\/products\/show.html.erb<\/code>&nbsp;and&nbsp;<code>store-frontend\/app\/views\/spree\/home\/index.html.erb<\/code>.<\/p>\n\n\n\n<p>For the&nbsp;<code>index.html.erb<\/code>, under&nbsp;<code>&lt;div data-hook=\"homepage_products\"&gt;<\/code>&nbsp;add the code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">center<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"&lt;%= @ads&#91;'url'] %&gt;\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"data:image\/png;base64,&lt;%= @ads&#91;'base64'] %&gt;\"<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">center<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And for the&nbsp;<code>show.html.erb<\/code>&nbsp;at the very bottom add:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">center<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"&lt;%= @ads&#91;'url'] %&gt;\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"data:image\/png;base64,&lt;%= @ads&#91;'base64'] %&gt;\"<\/span> \/&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">center<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With that, our project should be up and running. Let&#8217;s see if there&#8217;s anything else going on.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><\/h4>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"spotting-and-resolving-bottlenecks-with-the-service-list\">Step 6 &#8211; Spotting and Resolving Bottlenecks with the Service List<\/h1>\n\n\n\n<p>With the Service List, we can see at a quick glance see endpoints that are running slower than the rest.<\/p>\n\n\n\n<p>If we look at the Frontend Service, we can see there are two endpoints in particular that are substantially slower than the rest.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.katacoda.com\/burningion\/scenarios\/ecommerce-observability\/assets\/ecommerce\/bottleneck.gif\" alt=\"Slow Services\"\/><\/figure>\n\n\n\n<p>Both the&nbsp;<code>HomeController#index<\/code>&nbsp;and the&nbsp;<code>ProductController#show<\/code>&nbsp;enpoints are showing&nbsp;<em>much<\/em>&nbsp;longer latency times. If we click in, and view a trace, we&#8217;ll see that we&#8217;ve got downstream microservices taking up a substantial portion of our load time.<\/p>\n\n\n\n<p>Use the span list to see where it may be, and we can then take a look at each of the downstream services and where things may be going wrong.<\/p>\n\n\n\n<p>It seems two microservices in particular are being called for the homepage. If we look into our&nbsp;<code>docker-compose.yml<\/code>, we can see both the&nbsp;<code>advertisements-service<\/code>&nbsp;and&nbsp;<code>discounts-service<\/code>&nbsp;are each taking over 2.5 seconds for each request. Let&#8217;s look within their specific urls to see if there isn&#8217;t something amiss.<\/p>\n\n\n\n<p>Looking at the code, it appears we&#8217;ve accidentally left a line in from testing what happens if latency goes up.<\/p>\n\n\n\n<p>Try spotting the line and removing the code to see if you can bring the latency down again for the application.<\/p>\n\n\n\n<p>What sort of an improvement in page load time did it give you? Can you graph the differences over time?<\/p>\n\n\n\n<p>Reference<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>https:\/\/www.katacoda.com\/burningion\/scenarios\/ecommerce-observability<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Step 1 &#8211; Spinning Up Our Legacy E-Commerce Shop Our legacy monolith shop uses Ruby on Rails and Spree. We&#8217;ve started to build out a first set of microservices, and these have been added to an initial set of containres. We use&nbsp;docker-compose&nbsp;to bring it up and running. There&#8217;s a prebuilt Rails Docker container image, along&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-30309","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/30309","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=30309"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/30309\/revisions"}],"predecessor-version":[{"id":30310,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/30309\/revisions\/30310"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=30309"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=30309"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=30309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}