DataDog / browser-sdk

Datadog Browser SDK
Apache License 2.0
279 stars 130 forks source link

🙏 Configuring Datadog RUM Proxy Enviroment #2471

Open minJaebak opened 8 months ago

minJaebak commented 8 months ago

Hi

I'm trying to configure Datadog RUM Proxy, setting up the RUM SDK in a Vue.js application and configuring an Nginx proxy server to pass RUM data to Datadoghq. I've referred to the RUM Proxy Doc (https://docs.datadoghq.com/ko/real_user_monitoring/guide/proxy-rum-data/?tab=npm), but I'm unable to confirm session collection in the Datadog console.

Environment Setup:

Datadog RUM SDK version: 4.50.1 Nginx version: 1.25.0

export const datadogRumInit = {
      applicationId: import.meta.env.VITE_DATADOG_APPLICATION_ID,
      clientToken: import.meta.env.VITE_DATADOG_CLIENT_TOKEN,
      site: 'datadoghq.com',
      service: import.meta.env.VITE_DATADOG_SERVICE,
      env: import.meta.env.VITE_DATADOG_ENV,
      version: import.meta.env.VITE_DATADOG_VERSION,
      sessionSampleRate: 100,
      sessionReplaySampleRate: 100,
      trackInteractions: true,
      defaultPrivacyLevel: 'mask-user-input',
      trackUserInteractions: true,
      trackResources: true,
      trackFrustrations: true,
      trackLongTasks: true,
      proxyUrl: <proxy url>,
      allowedTracingOrigins: <xxx>,
};

Nginx Configuration (nginx.conf):

http {
    client_body_buffer_size     10M;
    client_max_body_size        10M;

    #proxy_ssl_trusted_certificate /etc/ssl/certs/ca-bundle.crt;
    # Datadog Proxy
    server {
        listen 3834;

        # Proxy for RUM
        location /health {
            return 200;
        }

        location / {
            resolver 8.8.8.8 valid=300s ipv6=off;

            if (\$request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, HEAD';
                add_header 'Access-Control-Allow-Headers' 'Authorization, Origin, Access, DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma';
                return 200;
            }

            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type';

            proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;

            if (\$args ~ "(.*)ddforward=(.*com)&(.*)") {
                set \$args \$1\$3;
                proxy_pass https://\$2;
            }
        }
    }
}

I'm seeking assistance to confirm if the provided configuration is correct. If proxy setup is possible, it doesn't have to be Nginx specifically. Your help is much appreciated.

bcaudan commented 8 months ago

Hi @minJaebak,

In order to validate that your proxy configuration works as expected, you could:

  1. Ensure that the data collection works correctly without the proxy configuration, to be sure that there is not something else going on
  2. Add some logging on the requests performed by your proxy, it would allow you to compare the requests made by the proxy to the requests made by the SDK without the proxy configuration and check if there is any difference
argais commented 8 months ago

Could we get an actual example snippet in the docs? I am going through the exact same exercise and struggling with the nginx config too.

The docs as they are its the same as "here what we expect you to do, figure it out how", which is not really helpful :(

argais commented 8 months ago

I just heard back from support that they wont provide an example or help with nginx because they dont own nginx. Might as well not have the proxy functionality if an example of how to use it wont be provided.

Either way. @minJaebak I've been testing this by forwarding to requestcatcher.com instead of datadog to ensure the decoding is working as expected. I've dropped vanilla nginx in favor of openresty as it has lua integrated and this is my config

      server {
          listen 80;
          server_name my.domain.com;

          # Add resolver directives, required when the proxy_pass is a variable
          resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
          resolver_timeout 5s;

          location /health {
              return 200;
          }

          location / {
              # Extract ddforward parameter from query string into dd_path variable
              if ($arg_ddforward ~* "(.*)") {
                  set $dd_args $1;
              }

              # Convert the URL-encoded string to the normal string
              set_by_lua_block $dd_path {
                  return ngx.unescape_uri(ngx.var.dd_args)
              }

              # The Datadog intake URL based on your example
              # set $datadog_url "https://mydomain.requestcatcher.com";
              set $datadog_url "https://browser-intake-datadoghq.com";

              # Define the final Datadog intake URL
              set $final_datadog_url "${datadog_url}${dd_path}";

              # Other proxy settings
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              # proxy_set_header Host $host;
              proxy_http_version 1.1;
              proxy_method POST;

              proxy_pass $final_datadog_url;
          }
      }
    }
bcaudan commented 8 months ago

We are providing a functionality allowing you to use your own proxy but unfortunately we are not providing a proxy solution for you to use directly. If needed, we can help you to clarify the expected inputs/outputs for your proxy but we won't be able to validate / troubleshoot your proxy configuration. You should be able to find some documentation for the main proxy providers on how to achieve the expected behaviours. Sorry to not be able to help more on that front.

argais commented 8 months ago

Its unfortunate indeed. I was just expecting that like for most functionality that DataDog provides an snippet or example of how to use it would be provided.

Given the amount of money that goes into DataDog I was expecting more. That said, already addressing that expectation with the support team.

I hope the answer I provided above helps people coming to the gh issues for this.

gpsouza93 commented 6 months ago

Hi,

We had a similar issue and were able to configure the internal proxy in a simpler way when using the alternate setup available in RUM SDK version v5.4.0.

Datadog RUM SDK version: 5.4.0 Nginx version: 1.21.0

RUM initialization

export const datadogRumInit = {
      applicationId: import.meta.env.DATADOG_APPLICATION_ID,
      clientToken: import.meta.env.DATADOG_CLIENT_TOKEN,
      site: 'datadoghq.com',
      service: 'rum-proxy-test',
      env: 'qa',
      version: '1.0',
      sessionSampleRate: 100,
      sessionReplaySampleRate: 100,
      defaultPrivacyLevel: 'mask-user-input',
      trackUserInteractions: true,
      trackResources: true,
      trackLongTasks: true,
      proxy: (options) => `http://10.1.1.90:8080${options.path}?${options.parameters}`,
      allowedTracingOrigins: <xxx>,
};

NGINX configuration

      server {
          listen 8080;

          location / {
              # Add an X-Forwarded-For header containing the request client IP address for accurate geoIP
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

              # Forward the request using the POST method
              proxy_method POST;

              # Proxy forward to defined Datadog Intake Origin
              proxy_pass https://browser-intake-datadoghq.com;
          }
      }
    }

