vercel / otel

OTEL tracing for Vercel
https://vercel.com/docs/observability/otel-overview
40 stars 9 forks source link

fetch instrumentationConfig ignoreUrls not working #110

Open fmaag opened 3 months ago

fmaag commented 3 months ago

Hi,

i am trying to instrument parts of my nextjs application. I want to exclude a lot of urls from this project by using the ignoreUrls config option

export function register() {
  registerOTel({
    serviceName: 'my-app-name',
    spanProcessors: [new JSONProcessor(tracing_config)],
    instrumentationConfig: {
      fetch: {
        ignoreUrls: [/^(?!.*\/chat).*/]
      }
    }
  })
}

My Custom JSONProcessor is written for debug purposes that just console.logs every span in the onEnd function. This shows that not a single exception is being made and the whole application is being instrumented even though i explicitly tell it to exclude every url that does not contain /chat

If i make cherry picked examples by just providing possible string prefixes instead of a regex, the same thing happens. It also is not ignored when explicitly setting opentelemetry.ignore = true in the fetch operation like in the example below.

 const response = await fetch(`/api/manageRole`, {
    method: "GET",
    opentelemetry:{
      ignore: true
    }
  });

Thanks!

harry-gocity commented 3 months ago

Having the same issue, except instead of using registerOtel, I'm using the FetchInstrumentation from the @vercel/otel with the NodeSDK from @opentelemetry/sdk-node (as I also need access to the resource for registering a MeterProvider).

// instrumentation.node.ts

import { Resource } from "@opentelemetry/resources";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { FetchInstrumentation, OTLPHttpJsonTraceExporter } from "@vercel/otel";

const resource = new Resource({
  [SEMRESATTRS_SERVICE_NAME]: "my-project",
});

const traceExporter = new OTLPHttpJsonTraceExporter({ url: "..." });

const batchSpanProcessor = new BatchSpanProcessor(traceExporter, { scheduledDelayMillis: 500 });

const promExporter = new PrometheusExporter();

const meterProvider = new MeterProvider({ resource, readers: [promExporter] });

const sdk = new NodeSDK({
  resource,
  spanProcessors: [batchSpanProcessor],
  instrumentations: [
    new FetchInstrumentation({
      ignoreUrls: ["/api/health-check", "/api/metrics/prometheus"], // doesn't work
    }),
  ],
});

sdk.start();
harry-gocity commented 3 months ago

After doing a bit more investigation today, I realised that this is an ignore list for outgoing fetch requests from Next.js, not incoming requests to Next.js. I was able to ignore requests made to APIs from our Node server in getServerSideProps, but couldn't ignore requests made to Next.js itself e.g. our /api/health-check made by Kubernetes, which shows up as a trace every 30 seconds.

nachten commented 3 months ago

@harry-gocity i hope this works for you:

import { Resource } from "@opentelemetry/resources";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { FetchInstrumentation, OTLPHttpJsonTraceExporter } from "@vercel/otel";
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';

const resource = new Resource({
  [SEMRESATTRS_SERVICE_NAME]: "my-project",
});

const traceExporter = new OTLPHttpJsonTraceExporter({ url: "..." });

const batchSpanProcessor = new BatchSpanProcessor(traceExporter, { scheduledDelayMillis: 500 });

const promExporter = new PrometheusExporter();

const meterProvider = new MeterProvider({ resource, readers: [promExporter] });

const sdk = new NodeSDK({
  resource,
  spanProcessors: [batchSpanProcessor],
  instrumentations: [
    new FetchInstrumentation({
      ignoreUrls: ["/api/health-check", "/api/metrics/prometheus"], // doesn't work
    }),
    new HttpInstrumentation({
      enabled: true,
      ignoreIncomingRequestHook: (request: IncomingMessage) => {
          const ignorePatterns = [
              /^\/_next\//, // starts with /_next/
              /^\/images\//, // starts with /images/
              /\?_rsc=/, // contains ?_rsc=
              /^\/hc/, // starts with /hc
          ];

          const url = request.url;

          if (typeof url === 'string' && ignorePatterns.some((pattern) => pattern.test(url))) {
              return true;
          }

          return false;
      },
      ignoreOutgoingRequestHook: () => {
          return true;
      },
  }),
  ],
});

sdk.start();