UNPKG

@toruslabs/loglevel-sentry

Version:

A package to allow logging and monitoring with sentry

203 lines (199 loc) 7.62 kB
'use strict'; var _objectSpread = require('@babel/runtime/helpers/objectSpread2'); var _defineProperty = require('@babel/runtime/helpers/defineProperty'); var core = require('@sentry/core'); class LoglevelSentry { constructor(sentry) { _defineProperty(this, "sentry", void 0); _defineProperty(this, "category", void 0); this.sentry = sentry; this.category = "loglevel-sentry"; } static async translateError(args) { const index = args.findIndex(arg => arg instanceof Error); const msgIndex = args.findIndex(arg => typeof arg === "string"); const apiErrorIdx = args.findIndex(arg => arg && typeof arg === "object" && "status" in arg && "type" in arg); const axiosErrorIdx = args.findIndex(arg => arg && typeof arg === "object" && "isAxiosError" in arg && arg.isAxiosError === true); let err; if (apiErrorIdx !== -1) { var _apiError$headers; const apiError = args[apiErrorIdx]; const contentType = (_apiError$headers = apiError.headers) === null || _apiError$headers === void 0 ? void 0 : _apiError$headers.get("content-type"); if (contentType.includes("application/json")) { const errJson = await apiError.json(); err = new Error((errJson === null || errJson === void 0 ? void 0 : errJson.error) || (errJson === null || errJson === void 0 ? void 0 : errJson.message) || JSON.stringify(errJson)); } else if (contentType.includes("text/plain")) { err = new Error(await apiError.text()); } else { err = new Error(`${apiError.status} ${apiError.type.toString()} ${apiError.statusText}`); } } else if (axiosErrorIdx !== -1) { const axiosError = args[axiosErrorIdx]; const errorResponse = axiosError.response; if (errorResponse) { var _errorResponse$header; const contentType = (_errorResponse$header = errorResponse.headers) === null || _errorResponse$header === void 0 ? void 0 : _errorResponse$header["content-type"]; if (contentType.includes("application/json")) { const errJson = errorResponse.data; const errorMsg = "error" in errJson ? errJson.error : "message" in errJson ? errJson.message : JSON.stringify(errJson); err = new Error(errorMsg); } else if (contentType.includes("text/plain")) { err = new Error(errorResponse.data); } else { err = new Error(`${errorResponse.status} ${errorResponse.data.toString()}`); } } else { err = new Error("Network error"); } } else if (index !== -1) { err = args.splice(index, 1)[0]; } else if (msgIndex !== -1) { err = new Error(args.splice(msgIndex, 1)[0]); } else { err = new Error("Unknown error"); } return [err, args]; } static translateArgs(args) { const msgIndex = args.findIndex(arg => typeof arg === "string"); const firstMsg = msgIndex !== -1 ? args.splice(msgIndex, 1)[0] : undefined; return firstMsg ? { message: firstMsg, // args is already spliced data: { arguments: args } } : { data: { arguments: args } }; } static translateLevel(level) { switch (level) { case "info": return "info"; case "warn": return "warning"; default: return "debug"; } } install(logger) { const defaultMethodFactory = logger.methodFactory; logger.methodFactory = (method, level, name) => { if (name) this.category = name.toString(); const defaultMethod = defaultMethodFactory(method, level, name); const isFrontend = typeof window !== "undefined"; const overrideDefaultMethod = (...args) => { var _this$sentry; const currentSpan = (_this$sentry = this.sentry) === null || _this$sentry === void 0 ? void 0 : _this$sentry.getActiveSpan(); const { traceId, spanId } = (currentSpan === null || currentSpan === void 0 ? void 0 : currentSpan.spanContext()) || {}; const isError = method === "error" && args.length >= 1 && args[0] instanceof Error; if (isFrontend) { if (isError) { const error = args[0]; const errMsg = traceId || spanId ? `${error.message}: traceId: ${traceId} - spanId: ${spanId}` : error.message; const newError = new Error(errMsg, { cause: error }); const newArgs = [newError, ...args.slice(1)]; if (defaultMethod) defaultMethod(...newArgs); return; } if (defaultMethod) defaultMethod(...args); } else { let logData = { timestamp: new Date(), level: method.toUpperCase(), logger: name }; if (traceId || spanId) logData = _objectSpread(_objectSpread({}, logData), {}, { traceId, spanId }); if (isError) { var _error$message; const error = args[0]; logData = _objectSpread(_objectSpread({}, logData), {}, { message: (_error$message = error.message) !== null && _error$message !== void 0 ? _error$message : "", stack: error.stack, extra: args.length > 1 ? args.slice(1) : undefined }); } else { var _args$; logData = _objectSpread(_objectSpread({}, logData), {}, { message: (_args$ = args[0]) !== null && _args$ !== void 0 ? _args$ : "", extra: args.length > 1 ? args.slice(1) : undefined }); } if (defaultMethod) defaultMethod(JSON.stringify(core.normalize(logData))); } }; switch (method) { case "error": return async (...args) => { // preserve original stack trace as it's lost when using async/await const { stack } = args.find(arg => arg instanceof Error) || new Error(); const [err, otherArgs] = await LoglevelSentry.translateError(args); err.stack = stack; this.error(err, ...otherArgs); overrideDefaultMethod(err, ...otherArgs); }; default: return (...args) => { this.log(LoglevelSentry.translateLevel(method), ...args); // keep behavior consistent to console in browser overrideDefaultMethod(...args); }; } }; logger.setLevel(logger.getLevel()); } setEnabled(enabled) { if (this.sentry) { const options = this.sentry.getClient().getOptions(); if (options) { options.enabled = enabled; } } } isEnabled() { if (this.sentry) { var _options$enabled; const options = this.sentry.getClient().getOptions(); return (_options$enabled = options === null || options === void 0 ? void 0 : options.enabled) !== null && _options$enabled !== void 0 ? _options$enabled : false; } return false; } log(level, ...args) { if (this.sentry) { this.sentry.addBreadcrumb(_objectSpread(_objectSpread({}, LoglevelSentry.translateArgs(args)), {}, { category: this.category, level, timestamp: Date.now() })); } } trace(...args) { this.log("debug", ...args); } error(err, ...args) { if (this.sentry) { const eventHint = { data: { logger: "loglevel-sentry", "logger.name": this.category, arguments: args } }; this.sentry.captureException(err, eventHint); } } } exports.LoglevelSentry = LoglevelSentry;