mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Added custom Sentry integration for Knex.js (#19315)
no refs Added custom Sentry integration for Knex.js to trace database queries in Sentry
This commit is contained in:
parent
f91d046f5e
commit
bd6bfe13c0
3 changed files with 82 additions and 3 deletions
|
@ -483,7 +483,7 @@ async function bootGhost({backend = true, frontend = true, server = true} = {})
|
||||||
|
|
||||||
// Sentry must be initialized early, but requires config
|
// Sentry must be initialized early, but requires config
|
||||||
debug('Begin: Load sentry');
|
debug('Begin: Load sentry');
|
||||||
require('./shared/sentry');
|
const sentry = require('./shared/sentry');
|
||||||
debug('End: Load sentry');
|
debug('End: Load sentry');
|
||||||
|
|
||||||
// Step 2 - Start server with minimal app in global maintenance mode
|
// Step 2 - Start server with minimal app in global maintenance mode
|
||||||
|
@ -502,6 +502,9 @@ async function bootGhost({backend = true, frontend = true, server = true} = {})
|
||||||
debug('Begin: Get DB ready');
|
debug('Begin: Get DB ready');
|
||||||
await initDatabase({config});
|
await initDatabase({config});
|
||||||
bootLogger.log('database ready');
|
bootLogger.log('database ready');
|
||||||
|
sentry.initQueryTracing(
|
||||||
|
require('./server/data/db/connection')
|
||||||
|
);
|
||||||
debug('End: Get DB ready');
|
debug('End: Get DB ready');
|
||||||
|
|
||||||
// Step 4 - Load Ghost with all its services
|
// Step 4 - Load Ghost with all its services
|
||||||
|
|
67
ghost/core/core/shared/SentryKnexTracingIntegration.js
Normal file
67
ghost/core/core/shared/SentryKnexTracingIntegration.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
* @typedef {import('knex').Knex.Client} KnexClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('@sentry/types').Integration} SentryIntegration
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sentry Knex tracing integration
|
||||||
|
*
|
||||||
|
* @implements {SentryIntegration}
|
||||||
|
*/
|
||||||
|
class SentryKnexTracingIntegration {
|
||||||
|
static id = 'Knex';
|
||||||
|
|
||||||
|
name = SentryKnexTracingIntegration.id;
|
||||||
|
|
||||||
|
/** @type {KnexClient} */
|
||||||
|
#knex;
|
||||||
|
|
||||||
|
/** @type {Map} */
|
||||||
|
#spanCache = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {KnexClient} knex
|
||||||
|
*/
|
||||||
|
constructor(knex) {
|
||||||
|
this.#knex = knex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} addGlobalEventProcessor
|
||||||
|
* @param {Function} getCurrentHub
|
||||||
|
*/
|
||||||
|
setupOnce(addGlobalEventProcessor, getCurrentHub) {
|
||||||
|
this.#knex.on('query', (query) => {
|
||||||
|
const scope = getCurrentHub().getScope();
|
||||||
|
const parentSpan = scope?.getSpan();
|
||||||
|
|
||||||
|
const span = parentSpan?.startChild({
|
||||||
|
op: 'db.query',
|
||||||
|
description: query.sql
|
||||||
|
});
|
||||||
|
|
||||||
|
if (span) {
|
||||||
|
this.#spanCache.set(query.__knexQueryUid, span);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleQueryExecuted = (err, query) => {
|
||||||
|
const queryId = query.__knexQueryUid;
|
||||||
|
const span = this.#spanCache.get(queryId);
|
||||||
|
|
||||||
|
if (span) {
|
||||||
|
span.finish();
|
||||||
|
|
||||||
|
this.#spanCache.delete(queryId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.#knex.on('query-response', handleQueryExecuted);
|
||||||
|
this.#knex.on('query-error', handleQueryExecuted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SentryKnexTracingIntegration;
|
|
@ -1,4 +1,5 @@
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
|
const SentryKnexTracingIntegration = require('./SentryKnexTracingIntegration');
|
||||||
const sentryConfig = config.get('sentry');
|
const sentryConfig = config.get('sentry');
|
||||||
const errors = require('@tryghost/errors');
|
const errors = require('@tryghost/errors');
|
||||||
|
|
||||||
|
@ -93,7 +94,14 @@ if (sentryConfig && !sentryConfig.disabled) {
|
||||||
}),
|
}),
|
||||||
tracingHandler: Sentry.Handlers.tracingHandler(),
|
tracingHandler: Sentry.Handlers.tracingHandler(),
|
||||||
captureException: Sentry.captureException,
|
captureException: Sentry.captureException,
|
||||||
beforeSend: beforeSend
|
beforeSend: beforeSend,
|
||||||
|
initQueryTracing: (knex) => {
|
||||||
|
if (sentryConfig.tracing?.enabled === true) {
|
||||||
|
const integration = new SentryKnexTracingIntegration(knex);
|
||||||
|
|
||||||
|
Sentry.addIntegration(integration);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const expressNoop = function (req, res, next) {
|
const expressNoop = function (req, res, next) {
|
||||||
|
@ -106,6 +114,7 @@ if (sentryConfig && !sentryConfig.disabled) {
|
||||||
requestHandler: expressNoop,
|
requestHandler: expressNoop,
|
||||||
errorHandler: expressNoop,
|
errorHandler: expressNoop,
|
||||||
tracingHandler: expressNoop,
|
tracingHandler: expressNoop,
|
||||||
captureException: noop
|
captureException: noop,
|
||||||
|
initQueryTracing: noop
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue