const logger = require('@/utils/logger');
const config = require('@/config').value;
const Sentry = require('@sentry/node');
const art = require('art-template');
const path = require('path');
if (config.sentry) {
Sentry.init({
dsn: config.sentry,
});
Sentry.configureScope((scope) => {
scope.setTag('node_name', config.nodeName);
});
logger.info('Sentry inited.');
}
module.exports = async (ctx, next) => {
try {
await next();
} catch (err) {
let message = err;
if (err.name && (err.name === 'HTTPError' || err.name === 'RequestError')) {
message = `${err.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`;
const templateZh = `
- 完整路由地址,包含所有必选与可选参数
\`${ctx.path}\`
- 预期是什么
- 实际发生了什么
- 部署相关信息
| Env | Value |
| ------------------ | ------------- |
| OS | |
| Node version |${process.version} |
| if Docker, version | |
- 额外信息(日志、报错等)
\`\`\`
${err.message}
\`\`\` `;
const templateEn = `
- The involved route, with all required and optional parameters
\`${ctx.path}\`
- What is expected
- What is actually happening
- Self-deployment information
| Env | Value |
| ------------------ | ------------- |
| OS | |
| Node version |${process.version} |
| if Docker, version | |
- Additional info (logs errors etc)
\`\`\`
${err.message}
\`\`\` `;
message += `
如果您认为 RSSHub 导致了该错误,请在 GitHub 报告。`;
message += `
If you believe this is an error caused by RSSHub, please report me on GitHub.`;
} else if (err instanceof Error) {
message = process.env.NODE_ENV === 'production' ? err.message : err.stack;
}
logger.error(`Error in ${ctx.request.path}: ${message}`);
if (config.isPackage) {
ctx.body = {
error: {
message: err.message,
},
};
} else {
ctx.set({
'Content-Type': 'text/html; charset=UTF-8',
});
if (ctx.status === 403) {
message = err.message;
} else {
ctx.status = 404;
}
const requestPath = ctx.request.path;
ctx.body = art(path.resolve(__dirname, '../views/error.art'), {
requestPath,
message,
});
}
if (!ctx.debug.errorPaths[ctx.request.path]) {
ctx.debug.errorPaths[ctx.request.path] = 0;
}
ctx.debug.errorPaths[ctx.request.path]++;
if (!ctx.debug.errorRoutes[ctx._matchedRoute]) {
ctx._matchedRoute && (ctx.debug.errorRoutes[ctx._matchedRoute] = 0);
}
ctx._matchedRoute && ctx.debug.errorRoutes[ctx._matchedRoute]++;
if (!ctx.state.debuged) {
if (!ctx.debug.routes[ctx._matchedRoute]) {
ctx._matchedRoute && (ctx.debug.routes[ctx._matchedRoute] = 0);
}
ctx._matchedRoute && ctx.debug.routes[ctx._matchedRoute]++;
if (ctx.response.get('X-Koa-Redis-Cache') || ctx.response.get('X-Koa-Memory-Cache')) {
ctx.debug.hitCache++;
}
}
if (config.sentry) {
Sentry.withScope((scope) => {
scope.setTag('route', ctx._matchedRoute);
scope.setTag('name', ctx.request.path.split('/')[1]);
scope.addEventProcessor((event) => Sentry.Handlers.parseRequest(event, ctx.request));
Sentry.captureException(err);
});
}
}
};