Closed maxmoeschinger closed 10 months ago
Hi, can you share more details?
Thanks!
You need to actually set the dsn
option in Sentry.init. Otherwise the SDK will not work.
Sure next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
modularizeImports: {
"@mui/icons-material": {
transform: "@mui/icons-material/{{member}}",
},
},
experimental: {
serverActions: true,
serverComponentsExternalPackages: [
"knex",
"oracledb",
"mysql2",
"mysql",
"@google-cloud/storage",
"@google-cloud/pubsub",
"class-validator",
"class-transformer",
"web-ifc",
],
},
images: {
domains: ["ostrich.local", "storage.googleapis.com"],
},
webpack: (config, { isServer }) => {
if (isServer) {
// Possible drivers for knex - IGNORE
config.externals.push(/m[sy]sql|oracle|sqlite\d?|tls|net/i)
}
return config
},
}
module.exports = nextConfig
// Injected content via Sentry wizard below
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { withSentryConfig } = require("@sentry/nextjs")
module.exports = withSentryConfig(
module.exports,
{
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options
// Suppresses source map uploading logs during build
silent: true,
org: "birdsview-as",
project: "ostrich-frontend",
},
{
// For all available options, see:
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,
// Transpiles SDK to be compatible with IE11 (increases bundle size)
transpileClientSDK: true,
// Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
tunnelRoute: "/monitoring",
// Hides source maps from generated client bundles
hideSourceMaps: true,
// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,
},
)
Dockerfile
FROM node:18-alpine as base
WORKDIR /app
FROM base as prod
COPY . .
EXPOSE 3000
ARG COMMIT_SHA
ENV SENTRY_RELEASE=$COMMIT_SHA
CMD ["yarn", "start"]
FROM base as dev
CMD yarn; yarn migrate; yarn dev
I have also tried the following with the same outcome
Sentry.init({
dsn: process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1,
// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,
replaysOnErrorSampleRate: 1.0,
// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,
// You can remove this option if you're not planning to use the Sentry Session Replay feature:
integrations: [
new Sentry.Replay({
// Additional Replay configuration goes in here, for example:
maskAllText: true,
blockAllMedia: true,
}),
],
})
It appears you're not setting the NEXT_PUBLIC_SENTRY_DSN
environment variable in your build. I recommend doing that.
NEXT_PUBLIC_SENTRY_DSN
is only one of the variable that needs to be set. I have the same issue with NEXT_PUBLIC_SENTRY_ENVIRONMENT
and that one can't be set build time since I am reusing the same container in multiple enviornment
Your can define dsn and environment via the dsn
and environment
options in Sentry.init()
. However you pass in these variables depends on your setup. NEXT_PUBLIC_
is not something we came up with. It is a Next.js feature to prevent you from leaking env vars into your client bundle.
I understand that. But the NEXT_PUBLIC_
environment variables are not available in sentry.client.config.ts
after I build my application. Is that expected behavior?
the NEXTPUBLIC environment variables are not available in sentry.client.config.ts after I build my application. Is that expected behavior?
If that is the case please double-check that you're setting the NEXT_PUBLIC_
env vars during build. All NEXT_PUBLIC_
env vars need to be available during build. During runtime alone, they will not be picked up for the client bundles.
So you are saying I need to build a different docker image for every environment just so that sentry configures correctly? That seems quite a waste of compute time.
Next.js has support for runtime environment variables (https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#runtime-environment-variables) but the way you have setup sentry in next.js doesn't make it possible to get it. Do you have any plans on working on a fix for that?
Unfortunately, we cannot have a fix for this, simply because it is not broken. This is a limitation on how you bundle and build applications that run on the client side - you built them once and they stay static so they can be deployed to CDNs and so on. We have not built something custom here so we are effectively using Next.js runtime environment variables.
Does this somehow make sense? What do you recommend we change? What would you do differently?
Next.js has server side rendering so it should be possible to pass the needed variables to the client runtime. I think the problem is the way the client configuration from the default setup is used. I previously sent a link to the next.js documentation and there you have this example:
import { unstable_noStore as noStore } from 'next/cache'
export default function Component() {
noStore()
// cookies(), headers(), and other dynamic functions
// will also opt into dynamic rendering, making
// this env variable is evaluated at runtime
const value = process.env.MY_VALUE
// ...
}
Instead of MY_VALUE
you could have retrieved the sentry variables and then passed those to the frontend and initialized sentry from there.
@maxmoeschinger This would assume that people always do server-side rendering which is not the case. You technically could call Sentry.init()
in the useEffect
of a client component to which you pass a DSN variable from the server. If this works for you, go for it! We sadly can't do it because we need to provide a generic solution.
This issue has gone three weeks without activity. In another week, I will close it.
But! If you comment or otherwise update it, I will reset the clock, and if you remove the label Waiting for: Community
, I will leave it alone ... forever!
"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀
This is more a problem with Next.js than with this package - although I believe the setup documentation could be improved to explain the situation.
Just to clarify the problem: Next.js provides a NEXTPUBLIC prefix to inline variable values into the client bundle at build time - and this is an important characteristic of the feature, because it means that this feature cannot be used for variables that differ from one environment to the next, if you use a single build for multiple environments (i.e. promoting to production in Heroku, or deploying the same docker image to a staging and then a prod environment)
There's some discussion of this in the Next repo here: https://github.com/vercel/next.js/issues/39299#issuecomment-1642406341
The documentation for this package says "You can include your DSN directly in these three files, or provide it in either of two environment variables, SENTRY_DSN or NEXT_PUBLIC_SENTRY_DSN", but in reality, this only works if the value will be the same for all your environments that use the same build.
If you want to specify a DSN per-environment (or specify other env-specific vars, like SENTRY_ENVIRONMENT, for example), you can either use the currently deprecated publicRuntimeConfig method (which is what I do), or create your own API for fetching env values from your server, and use that API when initializing Sentry, passing the appropriate value from the API into Sentry.init
.
The other option, of course is to build a separate build for each environment, each with the appropriate NEXT_PUBLICSENTRY*** variables.
The documentation could certainly make all this more clear.
By iterating on what said by @mltsy, there is a "hack" which proved to be working and that could be useful to whoever wants/needs to set the environment at run time in the client and for example does not want to build one docker image for environment.
Mainly it is about mounting an empty react component on the layout and re initialise the Sentry inside a useEffect callback.
# SentryClientInit react component
'use client'
import { FC, useEffect } from 'react'
import { RuntimeEnvsObject } from '@/types'
import * as Sentry from '@sentry/nextjs';
interface SentryClientInitProps {
sentryEnvs: object
}
const SentryClientInit: FC<SentryClientInitProps> = ({ sentryEnvs }) => {
useEffect(() => {
Sentry.init({
dsn: sentryEnvs?.SENTRY_PROJECT_DSN,
environment: sentryEnvs?.SENTRY_ENVIRONMENT,
enableTracing: false,
release: sentryEnvs?.SENTRY_RELEASE,
replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0.1,
});
}, [])
return <></>
}
export default SentryClientInit
Assuming for example you have a RootLayoutWrapper which encapsulates the whole html, you mount there the react component you just defined and you initialise it with the Sentry envs required to the Sentry init as the following:
const sentryEnvs = async () => {
return {
'SENTRY_PROJECT_DSN': process.env.SENTRY_PROJECT_DSN,
'SENTRY_RELEASE': process.env.SENTRY_RELEASE,
'SENTRY_ENVIRONMENT': process.env.SENTRY_ENVIRONMENT
}
}
interface StyleRegistriesProps {
children: ReactNode
}
const RootLayoutWrapper: FC<StyleRegistriesProps> = async ({ children }) => {
... some layout code ...
return (
<html lang="en">
<head>
...
</head>
<body>
<SentryClientInit sentryEnvs={sentryEnv()} />
<OtherThings>
...
</OtherThings>
</body>
</html>
)
}
export default RootLayoutWrapper
@nic-lan while this may work superficially, it means the SDK initializes extremely late in the pageload lifecycle, meaning you may not record errors that happen during pageload, and the pageload performance monitoring may also be a bit off.
(also it makes your root layout server-side-rendered which comes with a performance penalty)
As I said, it is a hack to work around the fact that Sentry seems not to be able to provide a proper way of doing this.
Sentry seems not to be able to provide a proper way of doing this
I need to reiterate, and I really hope that this doesn't come off as salty 😄: There is no way of doing this. This is the nature of static builds and dynamically rendered content. If you know how to fix this, feel free to make a suggestion!
Is there any way that we use tunnelling and get rid of the client config? I think this way we can send them to the server and from there, send the result to the sentry, so we don't need to use DSN on the browser.
Yup that's possible by pointing the tunnel
option in Sentry.init()
to a proxy. You should still set a dsn
value, otherwise the SDK won't start. In your proxy you probably will have to rewrite the DSN from the payload.
Is there an existing issue for this?
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/nextjs
SDK Version
7.80.1
Framework Version
Nextjs 13.5.5
Link to Sentry event
No response
SDK Setup
Steps to Reproduce
npx @sentry/wizard@latest -i nextjs
NEXT_PUBLIC_SENTRY_DSN
environment variableExpected Result
Expect sentry to upload issues
Actual Result
Sentry is not uploading issues. Seems like the environment variable is not set in frontend