Compare commits

...

1 Commits

Author SHA1 Message Date
grandwizard28
94a2b85233 feat(web): move sentry dsn and tunnel to runtime web settings
Move the Sentry dsn and tunnel out of build-time Vite injection into the
web.settings config so they are configurable per deployment at runtime via
SIGNOZ_WEB_SETTINGS_SENTRY_DSN and SIGNOZ_WEB_SETTINGS_SENTRY_TUNNEL. The
backend injects them into index.html and the frontend reads them from
window.signozBootData.settings; environment and release stay build-time.
2026-06-30 16:11:09 +05:30
12 changed files with 63 additions and 23 deletions

View File

@@ -71,6 +71,10 @@ web:
sentry:
# Whether to enable Sentry in web.
enabled: false
# The Sentry DSN.
dsn: ""
# The Sentry tunnel URL.
tunnel: ""
pylon:
# Whether to enable Pylon in web.
enabled: false

View File

@@ -4,5 +4,7 @@ VITE_FRONTEND_API_ENDPOINT="http://localhost:8080"
VITE_PYLON_APP_ID="pylon-app-id"
VITE_APPCUES_APP_ID="appcess-app-id"
VITE_PYLON_IDENTITY_SECRET="pylon-identity-secret"
VITE_SENTRY_DSN="sentry-dsn"
VITE_TUNNEL_URL="sentry-tunnel-url"
CI="1"

View File

