Next.js: how to use SplunkRum.setGlobalAttributes?
seanparmelee opened this issue · 10 comments
We have integrating Splunk RUM into a number of Next.js apps, following the directions here.
We'd like to now use setGlobalAttributes
to add some additional information to our spans. It seems that if we import SplunkRum from '@splunk/otel-web'
and try to use it in one of our components, we'll encounter an error during build:
./node_modules/@splunk/otel-web/node_modules/@opentelemetry/instrumentation/build/src/platform/node/instrumentation.js
Critical dependency: the request of a dependency is an expression
Import trace for requested module:
./node_modules/@splunk/otel-web/node_modules/@opentelemetry/instrumentation/build/src/platform/node/index.js
./node_modules/@splunk/otel-web/node_modules/@opentelemetry/instrumentation/build/src/platform/index.js
./node_modules/@splunk/otel-web/node_modules/@opentelemetry/instrumentation/build/src/index.js
./node_modules/@splunk/otel-web/dist/esm/index.js
./pages/list.js
> Build error occurred
ReferenceError: NodeList is not defined
I saw this was brought up in #222, but I'm still left wondering how to use setGlobalAttributes
. I understand that Splunk Rum is only meant to be used on the client side, but even if we add some checks to ensure setGlobalAttributes
is only called on the client-side, simply having the import
in the page causes the build to fail with the aforementioned error.
Are you sure you're using @splunk/otel-web
only on the client side? As explained in https://github.com/signalfx/splunk-otel-js-web/blob/main/examples/next-ssr-example/README.md.
@jtmal-signalfx can you please provide an example of how to call setGlobalAttributes
in a NextJS application? Happy to add it the README.
I just added:
SplunkRum.setGlobalAttributes({
testAttr1: 'test-attr-1-value',
});
to src/splunk-rum.js
like in the tutorial in docs. Works fine for me. Maybe create a reproduction in a repo or codesandbox.io?
It looks like you're trying to use Splunk RUM in server-side code.
@jtmal-signalfx We're already setting some global attributes in the splunk-rum
file (no need to call setGlobalAttributes
there because they can be passed into the init
call):
SplunkRum.init({
...
testAttr1: 'test-attr-1-value'
});
It'd be useful to be able to call that function when the app is running (in my case, I don't know the values until then).
Here's a reproduction repo to check out: https://github.com/seanparmelee/next-splunk-rum
I added the call to a useEffect
so it only runs on the client: https://github.com/seanparmelee/next-splunk-rum/blob/main/pages/index.tsx#L9-L13, but the app won't even build.
useEffect(() => {
window.SplunkRum?.setGlobalAttributes({
foo: 'bar'
});
}, []);
import SplunkRum from '@splunk/otel-web';
(typeof window == 'object' ? window : {}).SplunkRum = SplunkRum;
seems to be working for me, so you should be able to get it up and running. I'll talk to the team about it.
Edit: to clarify, you can't import @splunk/otel-web
in potentially server-side code.
Thanks @jtmal-signalfx. I'd be curious if there's any benefit to continuing down this path vs instrumenting splunk rum via a script tag. At the moment, seems the npm package causes more JS to be bundled into the app (due to multiple versions of the otel dependencies being bundled with the app) and it requires SplunkRum
to be manually added to the window
if you want to be call any of the functions elsewhere in the app. We decided to self host the script for now.
I'll move this to our internal backlog for now. If anyone finds their way here and we still haven't implemented anything that works for you, let us know.
I have a similar problem. We are trying to use SplunkRum in our React project which uses Next.js. I've already modified next.config.js as recommended in the Splunk guideline.
So the SplunkRum.init()
code alone works fine. But when I try to also add SplunkRum.setGlobalAttributes()
in a different place in the code, then the project build fails with a ReferenceError: NodeList is not defined error.
Is there a solution for this yet?
That means you put the code in either a backend section, or an isomorphic section. If we just made it compile, which is technically possible, we could end up with a code which executes on the backend, and the attributes are not present on data sent from the frontend. I'll try to raise this again internally.
I'm using the same guide, I read and tested all of your comments, but when I run this code the output is: undefined
"use client";
import { useEffect } from "react";
export const useMonitoring = () => {
useEffect(() => {
console.log(window?.SplunkRum);
}, []);
};
instrument.js
/* globals process */
import SplunkRum from "@splunk/otel-web";
(typeof window == "object" ? window : {}).SplunkRum = SplunkRum;
SplunkRum.init({
beaconEndpoint: process.env.NEXT_PUBLIC_SPLUNK_URL,
rumAccessToken: process.env.NEXT_PUBLIC_SPLUNK_TOKEN,
applicationName: process.env.NEXT_PUBLIC_SPLUNK_APP,
deploymentEnvironment: process.env.NEXT_PUBLIC_SPLUNK_ENV,
});
next.config in the same folder as instrument
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export",
images: {
unoptimized: true,
},
transpilePackages: ["ui"],
reactStrictMode: true,
webpack: (config, { isServer }) => {
if (isServer) {
return config;
}
const origEntry = config.entry;
const entry = async () => {
let entries = origEntry;
if (typeof entries === "function") {
entries = await entries();
}
const instrumentFile = "./instrument.js";
// Webpack accepts string, string[] or object as entrypoint's value.
// https://webpack.js.org/configuration/entry-context/#entry
// Generally in our testing main is just a string value
// but for completeness/future saftey this covers all
if (typeof entries.main === "string") {
entries.main = [instrumentFile, entries.main];
} else if (Array.isArray(entries.main)) {
entries.main = [instrumentFile, ...entries.main];
} else {
let imported = entries.main.import;
if (typeof imported === "string") {
imported = [instrumentFile, imported];
} else {
imported = [instrumentFile, ...imported];
}
entries.main = {
...entries.main,
import: imported,
};
}
return entries;
};
// Replace entry in config with new value
return {
...config,
entry,
};
},
};
module.exports = nextConfig;
I'm using this version
"@splunk/otel-web": "^0.16.4",