Search code examples
ruby-on-railstracedatadogfaradayapm

How to add Faraday request body into Datadog tracing in a Rails app


I'm trying to configure Faraday tracing in a Rails application using Datadog.

I've set up the Faraday -> Datadog connection:

require 'faraday'
require 'ddtrace'

Datadog.configure do |c|
  c.use :faraday
end

Faraday.post("http://httpstat.us/200", {foo: 1, bar: 2}.to_json)
Faraday.get("http://httpstat.us/201?foo=1&bar=2")

It works well, the requests are being logged to Datadog.

But those logs do not contain any request parameters, nevertheless GET or POST.

GET request log POST request log

Any adviсe on how to get the request params/body logged to Datadog?


Solution

  • So, by default the only things sent to Datadog from Faraday as part of the span in terms of the HTTP request are are:

          span.set_tag(Datadog::Ext::HTTP::URL, env[:url].path)
          span.set_tag(Datadog::Ext::HTTP::METHOD, env[:method].to_s.upcase)
          span.set_tag(Datadog::Ext::NET::TARGET_HOST, env[:url].host)
          span.set_tag(Datadog::Ext::NET::TARGET_PORT, env[:url].port)
    

    Source: https://github.com/DataDog/dd-trace-rb/blob/e391d2eb64d3c6151a4bdd2710c6a8c7c1d57457/lib/ddtrace/contrib/faraday/middleware.rb#L54

    The body of the request is not set in the http part of the span by default, only the URL, HTTP method, host and port are.

    However, with manual instrumentation you can add anything you want to the span, so you could write an extension or monkey-patch to the Faraday middleware to add the body and parameters to the span:

    span.set_tag("http.body", env[:body])
    span.set_tag("http.params", env[:params])
    

    An example monkey patch:

    require 'faraday'
    require 'ddtrace'
    require 'ddtrace/contrib/faraday/middleware'
    
    module FaradayExtension
      private
      def annotate!(span, env, options)
        # monkey patch to add body to span
        span.set_tag("http.body", env[:body]) unless env[:body].to_s.strip.empty?
        span.set_tag("http.query", env[:url].query) if env[:url].query
        super
      end
    end
    
    Datadog::Contrib::Faraday::Middleware.prepend(FaradayExtension)
    
    Datadog.configure do |c|
      c.use :faraday
    end
    
    Faraday.post("http://httpstat.us/200", {foo: 1, bar: 2}.to_json)
    Faraday.get("http://httpstat.us/201?foo=1&bar=2")
    

    This worked for me in my testing:

    Post Get

    NB: I am a Datadog employee, but not on the engineering team, just wanted to be transparent!