@@ -35,6 +35,7 @@ import { PreferenceContextProvider } from 'providers/preferences/context/Prefere
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import { LicenseStatus } from 'types/api/licensesV3/getActive';
import { extractDomain } from 'utils/app';
import { getWebSettings } from 'utils/bootSettings';
import { Home } from './pageComponents';
import PrivateRoute from './Private';
@@ -333,24 +334,19 @@ function App(): JSX.Element {
}, [user, isFetchingUser, isCloudUser, enableAnalytics]);
useEffect(() => {
const webSettings = getWebSettings();
if (isCloudUser || isEnterpriseSelfHostedUser) {
if (
(window.signozBootData?.settings?.posthog.enabled ?? true) &&
process.env.POSTHOG_KEY
) {
if ((webSettings?.posthog.enabled ?? true) && process.env.POSTHOG_KEY) {
posthog.init(process.env.POSTHOG_KEY, {
api_host: 'https://us.i.posthog.com',
person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
});
}
if (
!isSentryInitialized &&
(window.signozBootData?.settings?.sentry.enabled ?? true)
) {
if (!isSentryInitialized && (webSettings?.sentry.enabled ?? true)) {
Sentry.init({
dsn: process.env.SENTRY_DSN,
tunnel: process.env.TUNNEL_URL,
dsn: webSettings?.sentry.dsn,
tunnel: webSettings?.sentry.tunnel,
environment: process.env.ENVIRONMENT,
release: process.env.VERSION,
integrations: [

View File

@@ -46,12 +46,20 @@
},
"Sentry": {
"required": [
"enabled"
"enabled",
"dsn",
"tunnel"
],
"additionalProperties": false,
"properties": {
"dsn": {
"type": "string"
},
"enabled": {
"type": "boolean"
},
"tunnel": {
"type": "string"
}
},
"type": "object"

View File

@@ -16,5 +16,7 @@ export interface Pylon {
enabled: boolean;
}
export interface Sentry {
dsn: string;
enabled: boolean;
tunnel: string;
}

View File

@@ -0,0 +1,9 @@
import type { WebSettings } from 'types/generated/webSettings';
/**
* Returns the web settings injected by the backend into index.html at runtime
* (window.signozBootData.settings), or null when unavailable.
*/
export function getWebSettings(): WebSettings | null {
return window.signozBootData?.settings ?? null;
}

View File

@@ -20,8 +20,6 @@ interface ImportMetaEnv {
readonly VITE_SENTRY_AUTH_TOKEN: string;
readonly VITE_SENTRY_ORG: string;
readonly VITE_SENTRY_PROJECT_ID: string;
readonly VITE_SENTRY_DSN: string;
readonly VITE_TUNNEL_URL: string;
readonly VITE_TUNNEL_DOMAIN: string;
readonly VITE_DOCS_BASE_URL: string;
readonly VITE_ENVIRONMENT: string;

View File

@@ -31,7 +31,11 @@ function devBootDataPlugin(env: Record<string, string>): Plugin {
const settings = {
posthog: { enabled: env.VITE_POSTHOG_ENABLED !== 'false' },
appcues: { enabled: env.VITE_APPCUES_ENABLED !== 'false' },
sentry: { enabled: env.VITE_SENTRY_ENABLED !== 'false' },
sentry: {
enabled: env.VITE_SENTRY_ENABLED !== 'false',
dsn: env.VITE_SENTRY_DSN || '',
tunnel: env.VITE_TUNNEL_URL || '',
},
pylon: { enabled: env.VITE_PYLON_ENABLED !== 'false' },
};
return html.replaceAll('[[.Settings]]', JSON.stringify(settings));
@@ -165,8 +169,6 @@ export default defineConfig(({ mode }): UserConfig => {
'process.env.POSTHOG_KEY': JSON.stringify(env.VITE_POSTHOG_KEY),
'process.env.SENTRY_ORG': JSON.stringify(env.VITE_SENTRY_ORG),
'process.env.SENTRY_PROJECT_ID': JSON.stringify(env.VITE_SENTRY_PROJECT_ID),
'process.env.SENTRY_DSN': JSON.stringify(env.VITE_SENTRY_DSN),
'process.env.TUNNEL_URL': JSON.stringify(env.VITE_TUNNEL_URL),
'process.env.TUNNEL_DOMAIN': JSON.stringify(env.VITE_TUNNEL_DOMAIN),
'process.env.DOCS_BASE_URL': JSON.stringify(env.VITE_DOCS_BASE_URL),
'process.env.ENVIRONMENT': JSON.stringify(env.VITE_ENVIRONMENT),

View File

@@ -36,7 +36,9 @@ type AppcuesConfig struct {
}
type SentryConfig struct {
Enabled bool `mapstructure:"enabled"`
Enabled bool `mapstructure:"enabled"`
DSN string `mapstructure:"dsn"`
Tunnel string `mapstructure:"tunnel"`
}
type PylonConfig struct {

View File

@@ -48,17 +48,20 @@ func TestSettingsConfigWithEnvProvider(t *testing.T) {
testCases := []struct {
name string
env string
value string
expected SettingsConfig
}{
{name: "posthog", env: "SIGNOZ_WEB_SETTINGS_POSTHOG_ENABLED", expected: SettingsConfig{Posthog: PosthogConfig{Enabled: true}}},
{name: "appcues", env: "SIGNOZ_WEB_SETTINGS_APPCUES_ENABLED", expected: SettingsConfig{Appcues: AppcuesConfig{Enabled: true}}},
{name: "sentry", env: "SIGNOZ_WEB_SETTINGS_SENTRY_ENABLED", expected: SettingsConfig{Sentry: SentryConfig{Enabled: true}}},
{name: "pylon", env: "SIGNOZ_WEB_SETTINGS_PYLON_ENABLED", expected: SettingsConfig{Pylon: PylonConfig{Enabled: true}}},
{name: "posthog", env: "SIGNOZ_WEB_SETTINGS_POSTHOG_ENABLED", value: "true", expected: SettingsConfig{Posthog: PosthogConfig{Enabled: true}}},
{name: "appcues", env: "SIGNOZ_WEB_SETTINGS_APPCUES_ENABLED", value: "true", expected: SettingsConfig{Appcues: AppcuesConfig{Enabled: true}}},
{name: "sentry_enabled", env: "SIGNOZ_WEB_SETTINGS_SENTRY_ENABLED", value: "true", expected: SettingsConfig{Sentry: SentryConfig{Enabled: true}}},
{name: "sentry_dsn", env: "SIGNOZ_WEB_SETTINGS_SENTRY_DSN", value: "https://examplePublicKey@o0.ingest.sentry.io/0", expected: SettingsConfig{Sentry: SentryConfig{DSN: "https://examplePublicKey@o0.ingest.sentry.io/0"}}},
{name: "sentry_tunnel", env: "SIGNOZ_WEB_SETTINGS_SENTRY_TUNNEL", value: "https://example.com/tunnel", expected: SettingsConfig{Sentry: SentryConfig{Tunnel: "https://example.com/tunnel"}}},
{name: "pylon", env: "SIGNOZ_WEB_SETTINGS_PYLON_ENABLED", value: "true", expected: SettingsConfig{Pylon: PylonConfig{Enabled: true}}},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
t.Setenv(testCase.env, "true")
t.Setenv(testCase.env, testCase.value)
conf, err := config.New(
context.Background(),

View File

@@ -121,11 +121,21 @@ func TestServeTemplatedIndex(t *testing.T) {
Settings: web.SettingsConfig{
Posthog: web.PosthogConfig{Enabled: true},
Appcues: web.AppcuesConfig{Enabled: true},
Sentry: web.SentryConfig{
Enabled: true,
DSN: "https://examplePublicKey@o0.ingest.sentry.io/0",
Tunnel: "https://example.com/tunnel",
},
},
},
expected: expectedHTML("/", web.Settings{
Posthog: web.Posthog{Enabled: true},
Appcues: web.Appcues{Enabled: true},
Sentry: web.Sentry{
Enabled: true,
DSN: "https://examplePublicKey@o0.ingest.sentry.io/0",
Tunnel: "https://example.com/tunnel",
},
}),
},
}

View File

@@ -16,7 +16,9 @@ type Appcues struct {
}
type Sentry struct {
Enabled bool `json:"enabled" required:"true"`
Enabled bool `json:"enabled" required:"true"`
DSN string `json:"dsn" required:"true"`
Tunnel string `json:"tunnel" required:"true"`
}
type Pylon struct {
@@ -33,6 +35,8 @@ func NewSettings(config Config) Settings {
},
Sentry: Sentry{
Enabled: config.Settings.Sentry.Enabled,
DSN: config.Settings.Sentry.DSN,
Tunnel: config.Settings.Sentry.Tunnel,
},
Pylon: Pylon{
Enabled: config.Settings.Pylon.Enabled,