diff --git a/apps/changelog/.env.example b/apps/changelog/.env.example index 14daf94f70fa6..c747ea7b6b785 100644 --- a/apps/changelog/.env.example +++ b/apps/changelog/.env.example @@ -6,3 +6,4 @@ DATABASE_URL=postgresql://postgres:postgres@localhost:5432/changelog NEXTAUTH_URL=http://localhost:3000 NEXTAUTH_SECRET=secret +NEXT_PUBLIC_SENTRY_DSN= diff --git a/apps/changelog/next.config.mjs b/apps/changelog/next.config.mjs index de6463572536d..9cc71c9c7de1b 100644 --- a/apps/changelog/next.config.mjs +++ b/apps/changelog/next.config.mjs @@ -18,4 +18,29 @@ const nextConfig = { }, }; -export default withSentryConfig(nextConfig); +export default withSentryConfig(nextConfig, { + org: 'sentry', + project: 'changelog', + + // Suppresses source map uploading logs during build + silent: !process.env.CI, + + // Upload a larger set of source maps for prettier stack traces (increases build time) + widenClientFileUpload: true, + + // Hides source maps from generated client bundles + hideSourceMaps: true, + + // Automatically tree-shake Sentry logger statements to reduce bundle size + disableLogger: true, + + reactComponentAnnotation: { + enabled: true, + }, + + unstable_sentryWebpackPluginOptions: { + applicationKey: 'sentry-changelog', + }, + + automaticVercelMonitors: true, +}); diff --git a/apps/changelog/package.json b/apps/changelog/package.json index cbfc227be12b8..8847f46f4c4b7 100644 --- a/apps/changelog/package.json +++ b/apps/changelog/package.json @@ -15,41 +15,42 @@ "migrate:dev": "dotenv -e .env.development -- yarn prisma migrate reset" }, "dependencies": { - "rehype-prism-plus": "^1.6.3", - "rehype-slug": "^6.0.0", "@auth/prisma-adapter": "^1.2.0", - "nextjs-toploader": "^1.6.6", - "prism-sentry": "^1.0.2", + "@google-cloud/storage": "^7.7.0", + "@prisma/client": "^5.8.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-toolbar": "^1.0.4", "@radix-ui/themes": "^2.0.3", "@sentry/nextjs": "^8.8.0", - "@google-cloud/storage": "^7.7.0", - "@prisma/client": "^5.8.1", + "@spotlightjs/spotlight": "^2.1.1", "next": "^14.2.5", "next-auth": "^4.24.5", "next-mdx-remote": "^4.4.1", + "nextjs-toploader": "^1.6.6", + "prism-sentry": "^1.0.2", "react": "18.3.1", "react-dom": "18.3.1", "react-select": "^5.7.3", - "sass": "^1.69.5", "react-textarea-autosize": "^8.5.3", + "rehype-prism-plus": "^1.6.3", + "rehype-slug": "^6.0.0", "rss": "^1.2.2", + "sass": "^1.69.5", "textarea-markdown-editor": "^1.0.4" }, "devDependencies": { - "autoprefixer": "^10.4.17", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18.3.0", - "prisma": "^5.8.1", "@types/rss": "^0.0.32", + "autoprefixer": "^10.4.17", "eslint": "^8", "eslint-config-next": "^14.2.5", "postcss": "^8.4.33", - "@tailwindcss/forms": "^0.5.7", + "prisma": "^5.8.1", "tailwindcss": "^3.4.1", - "@tailwindcss/typography": "^0.5.10", "typescript": "^5" }, "volta": { diff --git a/apps/changelog/sentry.client.config.ts b/apps/changelog/sentry.client.config.ts new file mode 100644 index 0000000000000..b7030c212003d --- /dev/null +++ b/apps/changelog/sentry.client.config.ts @@ -0,0 +1,35 @@ +// This file configures the initialization of Sentry on the client. +// The config you add here will be used whenever a users loads a page in their browser. +// https://docs.sentry.io/platforms/javascript/guides/nextjs/ + +import * as SentryCore from '@sentry/core'; +import * as Sentry from '@sentry/nextjs'; +import * as Spotlight from '@spotlightjs/spotlight'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + + // Adjust this value in production, or use tracesSampler for greater control + tracesSampleRate: 1, + + 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: [ + Sentry.replayIntegration(), + SentryCore.thirdPartyErrorFilterIntegration({ + filterKeys: ['sentry-docs'], + behaviour: 'drop-error-if-contains-third-party-frames', + }), + ], +}); + +if (process.env.NODE_ENV === 'development') { + Spotlight.init({ + showClearEventsButton: true, + }); +} diff --git a/apps/changelog/sentry.edge.config.ts b/apps/changelog/sentry.edge.config.ts new file mode 100644 index 0000000000000..09eadd570259f --- /dev/null +++ b/apps/changelog/sentry.edge.config.ts @@ -0,0 +1,8 @@ +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + tracesSampleRate: 1, + debug: false, + environment: process.env.NODE_ENV, +}); diff --git a/apps/changelog/sentry.server.config.ts b/apps/changelog/sentry.server.config.ts new file mode 100644 index 0000000000000..5b732e4908014 --- /dev/null +++ b/apps/changelog/sentry.server.config.ts @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + tracesSampleRate: 1, + debug: false, + environment: process.env.NODE_ENV, + spotlight: process.env.NODE_ENV === 'development', + integrations: [Sentry.prismaIntegration()], +}); diff --git a/apps/changelog/src/app/changelog/layout.module.css b/apps/changelog/src/app/changelog/layout.module.css deleted file mode 100644 index bebc60cf92811..0000000000000 --- a/apps/changelog/src/app/changelog/layout.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.changelogContent { - font-family: var(--font-rubik); -} diff --git a/apps/changelog/src/app/changelog/layout.tsx b/apps/changelog/src/app/changelog/layout.tsx index 8bb7becdf0bd5..22c3e26f2468b 100644 --- a/apps/changelog/src/app/changelog/layout.tsx +++ b/apps/changelog/src/app/changelog/layout.tsx @@ -17,7 +17,7 @@ export default function ChangelogLayout({children}: {children: ReactNode}) { return ( -
+
{children}
diff --git a/apps/changelog/src/app/globals.css b/apps/changelog/src/app/globals.css index 76814fcf4d03c..19e1522f2336d 100644 --- a/apps/changelog/src/app/globals.css +++ b/apps/changelog/src/app/globals.css @@ -4,26 +4,19 @@ @tailwind components; @tailwind utilities; -.radix-themes { - --cursor-button: pointer; - --iris-9: var(--accent-purple); - --iris-a9: var(--accent-purple); - --shadow-6: 0px 4px 16px 0px rgba(31, 22, 51, 0.1); -} - .fancy-border { transition-property: box-shadow, border-color; transition-duration: 0.25s; transition-timing-function: ease-out; +} - &:hover { - box-shadow: - 0 2px 0 rgba(54, 45, 89, 0.15), - -0.1875rem -0.1875rem 0 0.1875rem #f2b712, - 0 0 0 0.375rem #e1567c; - text-decoration: none; - cursor: pointer; - } +.fancy-border:hover { + box-shadow: + 0 2px 0 rgba(54, 45, 89, 0.15), + -0.1875rem -0.1875rem 0 0.1875rem #f2b712, + 0 0 0 0.375rem #e1567c; + text-decoration: none; + cursor: pointer; } .hero-top-left-down-slope { @@ -38,105 +31,7 @@ clip-path: polygon(0 0, 100% 0, 100% 40%, 0 100%); } -.icon { - margin-left: 0.25em; - - svg { - display: inline; - width: 14px; - height: 14px; - } -} - -.icon-external-link { - margin-left: 0; - - svg { - margin-left: 0.15em; - } -} - :root { - /* Oranges */ - --flame0: #df5128; - --flame1: #e55e32; - --flame2: #ea6b3c; - --flame3: #ef7846; - --flame4: #f4834f; - --flame5: #f79a4f; - --flame6: #faaf4e; - --flame7: #edcf9e; - --flame8: #ffefae; - - /* A range of desaturated purples */ - --desatPurple0: #0f0a1f; - --desatPurple1: #231c3d; - --desatPurple2: #362d59; - --desatPurple3: #473a67; - --desatPurple4: #584774; - --desatPurple5: #64517d; - --desatPurple6: #79628c; - --desatPurple7: #846e95; - --desatPurple8: #9481a4; - --desatPurple9: #a796b4; - --desatPurple10: #bbadc6; - --desatPurple11: #c3b6ce; - --desatPurple12: #d2c7da; - --desatPurple13: #e2d9e9; - --desatPurple14: #efe8f4; - --desatPurple15: #faf8ff; - - /* saturated purples */ - --brandPink: #e1557c; - --brandLink: var(--brandPink); - --darkPink: #c83852; - --codeColor: #9c5f99; - --brandDecoration: var(--desatPurple4); - /* accents */ - --accent-purple: #6a5fc1; - --accent-md-violet: '#584774'; - --accent-purple-light: #e1dff3; - --accent-yellow: #fedb4b; - --gray: #c7c5cc; - --dark-purple: #1f1633; - /* misc */ - --jewel0: #69c289; - /* Sentry green */ - --jewel1: #007a78; - /* Darkened Sentry green */ - --lightBlue: #48a5db; - /* Sentry blue */ - - /* - Color variables -*/ - --white: #ffffff; - --lightText: #9093c1; - --highlightPurple: var(--brandLink); - --lightPurple: var(--desatPurple11); - --lightestPurple: var(--desatPurple12); - --mediumPurple: var(--desatPurple6); - --darkestPurple: var(--desatPurple0); - --darkPurple: var(--desatPurple2); - --boldRed: var(--flame0); - --textDecorationPurple: var(--brandDecoration); - --lightestPurpleBackground: rgba(210, 199, 218, 0.2); - --successGreen: var(--jewel0); - - --transition-time: 0.125s; - - --headerHeight: 4rem; - - --light-text: var(--lightText); - --lightest-purple-background: var(--lightestPurpleBackground); - - --paragraph-margin-bottom: 1rem; - --border-color: #dee2e6; - --font-family-monospace: 'Roboto Mono', SFMono-Regular, Consolas, Liberation Mono, Menlo, - Courier, monospace; - - --fade-in-animation: fadeIn; - /* https://storybook.sentry.dev/?path=/story/core-colors--page */ --gray-500: #2b2233; --gray-400: #3e3446; diff --git a/apps/changelog/src/instrumentation.ts b/apps/changelog/src/instrumentation.ts new file mode 100644 index 0000000000000..6a02852d9b177 --- /dev/null +++ b/apps/changelog/src/instrumentation.ts @@ -0,0 +1,9 @@ +export async function register() { + if (process.env.NEXT_RUNTIME === 'nodejs') { + await import('../sentry.server.config'); + } + + if (process.env.NEXT_RUNTIME === 'edge') { + await import('../sentry.edge.config'); + } +} diff --git a/apps/changelog/tailwind.config.ts b/apps/changelog/tailwind.config.ts index b78fa42cb97ae..71c43f44b6c60 100644 --- a/apps/changelog/tailwind.config.ts +++ b/apps/changelog/tailwind.config.ts @@ -1,60 +1,68 @@ -const defaultTheme = require("tailwindcss/defaultTheme"); +const defaultTheme = require('tailwindcss/defaultTheme'); /** @type {import('tailwindcss').Config} */ module.exports = { - content: ["./src/**/*.{js,ts,jsx,tsx}"], + content: ['./src/**/*.{js,ts,jsx,tsx}'], theme: { extend: { animation: { - "fade-in": "fadeIn 0.35s ease-in-out", - "fade-in-left": "fadeInLeft 0.55s ease-in-out", - "fade-in-right": "fadeInRight 0.55s ease-in-out", + 'fade-in': 'fadeIn 0.35s ease-in-out', + 'fade-in-left': 'fadeInLeft 0.55s ease-in-out', + 'fade-in-right': 'fadeInRight 0.55s ease-in-out', }, boxShadow: { - DEFAULT: "var(--shadow-6)", + DEFAULT: 'var(--shadow-6)', }, keyframes: () => ({ fadeIn: { - "0%": { opacity: 0 }, - "100%": { opacity: 1 }, + '0%': {opacity: 0}, + '100%': {opacity: 1}, }, fadeInLeft: { - "0%": { opacity: 0, transform: "translateX(-20px)" }, - "100%": { opacity: 1, transform: "translateX(0)" }, + '0%': {opacity: 0, transform: 'translateX(-20px)'}, + '100%': {opacity: 1, transform: 'translateX(0)'}, }, fadeInRight: { - "0%": { opacity: 0, transform: "translateX(20px)" }, - "100%": { opacity: 1, transform: "translateX(0)" }, + '0%': {opacity: 0, transform: 'translateX(20px)'}, + '100%': {opacity: 1, transform: 'translateX(0)'}, }, }), fontFamily: { sans: [ - "var(--font-rubik)", - "-apple-system", - "BlinkMacSystemFont", - "Segoe UI", - "Helvetica", - "Arial", + 'var(--font-rubik)', + '-apple-system', + 'BlinkMacSystemFont', + 'Segoe UI', + 'Helvetica', + 'Arial', ...defaultTheme.fontFamily.sans, ], - mono: "var(--font-family-monospace)", + mono: [ + 'Roboto Mono', + 'SFMono-Regular', + 'Consolas', + 'Liberation Mono', + 'Menlo', + 'Courier', + 'monospace', + ], }, colors: { - primary: "#362d59", - pruple: "#8d5494", - darkPurple: "#1F1633", - "accent-purple": "#6A5FC1", - "accent-md-violet": "#584774", - red: "#e1567c", - gold: "#F1B71C", + primary: '#362d59', + pruple: '#8d5494', + darkPurple: '#1F1633', + 'accent-purple': '#6A5FC1', + 'accent-md-violet': '#584774', + red: '#e1567c', + gold: '#F1B71C', }, }, }, plugins: [ - require("@tailwindcss/typography"), - require("@tailwindcss/forms")({ - strategy: "class", + require('@tailwindcss/typography'), + require('@tailwindcss/forms')({ + strategy: 'class', }), ], - blocklist: ["collapse"], + blocklist: ['collapse'], }; diff --git a/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx b/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx index 7f568b7fc36c0..57fae8f9feff7 100644 --- a/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx +++ b/docs/platforms/javascript/common/tracing/instrumentation/opentelemetry.mdx @@ -113,3 +113,72 @@ tracer.startActiveSpan("span name", () => { ``` You can also use any other tracer; all OpenTelemetry spans will be picked up by Sentry automatically. + +## Using a Custom Sampler + +We recommend using `SentrySampler` as this will ensure the correct subset of traces is sent to Sentry depending on your `tracesSampleRate`, as well as that all other Sentry features like trace propagation work as expected. +If you however need to use your own sampler then make sure to wrap your `SamplingResult` with our `wrapSamplingDecision` method: + +```js {filename: custom-sampler.js} +const { wrapSamplingDecision } = require("@sentry/opentelemetry"); + +// implements Sampler from "@opentelemetry/sdk-trace-node" +class CustomSampler { + shouldSample( + context, + _traceId, + _spanName, + _spanKind, + attributes, + _links + ) { + const decision = yourDecisionLogic(); + + // wrap the result + return wrapSamplingDecision({ + decision, + context, + spanAttributes: attributes, + }); + } + + toString() { + return CustomSampler.name; + } +} + +module.exports = CustomSampler; + +``` + +Now use your sampler in your `TraceProvider`: + +```js {filename: instrument.js} +const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); +const Sentry = require("@sentry/node"); +const { + SentrySpanProcessor, + SentryPropagator, + SentrySampler, +} = require("@sentry/opentelemetry"); +const CustomSampler = require("./custom-sampler"); + +const sentryClient = Sentry.init({ + dsn: "__DSN__", + skipOpenTelemetrySetup: true, + + // By defining any sample rate, + // tracing intergations will be added by default + tracesSampleRate: 0 +}); + + +const provider = new NodeTracerProvider({ + sampler: new CustomSampler(sentryClient), +}); + +// ...rest of your setup + +// Validate that the setup is correct +Sentry.validateOpenTelemetrySetup(); +``` \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 60d2292df64a2..4f17f7ce0a9cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2739,11 +2739,21 @@ resolved "https://registry.yarnpkg.com/@spotlightjs/overlay/-/overlay-2.0.0-alpha.1.tgz#ccf8af298f05f07db54475aee5d633e3f7b4790c" integrity sha512-BJM8l9mJ6obTX/3xw1Erj9Pk/eVOP8oUtb3PoNjwQfnOrio7J8wlWjSETES22EslVPFI1kpl2UMtB+s91Ic8zQ== +"@spotlightjs/overlay@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@spotlightjs/overlay/-/overlay-2.1.0.tgz#47f6f616c3401bbe4b2094936018e4c840a0a66f" + integrity sha512-4A718MNG81N1q81lH45BppN/Z94lEHa9U8dUtfjpBdnSngJnwz6Ku3gmFhQQfEOcei+xtPdLgCVP3ODfu0etsg== + "@spotlightjs/sidecar@1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@spotlightjs/sidecar/-/sidecar-1.4.0.tgz#8cbd7b620e718723a9507c5b7975d7d379685cdd" integrity sha512-onj/phrNtDI8a79zc8jfxJ5BITQk5klO4xSoQXxiYeQWTZcegVeO8VftOVfWPBnMY/axnh+ltxJm/cHaV5SP6Q== +"@spotlightjs/sidecar@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@spotlightjs/sidecar/-/sidecar-1.5.0.tgz#b7afb8d0e4aaeaaa6d425b0f6a3eef97f78ae3e4" + integrity sha512-ASGHrRKQ40+kN/SAVEVD5GY3tt7gJM4lziEALHKb5rBXKHKIDqCckgEY4n8FhzpTo1N8azVFVHEIriPtpWTEsg== + "@spotlightjs/spotlight@^2.0.0-alpha.1": version "2.0.0-alpha.1" resolved "https://registry.yarnpkg.com/@spotlightjs/spotlight/-/spotlight-2.0.0-alpha.1.tgz#942b1ca78723ac5d20f2006e71abe4862ae9b29a" @@ -2752,6 +2762,16 @@ "@spotlightjs/overlay" "2.0.0-alpha.1" "@spotlightjs/sidecar" "1.4.0" +"@spotlightjs/spotlight@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@spotlightjs/spotlight/-/spotlight-2.1.1.tgz#c57a60c8a4164c2bf6cbf10c72fcf2dcaead8639" + integrity sha512-i67sfCEIXvsHMtGMfE7U0F0MQMcrMRc54ToyaqvzZZ4aRCcUpPdl50KChcixY1ksuI7KiiP0q4h+NbjOzrrX7w== + dependencies: + "@spotlightjs/overlay" "2.1.0" + "@spotlightjs/sidecar" "1.5.0" + import-meta-resolve "^4.1.0" + source-map "^0.7.4" + "@swc/counter@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" @@ -6490,6 +6510,11 @@ import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" +import-meta-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706" + integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -10620,7 +10645,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.0: +source-map@^0.7.0, source-map@^0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==