import { configureSync, getConfig, getConsoleSink, getJsonLinesFormatter, getLogger, parseLogLevel } from "@logtape/logtape";
import { captureException, captureMessage, withScope } from "@sentry/core";
import * as Sentry from "@sentry/node";

//#region src/telem/logging.ts
const ROOT_LOG_CATEGORY = ["sentry", "mcp"];
let loggingConfigured = false;
function resolveLowestLevel() {
	const envLevel = typeof process !== "undefined" ? process.env.LOG_LEVEL : void 0;
	if (envLevel) try {
		return parseLogLevel(envLevel);
	} catch (error) {}
	return typeof process !== "undefined" && process.env.NODE_ENV === "development" ? "debug" : "info";
}
/**
* Creates a LogTape sink that sends logs to Sentry's Logs product using Sentry.logger.
*
* Unlike @logtape/sentry's getSentrySink which uses captureException/captureMessage
* (creating Issues), this sink uses Sentry.logger.* methods to send data to the
* Logs product.
*
* Note: This uses @sentry/node logger API. Cloudflare Workers will need a separate
* implementation using @sentry/cloudflare logger API.
*/
function createSentryLogsSink() {
	return (record) => {
		if (!Sentry.logger) return;
		let message = "";
		for (let i = 0; i < record.message.length; i++) if (i % 2 === 0) message += record.message[i];
		else {
			const value = record.message[i];
			message += typeof value === "string" ? value : coerceMessage(value);
		}
		const attributes = record.properties;
		switch (record.level) {
			case "trace":
				Sentry.logger.trace(message, attributes);
				break;
			case "debug":
				Sentry.logger.debug(message, attributes);
				break;
			case "info":
				Sentry.logger.info(message, attributes);
				break;
			case "warning":
				Sentry.logger.warn(message, attributes);
				break;
			case "error":
				Sentry.logger.error(message, attributes);
				break;
			case "fatal":
				Sentry.logger.fatal(message, attributes);
				break;
			default: Sentry.logger.info(message, attributes);
		}
	};
}
function ensureLoggingConfigured() {
	if (loggingConfigured) return;
	const consoleSink = getConsoleSink({ formatter: getJsonLinesFormatter() });
	const sentrySink = createSentryLogsSink();
	configureSync({
		reset: getConfig() !== null,
		sinks: {
			console: consoleSink,
			sentry: sentrySink
		},
		loggers: [
			{
				category: [...ROOT_LOG_CATEGORY],
				sinks: ["console", "sentry"],
				lowestLevel: resolveLowestLevel()
			},
			{
				category: ["logtape", "meta"],
				sinks: ["console"],
				lowestLevel: "warning"
			},
			{
				category: "logtape",
				sinks: ["console"],
				lowestLevel: "error"
			}
		]
	});
	loggingConfigured = true;
}
function getLogger$1(scope, defaults) {
	ensureLoggingConfigured();
	const category = Array.isArray(scope) ? scope : [scope];
	const logger$1 = getLogger([...ROOT_LOG_CATEGORY, ...category]);
	return defaults ? logger$1.with(defaults) : logger$1;
}
const ISSUE_LOGGER_SCOPE = ["runtime", "issues"];
function isRecord(value) {
	return typeof value === "object" && value !== null;
}
function isSentryContexts(value) {
	if (!isRecord(value)) return false;
	return Object.values(value).every((entry) => isRecord(entry));
}
function isBaseLogOptionsCandidate(value) {
	if (!isRecord(value)) return false;
	if ("extra" in value || "loggerScope" in value) return true;
	if ("contexts" in value) {
		const contexts = value.contexts;
		return contexts === void 0 || isSentryContexts(contexts);
	}
	return false;
}
function isLogIssueOptionsCandidate(value) {
	return isBaseLogOptionsCandidate(value) || isRecord(value) && "attachments" in value;
}
function parseBaseOptions(contextsOrOptions) {
	if (isBaseLogOptionsCandidate(contextsOrOptions)) {
		const { contexts, extra, loggerScope } = contextsOrOptions;
		return {
			contexts,
			extra,
			loggerScope
		};
	}
	if (isSentryContexts(contextsOrOptions)) return { contexts: contextsOrOptions };
	return {};
}
function parseLogIssueOptions(contextsOrOptions, attachmentsArg) {
	const base = parseBaseOptions(contextsOrOptions);
	const attachments = isLogIssueOptionsCandidate(contextsOrOptions) ? contextsOrOptions.attachments : void 0;
	return {
		...base,
		attachments: attachments ?? attachmentsArg
	};
}
function parseLogOptions(contextsOrOptions) {
	return parseBaseOptions(contextsOrOptions);
}
function safeJsonStringify(value) {
	try {
		return JSON.stringify(value);
	} catch (error) {
		return void 0;
	}
}
function truncate(text, maxLength = 1024) {
	if (text.length <= maxLength) return text;
	return `${text.slice(0, maxLength - 1)}…`;
}
function coerceMessage(value) {
	if (typeof value === "string") return value;
	if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return value.toString();
	if (value === null || value === void 0) return String(value);
	const json = safeJsonStringify(value);
	if (json) return truncate(json);
	return Object.prototype.toString.call(value);
}
function serializeError(value, depth = 0) {
	if (value instanceof Error) {
		const serialized = { message: value.message };
		if (value.name && value.name !== "Error") serialized.name = value.name;
		if (typeof value.stack === "string") serialized.stack = value.stack;
		const hasCause = "cause" in value && value.cause !== void 0;
		if (hasCause && depth < 3) {
			const cause = value.cause;
			serialized.cause = serializeError(cause, depth + 1);
		}
		return serialized;
	}
	return { message: coerceMessage(value) };
}
const logger = getLogger$1([]);
const DEFAULT_LOGGER_SCOPE = [];
function buildLogProperties(level, options, serializedError) {
	const properties = { severity: level };
	if (serializedError) properties.error = serializedError;
	if (options.extra) Object.assign(properties, options.extra);
	if (options.contexts) properties.sentryContexts = options.contexts;
	return properties;
}
function logWithLevel(level, value, contextsOrOptions) {
	ensureLoggingConfigured();
	const options = parseLogOptions(contextsOrOptions);
	const serializedError = value instanceof Error ? serializeError(value) : void 0;
	const message = serializedError ? serializedError.message : coerceMessage(value);
	const scope = options.loggerScope ?? DEFAULT_LOGGER_SCOPE;
	const scopedLogger = getLogger$1(scope, { severity: level });
	const properties = buildLogProperties(level, options, serializedError);
	switch (level) {
		case "trace":
			scopedLogger.trace(message, () => properties);
			break;
		case "debug":
			scopedLogger.debug(message, () => properties);
			break;
		case "info":
			scopedLogger.info(message, () => properties);
			break;
		case "warning":
			scopedLogger.warn(message, () => properties);
			break;
		case "error":
			scopedLogger.error(message, () => properties);
			break;
		case "fatal":
			scopedLogger.fatal(message, () => properties);
			break;
		default: scopedLogger.info(message, () => properties);
	}
}
function logDebug(value, contextsOrOptions) {
	logWithLevel("debug", value, contextsOrOptions);
}
function logInfo(value, contextsOrOptions) {
	logWithLevel("info", value, contextsOrOptions);
}
function logWarn(value, contextsOrOptions) {
	logWithLevel("warning", value, contextsOrOptions);
}
function logError(value, contextsOrOptions) {
	logWithLevel("error", value, contextsOrOptions);
}
function logIssue(error, contextsOrOptions, attachmentsArg) {
	ensureLoggingConfigured();
	const options = parseLogIssueOptions(contextsOrOptions, attachmentsArg);
	const eventId = withScope((scopeInstance) => {
		if (options.contexts) for (const [key, context] of Object.entries(options.contexts)) scopeInstance.setContext(key, context);
		if (options.extra) scopeInstance.setContext("log", options.extra);
		if (options.attachments) for (const [key, data] of Object.entries(options.attachments)) scopeInstance.addAttachment({
			data,
			filename: key
		});
		const captureLevel = "error";
		return typeof error === "string" ? captureMessage(error, {
			contexts: options.contexts,
			level: captureLevel
		}) : captureException(error, {
			contexts: options.contexts,
			level: captureLevel
		});
	});
	const { attachments,...baseOptions } = options;
	const extra = {
		...baseOptions.extra ?? {},
		...attachments && Object.keys(attachments).length > 0 ? { attachments: Object.keys(attachments) } : {},
		...eventId ? { eventId } : {}
	};
	logError(error, {
		...baseOptions,
		extra,
		loggerScope: baseOptions.loggerScope ?? ISSUE_LOGGER_SCOPE
	});
	return eventId;
}

//#endregion
export { getLogger$1 as getLogger, logDebug, logError, logInfo, logIssue, logWarn, logger };
//# sourceMappingURL=logging-DqqDTe02.js.map