Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capture tracing when a specific header is passed in an HTTP request #3660

Open
LeeHester opened this issue May 22, 2024 · 3 comments
Open

Capture tracing when a specific header is passed in an HTTP request #3660

LeeHester opened this issue May 22, 2024 · 3 comments

Comments

@LeeHester
Copy link

LeeHester commented May 22, 2024

We currently trace at a low sample rate (1%) in our web app. Sometimes, a trace would be really helpful in tracking down a problem for a specific user. I'd like to be able to add a special HTTP header (for example, "FORCE_DATADOG_TRACE" or something) to an HTTP request, have my rails app notice that, and trace that specific request, so that I can use the trace for debugging purposes. I tried doing this with a Rails middleware, like this:

(in config/application.rb)

  ...

  # This middleware checks for an HTTP header named "FORCE_DATADOG_TRACE", and
  # tells DataDog tracing to keep the trace for any request with this present.
  class ForceDataDogTraceMiddleware
    def initialize(app)
      @app = app
    end

    def call(env)
      if env["HTTP_FORCE_DATADOG_TRACE"]
        # Keeps the active trace
        Datadog::Tracing.keep!
      end
      @app.call(env)
    end
  end

  ...

  class Application < Rails::Application
    ...
    config.middleware.use ForceDataDogTraceMiddleware
    ...
  end

I debugged this locally and I see the Datadog::Tracing.keep! line of code is being executed when that header is passed, but I'm not getting those "forced" traces to show up in the DataDog UI. I'm not sure if this is because there is no active trace at the time, or if I'm just going down the wrong path here. Has anyone else tried to accomplish something similar?

@markedmondson
Copy link

We're doing something similar but closer to the controller...

    around_action do |controller, action|
      if params[:force_trace] == "true"
        Datadog::Tracing.trace("#{controller.class}##{params[:action]}") do |_span, trace|
          trace.keep!
          action.call
        end
      else
        action.call
      end
    end

This works on all except one application route (I ended up here because I'm trying to figure out why that one controller doesn't keep its traces!)

Hope this helps.

@LeeHester
Copy link
Author

Mark, that is super helpful, thanks for sharing!

@marcotc
Copy link
Member

marcotc commented Jul 23, 2024

👋, this is they're likely happening because when Datadog::Tracing.keep! is called, there's still no trace active:

active_trace.keep! if trace

In your original example, you can guarantee that the trace is created before choosing a sampling decision (keep!) like so:

def call(env)
  if env["HTTP_FORCE_DATADOG_TRACE"]
    # Keeps the active trace
    Tracing.continue_trace!(nil) do
      Datadog::Tracing.keep!
      @app.call(env)
    end
  else
    @app.call(env)
  end
end

This is the cleanest way in my opinion, and it doesn't require you to create a dummy span (Datadog::Tracing.trace("#{controller.class}##{params[:action]}")).

Let me know if this works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants