UNPKG

@embrace-io/web-sdk

Version:
145 lines (144 loc) 5.76 kB
import { getIncrementedCount } from "../../utils/getIncrementedCount.js"; import { KEY_EMB_ERROR_LOG_COUNT, KEY_EMB_EXCEPTION_CAUSE, KEY_EMB_EXCEPTION_HANDLING, KEY_EMB_EXCEPTION_NUMBER, KEY_EMB_JS_EXCEPTION_STACKTRACE, KEY_EMB_JS_FILE_BUNDLE_IDS, KEY_EMB_STATE, KEY_EMB_TYPE, KEY_EMB_UNHANDLED_EXCEPTIONS_COUNT } from "../../constants/attributes.js"; import { getVisibilityState } from "../../utils/getVisibilityState.js"; import { GLOBAL_CONFIG } from "../../utils/globalConfig.js"; import { diag } from "@opentelemetry/api"; import { ATTR_EXCEPTION_MESSAGE, ATTR_EXCEPTION_STACKTRACE, ATTR_EXCEPTION_TYPE } from "@opentelemetry/semantic-conventions"; import { SeverityNumber, logs } from "@opentelemetry/api-logs"; //#region src/managers/EmbraceLogManager/EmbraceLogManager.ts const EMBRACE_EXCEPTION_NUMBER_STORAGE_KEY = "embrace_exception_number"; /** * GLOBAL_CONFIG._EmbraceFileBundleIDs is populated at runtime when each file is loaded, * based on the contents injected by the embrace-web-cli. */ const getJSFileBundleIDs = () => JSON.stringify(GLOBAL_CONFIG._EmbraceFileBundleIDs || {}); var EmbraceLogManager = class EmbraceLogManager { _diag; _perf; _logger; _userSessionManager; _limitManager; _visibilityDoc; _storage; constructor({ diag: diagParam, perf, userSessionManager, limitManager, loggerProvider: globalLoggerProviderOverride, visibilityDoc, storage }) { const loggerProvider = globalLoggerProviderOverride ?? logs; this._diag = diagParam ?? diag.createComponentLogger({ namespace: "EmbraceLogManager" }); this._perf = perf; this._logger = loggerProvider.getLogger("embrace-web-sdk-logs"); this._userSessionManager = userSessionManager; this._limitManager = limitManager; this._visibilityDoc = visibilityDoc; this._storage = storage; } _validateAttributes(attributes) { if (Object.prototype.toString.call(attributes) !== "[object Object]") { this._diag.warn("attributes must be a plain object", attributes); return {}; } return attributes; } static _logSeverityToSeverityNumber(severity) { switch (severity) { case "info": return SeverityNumber.INFO; case "warning": return SeverityNumber.WARN; default: return SeverityNumber.ERROR; } } logException(error, { handled = true, attributes = {}, timestamp = this._perf.getNowMillis(), handler = "manual" } = {}) { const validAttrs = this._validateAttributes(attributes); if (!handled) this._userSessionManager.incrSessionPartCountForKey(KEY_EMB_UNHANDLED_EXCEPTIONS_COUNT); const type = error?.constructor?.name || typeof error; let errMessage = ""; let errName = type; let errStack = ""; let errCause = ""; if (error instanceof Error) { errMessage = String(error.message || "").trim(); errName = error.name || ""; errStack = error.stack || ""; errCause = error.cause ? "present" : ""; } else if (error && typeof error === "object") try { errMessage = JSON.stringify(error); } catch { errMessage = String(error).trim(); } else errMessage = String(error).trim(); const limited = this._limitManager.limitException(errMessage, validAttrs); if (limited === "dropped") return; this._logger.emit({ timestamp, severityNumber: SeverityNumber.ERROR, severityText: "ERROR", body: limited.message, attributes: { ...limited.attributes, [KEY_EMB_TYPE]: "sys.exception", [KEY_EMB_EXCEPTION_HANDLING]: EmbraceLogManager._exceptionHandlingType(handled, handler), [KEY_EMB_EXCEPTION_CAUSE]: errCause, [ATTR_EXCEPTION_TYPE]: type, ["exception.name"]: errName, [ATTR_EXCEPTION_MESSAGE]: limited.message, [ATTR_EXCEPTION_STACKTRACE]: errStack, [KEY_EMB_JS_FILE_BUNDLE_IDS]: getJSFileBundleIDs(), [KEY_EMB_STATE]: getVisibilityState(this._visibilityDoc), [KEY_EMB_EXCEPTION_NUMBER]: getIncrementedCount(this._storage, EMBRACE_EXCEPTION_NUMBER_STORAGE_KEY, this._diag) } }); } message(message, severity, { attributes = {}, includeStacktrace = true, stacktrace } = {}) { if (typeof message !== "string" || !message.trim()) { this._diag.warn("Message must be a non-empty string"); return; } if (![ "info", "warning", "error" ].includes(severity)) { this._diag.warn("Severity must be info, warning, or error"); return; } const validAttrs = this._validateAttributes(attributes); if (severity === "error") this._userSessionManager.incrSessionPartCountForKey(KEY_EMB_ERROR_LOG_COUNT); let stack = ""; if (severity !== "info") { if (typeof stacktrace === "string") stack = stacktrace; else if (includeStacktrace) stack = (/* @__PURE__ */ new Error()).stack || ""; } this._logMessage({ message: message.trim(), severity, timestamp: this._perf.getNowMillis(), attributes: validAttrs, stack }); } _logMessage({ message, severity, timestamp, attributes = {}, stack }) { const limitedLog = this._limitManager.limitLog(message, severity, attributes); if (limitedLog === "dropped") return; this._logger.emit({ timestamp, severityNumber: EmbraceLogManager._logSeverityToSeverityNumber(severity), severityText: severity.toUpperCase(), body: limitedLog.message, attributes: { ...limitedLog.attributes, [KEY_EMB_TYPE]: "sys.log", ...stack ? { [KEY_EMB_JS_EXCEPTION_STACKTRACE]: stack, [KEY_EMB_JS_FILE_BUNDLE_IDS]: getJSFileBundleIDs() } : {}, [KEY_EMB_STATE]: getVisibilityState(this._visibilityDoc) } }); } static _exceptionHandlingType(handled, handler) { if (handled) return "handled"; if (handler === "global_exception") return "unhandled_error"; if (handler === "promise_rejection") return "unhandled_rejection"; return "unhandled"; } }; //#endregion export { EmbraceLogManager }; //# sourceMappingURL=EmbraceLogManager.js.map