clienttarget / src /shared /utils /logger.ts
iDevBuddy
feat: Phase 1 — AI Client Acquisition System
bd28470
import pino from "pino";
import { getEnv } from "../config/env";
// PII fields that will be redacted in logs
const PII_FIELDS = ["email", "full_name", "first_name", "last_name", "phone", "linkedin_url"];
function redactPii(obj: Record<string, unknown>): Record<string, unknown> {
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
if (PII_FIELDS.includes(key) && typeof value === "string") {
// Show first 3 chars + *** e.g. "joh***"
result[key] = value.length > 3 ? `${value.slice(0, 3)}***` : "***";
} else if (value && typeof value === "object" && !Array.isArray(value)) {
result[key] = redactPii(value as Record<string, unknown>);
} else {
result[key] = value;
}
}
return result;
}
const env = getEnv();
export const logger = pino({
level: env.LOG_LEVEL,
transport:
env.NODE_ENV === "development"
? { target: "pino-pretty", options: { colorize: true } }
: undefined,
serializers: {
// Auto-redact PII in any "contact" or "data" field
contact: (val: Record<string, unknown>) => redactPii(val),
data: (val: Record<string, unknown>) => redactPii(val),
},
});
// Convenience method for audit-safe logging
export function auditLog(action: string, entity: string, details: Record<string, unknown>) {
logger.info({ action, entity, details: redactPii(details) }, `[AUDIT] ${action}`);
}