The main advantage is that we did not have to worry about extracting or formatting the ddforward parameter. The request is sent from the browser in the format "http://10.1.1.90:8080/api/v2/rum?ddsource=browser...", which makes it easier to be proxy-forwarded to "https://browser-intake-datadoghq.com/api/v2/rum?ddsource=browser..." by this NGINX configuration.

Hope it helps as well!

outdoortejan commented 2 months ago

Hi,

We had a similar issue and were able to configure the internal proxy in a simpler way when using the alternate setup available in RUM SDK version v5.4.0.

Datadog RUM SDK version: 5.4.0 Nginx version: 1.21.0

RUM initialization

export const datadogRumInit = {
      applicationId: import.meta.env.DATADOG_APPLICATION_ID,
      clientToken: import.meta.env.DATADOG_CLIENT_TOKEN,
      site: 'datadoghq.com',
      service: 'rum-proxy-test',
      env: 'qa',
      version: '1.0',
      sessionSampleRate: 100,
      sessionReplaySampleRate: 100,
      defaultPrivacyLevel: 'mask-user-input',
      trackUserInteractions: true,
      trackResources: true,
      trackLongTasks: true,
      proxy: (options) => `http://10.1.1.90:8080${options.path}?${options.parameters}`,
      allowedTracingOrigins: <xxx>,
};

NGINX configuration

      server {
          listen 8080;

          location / {
              # Add an X-Forwarded-For header containing the request client IP address for accurate geoIP
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

              # Forward the request using the POST method
              proxy_method POST;

              # Proxy forward to defined Datadog Intake Origin
              proxy_pass https://browser-intake-datadoghq.com;
          }
      }
    }

The main advantage is that we did not have to worry about extracting or formatting the ddforward parameter. The request is sent from the browser in the format "http://10.1.1.90:8080/api/v2/rum?ddsource=browser...", which makes it easier to be proxy-forwarded to "https://browser-intake-datadoghq.com/api/v2/rum?ddsource=browser..." by this NGINX configuration.

Hope it helps as well!

What is the IP address you hard coded in the proxy variable in your RUM initialization? Is that your nginx server?