Files
cfw-autumn/server/src/external/logtail/logtailUtils.ts
imeepos a98f11c214 refactor: pass env explicitly across all remaining request-path modules
- Remove last runtimeEnv import from processMessage.ts
- Add env: Env param to all functions with 'Cannot find name env' errors
- Convert initRedisV2 to lazy initialization (ensureRedisV2 + Proxy)
- Add Bindings: Env to StripeWebhookHonoEnv
- Fix 12+ files across external/, internal/, queue/ modules
- Scanning test passes: 1/1 (runtime-env-imports.test.ts)
2026-06-17 07:08:41 -07:00

114 lines
3.2 KiB
TypeScript

import type pino from "pino";
import { initLogger } from "@/utils/logging/initLogger";
const createLogMethod = (pinoMethod: any, logtailMethod?: any) => {
function rewriteAppPath(str: string) {
if (typeof str !== "string") return str;
// Replace file:///app/ with ./
str = str.replace("file:///app/", "./");
return str.replace(/\/app\//g, "./");
}
function rewriteErrorStack(error: Error) {
if (error instanceof Error && typeof error.stack === "string") {
const newError = new Error(error.message);
newError.stack = rewriteAppPath(error.stack);
return newError;
}
return error;
}
return (...args: any[]) => {
let message = "";
let mergedObj = {};
// Helper function to convert Error objects to plain objects
const strings = args
.filter((arg) => typeof arg === "string")
.map(rewriteAppPath);
const objects = args
.filter((arg) => typeof arg !== "string" && arg !== null)
.map((obj) => (obj instanceof Error ? rewriteErrorStack(obj) : obj));
// Use last string as message, or use Error message if no strings provided
if (strings.length > 0) {
message = strings[strings.length - 1];
} else {
// If no string message but we have an Error object, use its stack trace
const errorObject = args.find((arg) => arg instanceof Error);
if (errorObject) {
message = rewriteAppPath(
errorObject.stack || errorObject.message || "Error occurred",
);
}
}
// Merge all objects
mergedObj = Object.assign({}, ...objects);
// Pino format: object first, message second (if object exists)
if (Object.keys(mergedObj).length > 0) {
pinoMethod(mergedObj, message);
} else {
pinoMethod(message);
}
if (!logtailMethod) {
return;
}
// Logtail format: message first, then object (if exists)
if (Object.keys(mergedObj).length > 0) {
logtailMethod(message, mergedObj);
} else {
logtailMethod(message);
}
};
};
const createLoggerStructure = (
basePinoLogger: pino.Logger,
env: Env,
): Logger => ({
debug: createLogMethod(basePinoLogger.debug.bind(basePinoLogger)),
info: createLogMethod(basePinoLogger.info.bind(basePinoLogger)),
warn: createLogMethod(basePinoLogger.warn.bind(basePinoLogger)),
error: createLogMethod(basePinoLogger.error.bind(basePinoLogger)),
child: ({
context,
onlyProd = false,
}: {
context: any;
onlyProd?: boolean;
}) => {
if (onlyProd && (env.NODE_ENV as string | undefined) !== "production") {
return createLoggerStructure(basePinoLogger, env);
}
const childPinoLogger = basePinoLogger.child(context);
return createLoggerStructure(childPinoLogger, env);
},
});
export const createLogger = (env: Env) =>
createLoggerStructure(initLogger({}, env), env);
/**
* Lazy dual-output logger (stdout JSON + axiom). Used only by long-running
* trigger.dev tasks so their lines surface in both the trigger run UI and
* our axiom store. `createLogger` is unaffected.
*/
export const createDualLogger = (env: Env) =>
createLoggerStructure(initLogger({ mode: "dual" }, env), env);
export type Logger = {
debug: (...args: any[]) => void;
info: (...args: any[]) => void;
warn: (...args: any[]) => void;
error: (...args: any[]) => void;
child: (args: { context: any; onlyProd?: boolean }) => Logger;
};