@toruslabs/loglevel-sentry
Version:
A package to allow logging and monitoring with sentry
203 lines (199 loc) • 7.62 kB
JavaScript
;
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;