#Integration with Wouter

9 messages · Page 1 of 1 (latest)

meager crown
solar pilotBOT
#

Hi @meager crown. I'm happy to dig into this for you! I'll check my internal sources for answers to your question! :wave:

#

Yes, for integrating Sentry's browser tracing with Wouter, using a custom routing integration is the right approach. Since Sentry doesn't have a built-in integration specifically for Wouter (unlike React Router or TanStack Router), you'll need to implement custom routing instrumentation.

Here's how you can set it up:

  1. First, disable the automatic span creation in the browserTracingIntegration:
const client = Sentry.init({
  integrations: [
    Sentry.browserTracingIntegration({
      // disable automatic span creation
      instrumentNavigation: false,
      instrumentPageLoad: false,
    }),
  ],
});
  1. Then implement custom routing with Wouter by creating spans manually:
// Start the pageload span as early as possible
let pageLoadSpan = Sentry.startBrowserTracingPageLoadSpan(client, {
  name: window.location.pathname,
  attributes: {
    [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
  },
});

// Use Wouter's useLocation hook or router events to track navigation
// Example with useLocation:
const [location, setLocation] = useLocation();

// Set up an effect to track location changes
useEffect(() => {
  // For the initial pageload
  if (pageLoadSpan) {
    pageLoadSpan.updateName(location);
    pageLoadSpan.setAttribute(
      Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
      "route"
    );
    pageLoadSpan = undefined;
  } else {
    // For subsequent navigations
    Sentry.startBrowserTracingNavigationSpan(client, {
      op: "navigation",
      name: location,
      attributes: {
        [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
      },
    });
  }
}, [location]);

As for gotchas, here are a few things to keep in mind:

#
  1. Make sure you're initializing the pageload span as early as possible in your application lifecycle.
  2. Since Wouter is a lightweight router, you'll need to handle the route change detection yourself using hooks or event listeners.
  3. You might need to adapt the example to work with Wouter's specific API and event system.

This approach is similar to what's documented for other frameworks in Sentry's documentation for custom routing instrumentation.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@meager crown Our robots are still learning and improving, please let us know if this response was correct by reacting below.

meager crown
#

@solar pilot Thanks. In a react app, what would be the optimal place to initialize the pageLoadSpan? and then should I use a Ref or something to keep track of it?

solar pilotBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

In a React app using Wouter, the optimal place to initialize the pageLoadSpan would be as early as possible in your application's lifecycle. Here are the best practices for implementation:

Initializing pageLoadSpan

The ideal place to initialize the pageLoadSpan is in your application's entry point file (typically index.js or App.js), right after initializing Sentry:

// In your app's entry point (e.g., index.js)
import * as Sentry from "@sentry/react";

const client = Sentry.init({
  dsn: "your-dsn",
  integrations: [
    Sentry.browserTracingIntegration({
      instrumentNavigation: false,
      instrumentPageLoad: false,
    }),
  ],
  tracesSampleRate: 1.0,
});

// Start the pageload span immediately after initialization
let pageLoadSpan = Sentry.startBrowserTracingPageLoadSpan(client, {
  name: window.location.pathname,
  attributes: {
    [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
  },
});

Tracking the pageLoadSpan

Yes, using a React ref is a good approach to keep track of the pageLoadSpan across your application. You can create a context to make it accessible throughout your app:

// Create a context for the span
import { createContext, useRef, useContext } from 'react';

const SpanContext = createContext(null);

export function SpanProvider({ children, initialPageLoadSpan }) {
  const pageLoadSpanRef = useRef(initialPageLoadSpan);
  
  return (
    <SpanContext.Provider value={pageLoadSpanRef}>
      {children}
    </SpanContext.Provider>
  );
}

export function useSpanContext() {
  return useContext(SpanContext);
}

Then in your router component with Wouter:

import { useLocation } from 'wouter';
import { useSpanContext } from './SpanContext';
import * as Sentry from "@sentry/react";
#

function RouterTracker() {
const [location] = useLocation();
const pageLoadSpanRef = useSpanContext();

useEffect(() => {
const client = Sentry.getClient();

if (pageLoadSpanRef.current) {
  // Update the pageload span with the route name
  pageLoadSpanRef.current.updateName(location);
  pageLoadSpanRef.current.setAttribute(
    Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
    "route"
  );
  pageLoadSpanRef.current = undefined; // Clear after first navigation
} else {
  // For subsequent navigations
  Sentry.startBrowserTracingNavigationSpan(client, {
    op: "navigation",
    name: location,
    attributes: {
      [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
    },
  });
}

}, [location, pageLoadSpanRef]);

return null; // This component doesn't render anything
}


This approach follows the pattern shown in Sentry's documentation for [custom routing instrumentation](<https://docs.sentry.io/platforms/javascript/guides/react/tracing/instrumentation/automatic-instrumentation/#custom-routing>) while adapting it to React's component lifecycle and Wouter's routing system.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------