"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/index.ts var src_exports = {}; __export(src_exports, { IS_APIFY_LOGGER_EXCEPTION: () => IS_APIFY_LOGGER_EXCEPTION, LEVELS: () => LEVELS, LEVEL_TO_STRING: () => LEVEL_TO_STRING, Log: () => Log, LogFormat: () => LogFormat, LogLevel: () => LogLevel, Logger: () => Logger, LoggerJson: () => LoggerJson, LoggerText: () => LoggerText, PREFIX_DELIMITER: () => PREFIX_DELIMITER, default: () => src_default, getFormatFromEnv: () => getFormatFromEnv, getLevelFromEnv: () => getLevelFromEnv, limitDepth: () => limitDepth, truncate: () => truncate }); module.exports = __toCommonJS(src_exports); // src/log_consts.ts var LogLevel = /* @__PURE__ */ ((LogLevel2) => { LogLevel2[LogLevel2["OFF"] = 0] = "OFF"; LogLevel2[LogLevel2["ERROR"] = 1] = "ERROR"; LogLevel2[LogLevel2["SOFT_FAIL"] = 2] = "SOFT_FAIL"; LogLevel2[LogLevel2["WARNING"] = 3] = "WARNING"; LogLevel2[LogLevel2["INFO"] = 4] = "INFO"; LogLevel2[LogLevel2["DEBUG"] = 5] = "DEBUG"; LogLevel2[LogLevel2["PERF"] = 6] = "PERF"; return LogLevel2; })(LogLevel || {}); var LogFormat = /* @__PURE__ */ ((LogFormat2) => { LogFormat2["JSON"] = "JSON"; LogFormat2["TEXT"] = "TEXT"; return LogFormat2; })(LogFormat || {}); var PREFIX_DELIMITER = ":"; var LEVELS = LogLevel; var LEVEL_TO_STRING = Object.keys(LogLevel).filter((x) => Number.isNaN(+x)); var IS_APIFY_LOGGER_EXCEPTION = Symbol("apify.processed_error"); // src/log_helpers.ts var import_consts = require("@apify/consts"); function truncate(str, maxLength, suffix = "...[truncated]") { maxLength = Math.floor(maxLength); if (suffix.length > maxLength) { throw new Error("suffix string cannot be longer than maxLength"); } if (typeof str === "string" && str.length > maxLength) { str = str.substr(0, maxLength - suffix.length) + suffix; } return str; } __name(truncate, "truncate"); function getLevelFromEnv() { const envVar = process.env[import_consts.APIFY_ENV_VARS.LOG_LEVEL]; if (!envVar) return 4 /* INFO */; if (Number.isFinite(+envVar)) return +envVar; if (LogLevel[envVar]) return LogLevel[envVar]; return +envVar; } __name(getLevelFromEnv, "getLevelFromEnv"); function getFormatFromEnv() { const envVar = process.env[import_consts.APIFY_ENV_VARS.LOG_FORMAT] || "TEXT" /* TEXT */; switch (envVar.toLowerCase()) { case "JSON" /* JSON */.toLowerCase(): return "JSON" /* JSON */; case "TEXT" /* TEXT */.toLowerCase(): return "TEXT" /* TEXT */; default: console.warn(`Unknown value for environment variable ${import_consts.APIFY_ENV_VARS.LOG_FORMAT}: ${envVar}`); return "TEXT" /* TEXT */; } } __name(getFormatFromEnv, "getFormatFromEnv"); function limitDepth(record, depth, maxStringLength) { if (typeof record === "string") { return maxStringLength && record.length > maxStringLength ? truncate(record, maxStringLength) : record; } if (["number", "boolean", "symbol", "bigint"].includes(typeof record) || record == null || record instanceof Date) { return record; } if (record instanceof Error) { const { name, message, stack, cause, ...rest } = record; record = { name, message, stack, cause, ...rest, [IS_APIFY_LOGGER_EXCEPTION]: true }; } const nextCall = /* @__PURE__ */ __name((rec) => limitDepth(rec, depth - 1, maxStringLength), "nextCall"); if (Array.isArray(record)) { return depth ? record.map(nextCall) : "[array]"; } if (typeof record === "object" && record !== null) { const mapObject = /* @__PURE__ */ __name((obj) => { const res = {}; Reflect.ownKeys(obj).forEach((key) => { res[key] = nextCall(obj[key]); }); return res; }, "mapObject"); return depth ? mapObject(record) : "[object]"; } if (typeof record === "function") { return "[function]"; } console.log(`WARNING: Object cannot be logged: ${record}`); return void 0; } __name(limitDepth, "limitDepth"); // src/logger.ts var import_events = require("events"); var _Logger = class _Logger extends import_events.EventEmitter { constructor(options) { super(); this.options = options; } setOptions(options) { this.options = { ...this.options, ...options }; } getOptions() { return this.options; } _outputWithConsole(level, line) { switch (level) { case 1 /* ERROR */: console.error(line); break; case 3 /* WARNING */: console.warn(line); break; case 5 /* DEBUG */: console.debug(line); break; default: console.log(line); } } // eslint-disable-next-line @typescript-eslint/no-unused-vars _log(level, message, data, exception, opts = {}) { throw new Error("log() method must be implemented!"); } log(level, message, ...args) { const line = this._log(level, message, ...args); this.emit("line", line); } }; __name(_Logger, "Logger"); var Logger = _Logger; // src/logger_json.ts var DEFAULT_OPTIONS = { skipLevelInfo: false, skipTime: false }; var _LoggerJson = class _LoggerJson extends Logger { constructor(options = {}) { super({ ...DEFAULT_OPTIONS, ...options }); } _log(level, message, data, exception, opts = {}) { const { prefix, suffix } = opts; if (exception) data = { ...data, exception }; if (prefix) message = `${prefix}${PREFIX_DELIMITER} ${message}`; if (suffix) message = `${message} ${suffix}`; const rec = { time: !this.options.skipTime ? /* @__PURE__ */ new Date() : void 0, level: this.options.skipLevelInfo && level === 4 /* INFO */ ? void 0 : LogLevel[level], msg: message, ...data }; const line = JSON.stringify(rec); this._outputWithConsole(level, line); return line; } }; __name(_LoggerJson, "LoggerJson"); var LoggerJson = _LoggerJson; // src/logger_text.ts var import_ansi_colors2 = __toESM(require("ansi-colors")); // src/node_internals.ts var import_ansi_colors = __toESM(require("ansi-colors")); function identicalSequenceRange(a, b) { for (let i = 0; i < a.length - 3; i++) { const pos = b.indexOf(a[i]); if (pos !== -1) { const rest = b.length - pos; if (rest > 3) { let len = 1; const maxLen = Math.min(a.length - i, rest); while (maxLen > len && a[i + len] === b[pos + len]) { len++; } if (len > 3) { return { len, offset: i }; } } } } return { len: 0, offset: 0 }; } __name(identicalSequenceRange, "identicalSequenceRange"); function getStackString(error) { return error.stack ? String(error.stack) : Error.prototype.toString.call(error); } __name(getStackString, "getStackString"); function getStackFrames(err, stack) { const frames = stack.split("\n"); let cause; try { ({ cause } = err); } catch { } if (cause != null && typeof cause === "object" && IS_APIFY_LOGGER_EXCEPTION in cause) { const causeStack = getStackString(cause); const causeStackStart = causeStack.indexOf("\n at"); if (causeStackStart !== -1) { const causeFrames = causeStack.slice(causeStackStart + 1).split("\n"); const { len, offset } = identicalSequenceRange(frames, causeFrames); if (len > 0) { const skipped = len - 2; const msg = ` ... ${skipped} lines matching cause stack trace ...`; frames.splice(offset + 1, skipped, import_ansi_colors.default.grey(msg)); } } } return frames; } __name(getStackFrames, "getStackFrames"); // src/logger_text.ts var SHORTEN_LEVELS = { SOFT_FAIL: "SFAIL", WARNING: "WARN" }; var LEVEL_TO_COLOR = { [1 /* ERROR */]: "red", [2 /* SOFT_FAIL */]: "red", [3 /* WARNING */]: "yellow", [4 /* INFO */]: "green", [5 /* DEBUG */]: "blue", [6 /* PERF */]: "magenta" }; var SHORTENED_LOG_LEVELS = LEVEL_TO_STRING.map((level) => SHORTEN_LEVELS[level] || level); var MAX_LEVEL_LENGTH_SPACES = Math.max(...SHORTENED_LOG_LEVELS.map((l) => l.length)); var getLevelIndent = /* @__PURE__ */ __name((level) => { let spaces = ""; for (let i = 0; i < MAX_LEVEL_LENGTH_SPACES - level.length; i++) spaces += " "; return spaces; }, "getLevelIndent"); var DEFAULT_OPTIONS2 = { skipTime: true }; var _LoggerText = class _LoggerText extends Logger { constructor(options = {}) { super({ ...DEFAULT_OPTIONS2, ...options }); } _log(level, message, data, exception, opts = {}) { let { prefix, suffix } = opts; let maybeDate = ""; if (!this.options.skipTime) { maybeDate = `${(/* @__PURE__ */ new Date()).toISOString().replace("Z", "").replace("T", " ")} `; } const errStack = exception ? this._parseException(exception) : ""; const color = LEVEL_TO_COLOR[level]; const levelStr = SHORTENED_LOG_LEVELS[level]; const levelIndent = getLevelIndent(levelStr); const dataStr = !data ? "" : ` ${JSON.stringify(data)}`; prefix = prefix ? ` ${prefix}${PREFIX_DELIMITER}` : ""; suffix = suffix ? ` ${suffix}` : ""; const line = `${import_ansi_colors2.default.gray(maybeDate)}${import_ansi_colors2.default[color](levelStr)}${levelIndent}${import_ansi_colors2.default.yellow(prefix)} ${message || ""}${import_ansi_colors2.default.gray(dataStr)}${import_ansi_colors2.default.yellow(suffix)}${errStack}`; this._outputWithConsole(level, line); return line; } _parseException(exception, indentLevel = 1) { if (["string", "boolean", "number", "undefined", "bigint"].includes(typeof exception)) { return ` ${exception}`; } if (exception === null) { return "\nnull"; } if (typeof exception === "symbol") { return ` ${exception.toString()}`; } if (typeof exception === "object" && IS_APIFY_LOGGER_EXCEPTION in exception) { return this._parseLoggerException(exception, indentLevel); } return ` ${JSON.stringify(exception, null, 2)}`; } _parseLoggerException(exception, indentLevel = 1) { const errDetails = []; if (exception.type) { errDetails.push(`type=${exception.type}`); } if (exception.details) { Object.entries(exception.details).map(([key, val]) => errDetails.push(`${key}=${val}`)); } const errorString = exception.stack || exception.reason || exception.message; const isStack = errorString === exception.stack; const errorLines = getStackFrames(exception, errorString); if (isStack) { errorLines[0] = exception.message || errorLines[0]; } if (errDetails.length) { errorLines[0] += import_ansi_colors2.default.gray(`(details: ${errDetails.join(", ")})`); } for (let i = 1; i < errorLines.length; i++) { errorLines[i] = import_ansi_colors2.default.gray(errorLines[i]); } if (exception.cause) { const causeString = this._parseException(exception.cause, indentLevel + 1); const causeLines = causeString.trim().split("\n"); errorLines.push(import_ansi_colors2.default.red(` CAUSE: ${import_ansi_colors2.default.reset(causeLines[0])}`), ...causeLines.slice(1)); } return ` ${errorLines.map((line) => `${" ".repeat(indentLevel * 2)}${line}`).join("\n")}`; } }; __name(_LoggerText, "LoggerText"); var LoggerText = _LoggerText; // src/log.ts var getLoggerForFormat = /* @__PURE__ */ __name((format) => { switch (format) { case "JSON" /* JSON */: return new LoggerJson(); case "TEXT" /* TEXT */: default: return new LoggerText(); } }, "getLoggerForFormat"); var getDefaultOptions = /* @__PURE__ */ __name(() => ({ level: getLevelFromEnv(), maxDepth: 4, maxStringLength: 2e3, prefix: null, suffix: null, logger: getLoggerForFormat(getFormatFromEnv()), data: {} }), "getDefaultOptions"); var _Log = class _Log { constructor(options = {}) { /** * Map of available log levels that's useful for easy setting of appropriate log levels. * Each log level is represented internally by a number. Eg. `log.LEVELS.DEBUG === 5`. */ __publicField(this, "LEVELS", LogLevel); // for BC __publicField(this, "options"); __publicField(this, "warningsOnceLogged", /* @__PURE__ */ new Set()); this.options = { ...getDefaultOptions(), ...options }; if (!LogLevel[this.options.level]) throw new Error('Options "level" must be one of log.LEVELS enum!'); if (typeof this.options.maxDepth !== "number") throw new Error('Options "maxDepth" must be a number!'); if (typeof this.options.maxStringLength !== "number") throw new Error('Options "maxStringLength" must be a number!'); if (this.options.prefix && typeof this.options.prefix !== "string") throw new Error('Options "prefix" must be a string!'); if (this.options.suffix && typeof this.options.suffix !== "string") throw new Error('Options "suffix" must be a string!'); if (typeof this.options.logger !== "object") throw new Error('Options "logger" must be an object!'); if (typeof this.options.data !== "object") throw new Error('Options "data" must be an object!'); } _limitDepth(obj) { return limitDepth(obj, this.options.maxDepth); } /** * Returns the currently selected logging level. This is useful for checking whether a message * will actually be printed to the console before one actually performs a resource intensive operation * to construct the message, such as querying a DB for some metadata that need to be added. If the log * level is not high enough at the moment, it doesn't make sense to execute the query. */ getLevel() { return this.options.level; } /** * Sets the log level to the given value, preventing messages from less important log levels * from being printed to the console. Use in conjunction with the `log.LEVELS` constants such as * * ``` * log.setLevel(log.LEVELS.DEBUG); * ``` * * Default log level is INFO. */ setLevel(level) { if (!LogLevel[level]) throw new Error('Options "level" must be one of log.LEVELS enum!'); this.options.level = level; } internal(level, message, data, exception) { if (level > this.options.level) return; data = { ...this.options.data, ...data }; data = Reflect.ownKeys(data).length > 0 ? this._limitDepth(data) : void 0; exception = this._limitDepth(exception); this.options.logger.log(level, message, data, exception, { prefix: this.options.prefix, suffix: this.options.suffix }); } /** * Configures logger. */ setOptions(options) { this.options = { ...this.options, ...options }; } /** * Returns the logger configuration. */ getOptions() { return { ...this.options }; } /** * Creates a new instance of logger that inherits settings from a parent logger. */ child(options) { let { prefix } = this.options; if (options.prefix) { prefix = prefix ? `${prefix}${PREFIX_DELIMITER}${options.prefix}` : options.prefix; } const data = options.data ? { ...this.options.data, ...options.data } : this.options.data; const newOptions = { ...this.options, ...options, prefix, data }; return new _Log(newOptions); } /** * Logs an `ERROR` message. Use this method to log error messages that are not directly connected * to an exception. For logging exceptions, use the `log.exception` method. */ error(message, data) { this.internal(1 /* ERROR */, message, data); } /** * Logs an `ERROR` level message with a nicely formatted exception. Note that the exception is the first parameter * here and an additional message is only optional. */ exception(exception, message, data) { this.internal(1 /* ERROR */, message, data, exception); } softFail(message, data) { this.internal(2 /* SOFT_FAIL */, message, data); } /** * Logs a `WARNING` level message. Data are stringified and appended to the message. */ warning(message, data) { this.internal(3 /* WARNING */, message, data); } /** * Logs an `INFO` message. `INFO` is the default log level so info messages will be always logged, * unless the log level is changed. Data are stringified and appended to the message. */ info(message, data) { this.internal(4 /* INFO */, message, data); } /** * Logs a `DEBUG` message. By default, it will not be written to the console. To see `DEBUG` * messages in the console, set the log level to `DEBUG` either using the `log.setLevel(log.LEVELS.DEBUG)` * method or using the environment variable `APIFY_LOG_LEVEL=DEBUG`. Data are stringified and appended * to the message. */ debug(message, data) { this.internal(5 /* DEBUG */, message, data); } perf(message, data) { this.internal(6 /* PERF */, message, data); } /** * Logs a `WARNING` level message only once. */ warningOnce(message) { if (this.warningsOnceLogged.has(message)) return; this.warningsOnceLogged.add(message); this.warning(message); } /** * Logs given message only once as WARNING. It's used to warn user that some feature he is using has been deprecated. */ deprecated(message) { this.warningOnce(message); } }; __name(_Log, "Log"); var Log = _Log; // src/index.ts var log = new Log(); var src_default = log; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { IS_APIFY_LOGGER_EXCEPTION, LEVELS, LEVEL_TO_STRING, Log, LogFormat, LogLevel, Logger, LoggerJson, LoggerText, PREFIX_DELIMITER, getFormatFromEnv, getLevelFromEnv, limitDepth, truncate }); //# sourceMappingURL=index.cjs.map