Refactor logger to output only to log file and stderr

- Removed console output for log messages, focusing on file logging.
- Added stderr fallback for log messages when log file is unavailable.
- Improved error handling for log file write failures.
This commit is contained in:
Alex Newman
2025-12-27 20:22:31 -05:00
parent 356e3acae3
commit 5f34cae636
9 changed files with 118 additions and 106 deletions
+4 -2
View File
@@ -1,7 +1,9 @@
"use strict";var Be=Object.create;var Q=Object.defineProperty;var We=Object.getOwnPropertyDescriptor;var He=Object.getOwnPropertyNames;var Ye=Object.getPrototypeOf,Ve=Object.prototype.hasOwnProperty;var Ke=(d,e)=>{for(var t in e)Q(d,t,{get:e[t],enumerable:!0})},Se=(d,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of He(e))!Ve.call(d,n)&&n!==t&&Q(d,n,{get:()=>e[n],enumerable:!(s=We(e,n))||s.enumerable});return d};var ae=(d,e,t)=>(t=d!=null?Be(Ye(d)):{},Se(e||!d||!d.__esModule?Q(t,"default",{value:d,enumerable:!0}):t,d)),qe=d=>Se(Q({},"__esModule",{value:!0}),d);var ot={};Ke(ot,{generateContext:()=>it});module.exports=qe(ot);var se=ae(require("path"),1),re=require("os"),W=require("fs");var ve=require("bun:sqlite");var b=require("path"),Ne=require("os"),Ae=require("fs");var Ie=require("url");var B=require("fs"),Oe=require("path"),Re=require("os");var fe="bugfix,feature,refactor,discovery,decision,change",be="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var G=require("fs"),z=require("path"),de=(i=>(i[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i[i.SILENT=4]="SILENT",i))(de||{}),ce=class{level=null;useColor;logFilePath=null;constructor(){this.useColor=process.stdout.isTTY??!1,this.initializeLogFile()}initializeLogFile(){try{let e=M.get("CLAUDE_MEM_DATA_DIR"),t=(0,z.join)(e,"logs");(0,G.existsSync)(t)||(0,G.mkdirSync)(t,{recursive:!0});let s=new Date().toISOString().split("T")[0];this.logFilePath=(0,z.join)(t,`claude-mem-${s}.log`)}catch(e){console.error("[LOGGER] Failed to initialize log file:",e),this.logFilePath=null}}getLevel(){if(this.level===null)try{let e=M.get("CLAUDE_MEM_DATA_DIR"),t=(0,z.join)(e,"settings.json"),n=M.loadFromFile(t).CLAUDE_MEM_LOG_LEVEL.toUpperCase();this.level=de[n]??1}catch(e){console.error("[LOGGER] Failed to load settings, using INFO level:",e),this.level=1}return this.level}correlationId(e,t){return`obs-${e}-${t}`}sessionId(e){return`session-${e}`}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.getLevel()===0?`${e.message}
${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;let s=typeof t=="string"?JSON.parse(t):t;if(e==="Bash"&&s.command)return`${e}(${s.command})`;if(s.file_path)return`${e}(${s.file_path})`;if(s.notebook_path)return`${e}(${s.notebook_path})`;if(e==="Glob"&&s.pattern)return`${e}(${s.pattern})`;if(e==="Grep"&&s.pattern)return`${e}(${s.pattern})`;if(s.url)return`${e}(${s.url})`;if(s.query)return`${e}(${s.query})`;if(e==="Task"){if(s.subagent_type)return`${e}(${s.subagent_type})`;if(s.description)return`${e}(${s.description})`}return e==="Skill"&&s.skill?`${e}(${s.skill})`:e==="LSP"&&s.operation?`${e}(${s.operation})`:e}formatTimestamp(e){let t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),n=String(e.getDate()).padStart(2,"0"),i=String(e.getHours()).padStart(2,"0"),a=String(e.getMinutes()).padStart(2,"0"),c=String(e.getSeconds()).padStart(2,"0"),p=String(e.getMilliseconds()).padStart(3,"0");return`${t}-${s}-${n} ${i}:${a}:${c}.${p}`}log(e,t,s,n,i){if(e<this.getLevel())return;let a=this.formatTimestamp(new Date),c=de[e].padEnd(5),p=t.padEnd(6),l="";n?.correlationId?l=`[${n.correlationId}] `:n?.sessionId&&(l=`[session-${n.sessionId}] `);let u="";i!=null&&(this.getLevel()===0&&typeof i=="object"?u=`
`+JSON.stringify(i,null,2):u=" "+this.formatData(i));let f="";if(n){let{sessionId:E,sdkSessionId:A,correlationId:g,...r}=n;Object.keys(r).length>0&&(f=` {${Object.entries(r).map(([R,y])=>`${R}=${y}`).join(", ")}}`)}let O=`[${a}] [${c}] [${p}] ${l}${s}${f}${u}`;if(e===3?console.error(O):console.log(O),this.logFilePath)try{(0,G.appendFileSync)(this.logFilePath,O+`
`,"utf8")}catch(E){console.error("[LOGGER] Failed to write to log file:",E)}}debug(e,t,s,n){this.log(0,e,t,s,n)}info(e,t,s,n){this.log(1,e,t,s,n)}warn(e,t,s,n){this.log(2,e,t,s,n)}error(e,t,s,n){this.log(3,e,t,s,n)}dataIn(e,t,s,n){this.info(e,`\u2192 ${t}`,s,n)}dataOut(e,t,s,n){this.info(e,`\u2190 ${t}`,s,n)}success(e,t,s,n){this.info(e,`\u2713 ${t}`,s,n)}failure(e,t,s,n){this.error(e,`\u2717 ${t}`,s,n)}timing(e,t,s,n){this.info(e,`\u23F1 ${t}`,n,{duration:`${s}ms`})}happyPathError(e,t,s,n,i=""){let l=((new Error().stack||"").split(`
`+JSON.stringify(i,null,2):u=" "+this.formatData(i));let f="";if(n){let{sessionId:E,sdkSessionId:A,correlationId:g,...r}=n;Object.keys(r).length>0&&(f=` {${Object.entries(r).map(([R,y])=>`${R}=${y}`).join(", ")}}`)}let O=`[${a}] [${c}] [${p}] ${l}${s}${f}${u}`;if(this.logFilePath)try{(0,G.appendFileSync)(this.logFilePath,O+`
`,"utf8")}catch(E){process.stderr.write(`[LOGGER] Failed to write to log file: ${E}
`)}else process.stderr.write(O+`
`)}debug(e,t,s,n){this.log(0,e,t,s,n)}info(e,t,s,n){this.log(1,e,t,s,n)}warn(e,t,s,n){this.log(2,e,t,s,n)}error(e,t,s,n){this.log(3,e,t,s,n)}dataIn(e,t,s,n){this.info(e,`\u2192 ${t}`,s,n)}dataOut(e,t,s,n){this.info(e,`\u2190 ${t}`,s,n)}success(e,t,s,n){this.info(e,`\u2713 ${t}`,s,n)}failure(e,t,s,n){this.error(e,`\u2717 ${t}`,s,n)}timing(e,t,s,n){this.info(e,`\u23F1 ${t}`,n,{duration:`${s}ms`})}happyPathError(e,t,s,n,i=""){let l=((new Error().stack||"").split(`
`)[2]||"").match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/),u=l?`${l[1].split("/").pop()}:${l[2]}`:"unknown",f={...s,location:u};return this.warn(e,`[HAPPY-PATH] ${t}`,f,n),i}},S=new ce;var M=class{static DEFAULTS={CLAUDE_MEM_MODEL:"claude-sonnet-4-5",CLAUDE_MEM_CONTEXT_OBSERVATIONS:"50",CLAUDE_MEM_WORKER_PORT:"37777",CLAUDE_MEM_WORKER_HOST:"127.0.0.1",CLAUDE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_MEM_PROVIDER:"claude",CLAUDE_MEM_GEMINI_API_KEY:"",CLAUDE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",CLAUDE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",CLAUDE_MEM_OPENROUTER_API_KEY:"",CLAUDE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",CLAUDE_MEM_OPENROUTER_SITE_URL:"",CLAUDE_MEM_OPENROUTER_APP_NAME:"claude-mem",CLAUDE_MEM_OPENROUTER_MAX_CONTEXT_MESSAGES:"20",CLAUDE_MEM_OPENROUTER_MAX_TOKENS:"100000",CLAUDE_MEM_DATA_DIR:(0,Oe.join)((0,Re.homedir)(),".claude-mem"),CLAUDE_MEM_LOG_LEVEL:"INFO",CLAUDE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",CLAUDE_MEM_MODE:"code",CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"true",CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES:fe,CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS:be,CLAUDE_MEM_CONTEXT_FULL_COUNT:"5",CLAUDE_MEM_CONTEXT_FULL_FIELD:"narrative",CLAUDE_MEM_CONTEXT_SESSION_COUNT:"10",CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return this.DEFAULTS[e]}static getInt(e){let t=this.get(e);return parseInt(t,10)}static getBool(e){return this.get(e)==="true"}static loadFromFile(e){try{if(!(0,B.existsSync)(e))return this.getAllDefaults();let t=(0,B.readFileSync)(e,"utf-8"),s=JSON.parse(t),n=s;if(s.env&&typeof s.env=="object"){n=s.env;try{(0,B.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),S.info("SETTINGS","Migrated settings file from nested to flat schema",{settingsPath:e})}catch(a){S.warn("SETTINGS","Failed to auto-migrate settings file",{settingsPath:e},a)}}let i={...this.DEFAULTS};for(let a of Object.keys(this.DEFAULTS))n[a]!==void 0&&(i[a]=n[a]);return i}catch(t){return S.warn("SETTINGS","Failed to load settings, using defaults",{settingsPath:e},t),this.getAllDefaults()}}};var ze={};function Je(){return typeof __dirname<"u"?__dirname:(0,b.dirname)((0,Ie.fileURLToPath)(ze.url))}var Qe=Je(),v=M.get("CLAUDE_MEM_DATA_DIR"),pe=process.env.CLAUDE_CONFIG_DIR||(0,b.join)((0,Ne.homedir)(),".claude"),St=(0,b.join)(v,"archives"),ft=(0,b.join)(v,"logs"),bt=(0,b.join)(v,"trash"),Ot=(0,b.join)(v,"backups"),Rt=(0,b.join)(v,"modes"),Nt=(0,b.join)(v,"settings.json"),Le=(0,b.join)(v,"claude-mem.db"),At=(0,b.join)(v,"vector-db"),It=(0,b.join)(pe,"settings.json"),Lt=(0,b.join)(pe,"commands"),Ct=(0,b.join)(pe,"CLAUDE.md");function Ce(d){(0,Ae.mkdirSync)(d,{recursive:!0})}function Me(){return(0,b.join)(Qe,"..")}var Z=class{db;constructor(e=Le){e!==":memory:"&&Ce(v),this.db=new ve.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.db.run("PRAGMA synchronous = NORMAL"),this.db.run("PRAGMA foreign_keys = ON"),this.initializeSchema(),this.ensureWorkerPortColumn(),this.ensurePromptTrackingColumns(),this.removeSessionSummariesUniqueConstraint(),this.addObservationHierarchicalFields(),this.makeObservationsTextNullable(),this.createUserPromptsTable(),this.ensureDiscoveryTokensColumn(),this.createPendingMessagesTable()}initializeSchema(){try{this.db.run(`
CREATE TABLE IF NOT EXISTS schema_versions (
id INTEGER PRIMARY KEY,