mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added Sentry instrumentation for get helpers (#19576)
no issue - To help debug ABORTED_GET_HELPER errors, this PR adds Sentry instrumentation to the get helpers - It also adds the homepage, any pages/posts, the tag page, and the author page to the list of transactions that will send to Sentry
This commit is contained in:
parent
428be0f9ef
commit
794ef85968
3 changed files with 51 additions and 27 deletions
|
@ -7,6 +7,7 @@ const {hbs} = require('../services/handlebars');
|
||||||
const logging = require('@tryghost/logging');
|
const logging = require('@tryghost/logging');
|
||||||
const errors = require('@tryghost/errors');
|
const errors = require('@tryghost/errors');
|
||||||
const tpl = require('@tryghost/tpl');
|
const tpl = require('@tryghost/tpl');
|
||||||
|
const Sentry = require('@sentry/node');
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const jsonpath = require('jsonpath');
|
const jsonpath = require('jsonpath');
|
||||||
|
@ -206,9 +207,21 @@ module.exports = async function get(resource, options) {
|
||||||
|
|
||||||
// Parse the options we're going to pass to the API
|
// Parse the options we're going to pass to the API
|
||||||
apiOptions = parseOptions(ghostGlobals, this, apiOptions);
|
apiOptions = parseOptions(ghostGlobals, this, apiOptions);
|
||||||
|
let apiOptionsString = Object.entries(apiOptions)
|
||||||
|
.map(([key, value]) => ` ${key}="${value}"`)
|
||||||
|
.join('');
|
||||||
apiOptions.context = {member: data.member};
|
apiOptions.context = {member: data.member};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const spanName = `{{#get "${resource}"${apiOptionsString}}} ${data.member ? 'member' : 'public'}`;
|
||||||
|
const result = await Sentry.startSpan({
|
||||||
|
op: 'frontend.helpers.get',
|
||||||
|
name: spanName,
|
||||||
|
tags: {
|
||||||
|
resource,
|
||||||
|
...apiOptions,
|
||||||
|
context: data.member ? 'member' : 'public'
|
||||||
|
}
|
||||||
|
}, async (span) => {
|
||||||
const response = await makeAPICall(resource, controllerName, action, apiOptions);
|
const response = await makeAPICall(resource, controllerName, action, apiOptions);
|
||||||
|
|
||||||
// prepare data properties for use with handlebars
|
// prepare data properties for use with handlebars
|
||||||
|
@ -218,6 +231,7 @@ module.exports = async function get(resource, options) {
|
||||||
|
|
||||||
// used for logging details of slow requests
|
// used for logging details of slow requests
|
||||||
returnedRowsCount = response[resource] && response[resource].length;
|
returnedRowsCount = response[resource] && response[resource].length;
|
||||||
|
span?.setTag('returnedRows', returnedRowsCount);
|
||||||
|
|
||||||
// block params allows the theme developer to name the data using something like
|
// block params allows the theme developer to name the data using something like
|
||||||
// `{{#get "posts" as |result pageInfo|}}`
|
// `{{#get "posts" as |result pageInfo|}}`
|
||||||
|
@ -232,6 +246,8 @@ module.exports = async function get(resource, options) {
|
||||||
data: data,
|
data: data,
|
||||||
blockParams: blockParams
|
blockParams: blockParams
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logging.error(error);
|
logging.error(error);
|
||||||
data.error = error.message;
|
data.error = error.message;
|
||||||
|
|
|
@ -58,11 +58,15 @@ const beforeSend = function (event, hint) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALLOWED_HTTP_TRANSACTIONS = [
|
const ALLOWED_HTTP_TRANSACTIONS = [
|
||||||
'/ghost/api',
|
'/ghost/api', // any Ghost API call
|
||||||
'/members/api'
|
'/members/api', // any Members API call
|
||||||
|
'/:slug', // any frontend post/page
|
||||||
|
'/author', // any frontend author page
|
||||||
|
'/tag' // any frontend tag page
|
||||||
].map((path) => {
|
].map((path) => {
|
||||||
// Sentry names HTTP transactions like: "<HTTP_METHOD> <PATH>" i.e. "GET /ghost/api/content/settings"
|
// Sentry names HTTP transactions like: "<HTTP_METHOD> <PATH>" i.e. "GET /ghost/api/content/settings"
|
||||||
return new RegExp(`^(GET|POST|PUT|DELETE)\\s(?<path>${path}\\/.+)`);
|
// Match any of the paths above with any HTTP method, and also the homepage "GET /"
|
||||||
|
return new RegExp(`^(GET|POST|PUT|DELETE)\\s(?<path>${path}\\/.+|\\/$)`);
|
||||||
});
|
});
|
||||||
|
|
||||||
const beforeSendTransaction = function (event) {
|
const beforeSendTransaction = function (event) {
|
||||||
|
|
|
@ -156,7 +156,7 @@ describe('UNIT: sentry', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('beforeTransaction', function () {
|
describe('beforeSendTransaction', function () {
|
||||||
it('filters transactions based on an allow list', function () {
|
it('filters transactions based on an allow list', function () {
|
||||||
sentry = require('../../../core/shared/sentry');
|
sentry = require('../../../core/shared/sentry');
|
||||||
|
|
||||||
|
@ -166,7 +166,11 @@ describe('UNIT: sentry', function () {
|
||||||
{transaction: 'GET /ghost/api/settings'},
|
{transaction: 'GET /ghost/api/settings'},
|
||||||
{transaction: 'PUT /members/api/member'},
|
{transaction: 'PUT /members/api/member'},
|
||||||
{transaction: 'POST /ghost/api/tiers'},
|
{transaction: 'POST /ghost/api/tiers'},
|
||||||
{transaction: 'DELETE /members/api/member'}
|
{transaction: 'DELETE /members/api/member'},
|
||||||
|
{transaction: 'GET /'},
|
||||||
|
{transaction: 'GET /:slug/options(edit)?/'},
|
||||||
|
{transaction: 'GET /author/:slug'},
|
||||||
|
{transaction: 'GET /tag/:slug'}
|
||||||
];
|
];
|
||||||
|
|
||||||
allowedTransactions.forEach((transaction) => {
|
allowedTransactions.forEach((transaction) => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue