faro-web-sdk icon indicating copy to clipboard operation
faro-web-sdk copied to clipboard

Trying to Connect Frontend Clicks to Traces.

Open harshaj-toorak opened this issue 1 year ago • 3 comments

`

Description

import React, { useEffect } from 'react'; import { LogLevel } from '@grafana/faro-web-sdk'; import { trace, context } from '@opentelemetry/api'; // Import OpenTelemetry APIs

const withClickTracking = (WrappedComponent) => { return (props) => { useEffect(() => { const handleClick = (event) => { const element = event?.target; const elementType = element?.tagName?.toLowerCase(); const elementId = element?.id ? #${element?.id} : ''; const elementText = element?.innerText ? : ${element?.innerText} : '';

    // Retrieve the active span from the OpenTelemetry tracer
    const tracer = trace.getTracer('default');
    const activeSpan = tracer.startSpan('click-event', undefined, context.active());
    const traceId = activeSpan.spanContext().traceId;  // Get the trace ID

    const logMessage = `User clicked on ${elementId}${elementText}, traceId: ${traceId}`;
    const faro = window.faro;

    // Log the click event with Faro, including trace ID
    faro && (elementType === "span" || elementType === "button") && faro.api.pushLog([logMessage], {
      level: LogLevel.INFO,
      attributes: {
        elementType,
        elementId,
        elementText, // Pass the traceId to the log attributes
      },
      traceId:traceId,
      trace,
      activeSpan
    });

    // End the span after the event is handled
    activeSpan.end();
  };

  document.addEventListener('click', handleClick);

  return () => {
    document.removeEventListener('click', handleClick);
  };
}, []);

return <WrappedComponent {...props} />;

}; };

export default withClickTracking; `

This is my Initialization for the faro instance

import { useEffect } from "react"; import { ConsoleInstrumentation, ErrorsInstrumentation, FetchTransport, initializeFaro, getWebInstrumentations, SessionInstrumentation, WebVitalsInstrumentation, ConsoleTransport } from "@grafana/faro-web-sdk"; import { trace, context } from "@opentelemetry/api"; import { ZoneContextManager } from "@opentelemetry/context-zone"; import { W3CTraceContextPropagator } from "@opentelemetry/core"; import { registerInstrumentations } from "@opentelemetry/instrumentation"; import { UserInteractionInstrumentation } from "@opentelemetry/instrumentation-user-interaction"; import { DocumentLoadInstrumentation } from "@opentelemetry/instrumentation-document-load"; import { FetchInstrumentation } from "@opentelemetry/instrumentation-fetch"; import { XMLHttpRequestInstrumentation } from "@opentelemetry/instrumentation-xml-http-request"; import { Resource } from "@opentelemetry/resources"; import { BatchSpanProcessor, WebTracerProvider } from "@opentelemetry/sdk-trace-web"; import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_VERSION } from "@opentelemetry/semantic-conventions"; import { FaroSessionSpanProcessor, FaroTraceExporter, TracingInstrumentation } from "@grafana/faro-web-tracing"; import { createReactRouterV6Options, ReactIntegration } from "@grafana/faro-react"; import { getAPIURL } from "OP_WEB_COMMON_SERVICE/getAPIURL"; import { createRoutesFromChildren, matchRoutes, Routes, useLocation, useNavigationType } from "react-router-dom";

const useFaroInitializer = (url, apiKey, email, userId) => { const apiURL = getAPIURL();

useEffect(() => { if (!apiKey || !url || !email || !userId) return;

const instrumentationOptions = {
  propagateTraceHeaderCorsUrls: [
    new RegExp(`https://${apiURL.replace(/\./g, "\\.")}`)
  ]
};

const faro = initializeFaro({
  instrumentations: [
    ...getWebInstrumentations(),
    new TracingInstrumentation({
      instrumentations: [
        new FetchInstrumentation({
          url,
          propagateTraceHeaderCorsUrls: [
            new RegExp(`https://${apiURL.replace(/\./g, "\\.")}`)
          ]
        }),
        new XMLHttpRequestInstrumentation({
          url,
          propagateTraceHeaderCorsUrls: [
            new RegExp(`https://${apiURL.replace(/\./g, "\\.")}`)
          ]
        }),
        new UserInteractionInstrumentation({
          eventNames: ["click", "dblclick", "submit", "keypress"]
        })
      ]
    }),
    // new TracingInstrumentation({ instrumentationOptions }),
    new ErrorsInstrumentation(),
    new WebVitalsInstrumentation(),
    new ConsoleInstrumentation({ disabledLevels: [] }), // Capture console.log
    new SessionInstrumentation(),
    new ReactIntegration({
      router: createReactRouterV6Options({
        createRoutesFromChildren,
        matchRoutes,
        Routes,
        useLocation,
        useNavigationType
      })
    })
  ],
  transports: [
    new FetchTransport({
      url,
      apiKey
    }),
    new ConsoleTransport()
  ],
  app: {
    name: "frontend-dev",
    version: "1.0.0"
  }
});

const resource = Resource.default().merge(
  new Resource({
    [SEMRESATTRS_SERVICE_NAME]: "frontend-dev",
    [SEMRESATTRS_SERVICE_VERSION]: "1.0.0"
  })
);

const provider = new WebTracerProvider({ resource });

provider.addSpanProcessor(
  new FaroSessionSpanProcessor(
    new BatchSpanProcessor(new FaroTraceExporter({ ...faro }))
  )
);

provider.register({
  propagator: new W3CTraceContextPropagator(),
  contextManager: new ZoneContextManager()
});

const ignoreUrls = [url];

registerInstrumentations({
  instrumentations: [
    new DocumentLoadInstrumentation(),
    new FetchInstrumentation({ ignoreUrls }),
    new XMLHttpRequestInstrumentation({ ignoreUrls })
  ]
});

// register OTel with Faro
faro.api.initOTEL(trace, context);
console.log(context, "context");

faro.api.setUser({
  email,
  id: userId
});

// Optionally store the Faro instance globally for debugging
window.faroInstance = faro;

}, [url, apiKey, email, userId]); };

export default useFaroInitializer;

I'm trying to connect the Frontend Logs to the backend so that it is clearly visible in the node graph that where the user clicked and what Backend calls were made but in that case it's not working. for only Backend api calls everyting looks fine.

Image

Expecting the Frontend calls like this as well.

Image

harshaj-toorak avatar Sep 12 '24 10:09 harshaj-toorak