Bump to latest sentry; preload etc (#7617)

New node sentry prefers some node.js "preload" nonsense. I use this
"hack" to avoid having to make a lock-step change to the runner: tested
locally and then deployed to staging and tested there with both
server-side and client-side errors.
This commit is contained in:
Matt Godbolt
2025-04-26 13:36:11 -05:00
committed by GitHub
parent cf7ef2aa3b
commit 04bcf21900
6 changed files with 882 additions and 242 deletions

40
app.ts
View File

@@ -22,6 +22,11 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
////
// see https://docs.sentry.io/platforms/javascript/guides/node/install/late-initialization/
import '@sentry/node/preload'; // preload Sentry's "preload" support before any other imports
////
import child_process from 'node:child_process';
import os from 'node:os';
import path from 'node:path';
@@ -523,12 +528,10 @@ const awsProps = props.propsFor('aws');
// eslint-disable-next-line max-statements
async function main() {
await aws.initConfig(awsProps);
// Initialise express and then sentry. Sentry as early as possible to catch errors during startup.
SetupSentry(aws.getConfig('sentryDsn'), ceProps, releaseBuildNumber, gitReleaseName, defArgs);
const webServer = express();
const router = express.Router();
SetupSentry(aws.getConfig('sentryDsn'), ceProps, releaseBuildNumber, gitReleaseName, defArgs);
startWineInit();
RemoteExecutionQuery.initRemoteExecutionArchs(ceProps, defArgs.env);
@@ -664,12 +667,6 @@ async function main() {
.set('trust proxy', true)
.set('view engine', 'pug')
.on('error', err => logger.error('Caught error in web handler; continuing:', err))
// sentry request handler must be the first middleware on the app
.use(
Sentry.Handlers.requestHandler({
ip: true,
}),
)
// The healthcheck controller is hoisted to prevent it from being logged.
// TODO: Migrate the logger to a shared middleware.
.use(healthCheckController.createRouter())
@@ -687,20 +684,21 @@ async function main() {
.use(httpRoot, router)
.use((req, res, next) => {
next({status: 404, message: `page "${req.path}" could not be found`});
})
// sentry error handler must be the first error handling middleware
.use(Sentry.Handlers.errorHandler())
// eslint-disable-next-line no-unused-vars
.use((err: any, req: express.Request, res: express.Response, _next: express.NextFunction) => {
const status = err.status || err.statusCode || err.status_code || err.output?.statusCode || 500;
const message = err.message || 'Internal Server Error';
res.status(status);
res.render('error', renderConfig({error: {code: status, message: message}}));
if (status >= 500) {
logger.error('Internal server error:', err);
}
});
Sentry.setupExpressErrorHandler(webServer);
// eslint-disable-next-line no-unused-vars
webServer.use((err: any, req: express.Request, res: express.Response, _next: express.NextFunction) => {
const status = err.status || err.statusCode || err.status_code || err.output?.statusCode || 500;
const message = err.message || 'Internal Server Error';
res.status(status);
res.render('error', renderConfig({error: {code: status, message: message}}));
if (status >= 500) {
logger.error('Internal server error:', err);
}
});
const sponsorConfig = loadSponsorsFromString(await fs.readFile(configDir + '/sponsors.yaml', 'utf8'));
function renderConfig(extra: Record<string, any>, urlOptions?: any) {

View File

@@ -130,6 +130,11 @@ export class ApiHandler {
this.handle.route('/version').get(this.handleReleaseName.bind(this)).all(methodNotAllowed);
this.handle.route('/releaseBuild').get(this.handleReleaseBuild.bind(this)).all(methodNotAllowed);
// Let's not document this one, eh?
this.handle.route('/forceServerError').get((req, res) => {
logger.error(`Forced server error from ${req.ip}`);
throw new Error('Forced server error');
});
}
shortlinkInfoHandler(req: express.Request, res: express.Response, next: express.NextFunction) {

View File

@@ -29,13 +29,10 @@ import {parse} from '../shared/stacktrace.js';
import {logger} from './logger.js';
import {PropertyGetter} from './properties.interfaces.js';
function shouldRedactRequestData(data: string) {
try {
const parsed = JSON.parse(data);
return !parsed['allowStoreCodeDebug'];
} catch (e) {
return true;
}
function shouldRedactRequestData(data: unknown) {
if (data === undefined || data === null) return true;
if (Object.hasOwn(data, 'allowStoreCodeDebug')) return !data['allowStoreCodeDebug'];
return true;
}
export function SetupSentry(
@@ -54,9 +51,10 @@ export function SetupSentry(
dsn: sentryDsn,
release: releaseBuildNumber || gitReleaseName,
environment: sentryEnv || defArgs.env[0],
sendDefaultPii: true, // equivalent to `{ip: true}` on older Sentry versions
beforeSend(event) {
if (event.request?.data && shouldRedactRequestData(event.request.data)) {
event.request.data = JSON.stringify({redacted: true});
event.request.data = {redacted: true};
}
return event;
},

1057
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -28,8 +28,8 @@
"@fortawesome/fontawesome-free": "^6.7.2",
"@orchidjs/sifter": "^1.1.0",
"@popperjs/core": "^2.11.8",
"@sentry/browser": "^7.120.3",
"@sentry/node": "^7.120.3",
"@sentry/browser": "^9.14.0",
"@sentry/node": "^9.14.0",
"@types/semver": "^7.7.0",
"big-integer": "^1.6.52",
"bootstrap": "^5.3.5",
@@ -85,7 +85,7 @@
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@sentry/types": "^8.55.0",
"@sentry/types": "^9.14.0",
"@smithy/util-stream": "^4.2.0",
"@types/bootstrap": "^5.2.10",
"@types/chai": "^5.2.1",

View File

@@ -65,7 +65,7 @@ export function SetupSentry() {
release: options.release,
environment: options.sentryEnvironment,
ignoreErrors: [
/CancellationError\(monaco-editor/,
/this.error\(new CancellationError\(\)/,
/new StandardMouseEvent\(monaco-editor/,
/Object Not Found Matching Id:2/,
/i is null _doHitTestWithCaretPositionFromPoint/,