Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4617974

Browse files
committed
feat: create memory logger
1 parent9f918b8 commit4617974

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

‎src/extension.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ import { Remote } from "./remote"
1111
import{Storage}from"./storage"
1212
import{toSafeHost}from"./util"
1313
import{WorkspaceQuery,WorkspaceProvider}from"./workspacesProvider"
14+
import{getMemoryLogger}from"./memoryLogger"
1415

1516
exportasyncfunctionactivate(ctx:vscode.ExtensionContext):Promise<void>{
17+
// Initialize the memory logger right when the extension starts.
18+
getMemoryLogger();
19+
1620
// The Remote SSH extension's proposed APIs are used to override the SSH host
1721
// name in VS Code itself. It's visually unappealing having a lengthy name!
1822
//

‎src/memoryLogger.ts‎

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import*asvscodefrom"vscode"
2+
import*asosfrom"os"
3+
import*aspathfrom"path"
4+
import*asfsfrom"fs/promises"
5+
6+
/**
7+
* A class for tracking memory usage and logging resource lifecycles
8+
* to help identify memory leaks in the extension.
9+
*/
10+
exportclassMemoryLogger{
11+
privateoutputChannel:vscode.OutputChannel
12+
privatelogFile:string|undefined
13+
privateresourceCounts=newMap<string,number>()
14+
privatestartTime:number=Date.now()
15+
privatelogInterval:NodeJS.Timeout|undefined
16+
privatedisposed:boolean=false
17+
18+
constructor(){
19+
this.outputChannel=vscode.window.createOutputChannel("Coder Memory Logging")
20+
this.outputChannel.show()
21+
22+
// Setup periodic logging of memory usage
23+
this.startPeriodicLogging()
24+
}
25+
26+
/**
27+
* Start logging memory usage periodically
28+
*/
29+
privatestartPeriodicLogging(intervalMs=60000){
30+
if(this.logInterval){
31+
clearInterval(this.logInterval)
32+
}
33+
34+
this.logInterval=setInterval(()=>{
35+
if(this.disposed)return
36+
this.logMemoryUsage("PERIODIC")
37+
this.logResourceCounts()
38+
},intervalMs)
39+
}
40+
41+
/**
42+
* Initialize the log file for persistent logging
43+
*/
44+
publicasyncinitLogFile(globalStoragePath:string):Promise<void>{
45+
try{
46+
constlogDir=path.join(globalStoragePath,"logs")
47+
awaitfs.mkdir(logDir,{recursive:true})
48+
49+
this.logFile=path.join(logDir,`memory-log-${newDate().toISOString().replace(/[:.]/g,"-")}.txt`)
50+
51+
awaitthis.writeToLogFile("Memory logging initialized")
52+
this.info("Memory logging initialized to file: "+this.logFile)
53+
54+
// Log initial memory state
55+
this.logMemoryUsage("INIT")
56+
}catch(err){
57+
this.error(`Failed to initialize log file:${err}`)
58+
}
59+
}
60+
61+
/**
62+
* Log a new resource creation
63+
*/
64+
publictrackResourceCreated(resourceType:string,id:string=""):void{
65+
constcount=(this.resourceCounts.get(resourceType)||0)+1
66+
this.resourceCounts.set(resourceType,count)
67+
this.info(`RESOURCE_CREATED:${resourceType}${id ?":"+id :""} (Total:${count})`)
68+
}
69+
70+
/**
71+
* Log a resource disposal
72+
*/
73+
publictrackResourceDisposed(resourceType:string,id:string=""):void{
74+
constcount=Math.max(0,(this.resourceCounts.get(resourceType)||1)-1)
75+
if(count===0){
76+
this.resourceCounts.delete(resourceType)
77+
}else{
78+
this.resourceCounts.set(resourceType,count)
79+
}
80+
81+
this.info(`RESOURCE_DISPOSED:${resourceType}${id ?":"+id :""} (Remaining:${count})`)
82+
}
83+
84+
/**
85+
* Log error with memory usage
86+
*/
87+
publicerror(message:string,error?:unknown):void{
88+
consterrorMsg=error ?`:${errorinstanceofError ?error.stack||error.message :String(error)}` :""
89+
constfullMessage=`[ERROR]${message}${errorMsg}`
90+
91+
this.outputChannel.appendLine(fullMessage)
92+
this.writeToLogFile(fullMessage)
93+
this.logMemoryUsage("ERROR")
94+
}
95+
96+
/**
97+
* Log info with timestamp
98+
*/
99+
publicinfo(message:string):void{
100+
constfullMessage=`[INFO]${message}`
101+
this.outputChannel.appendLine(fullMessage)
102+
this.writeToLogFile(fullMessage)
103+
}
104+
105+
/**
106+
* Log debug info (only to file)
107+
*/
108+
publicdebug(message:string):void{
109+
constfullMessage=`[DEBUG]${message}`
110+
this.writeToLogFile(fullMessage)
111+
}
112+
113+
/**
114+
* Log current memory usage
115+
*/
116+
publiclogMemoryUsage(context:string):void{
117+
try{
118+
constmemoryUsage=process.memoryUsage()
119+
constnodeMemoryInfo={
120+
rss:`${(memoryUsage.rss/1024/1024).toFixed(2)}MB`,
121+
heapTotal:`${(memoryUsage.heapTotal/1024/1024).toFixed(2)}MB`,
122+
heapUsed:`${(memoryUsage.heapUsed/1024/1024).toFixed(2)}MB`,
123+
external:`${(memoryUsage.external/1024/1024).toFixed(2)}MB`,
124+
uptime:formatDuration(process.uptime()*1000),
125+
totalUptime:formatDuration(Date.now()-this.startTime)
126+
}
127+
128+
constsystemMemoryInfo={
129+
totalMem:`${(os.totalmem()/1024/1024/1024).toFixed(2)}GB`,
130+
freeMem:`${(os.freemem()/1024/1024/1024).toFixed(2)}GB`,
131+
loadAvg:os.loadavg().map(load=>load.toFixed(2)).join(", ")
132+
}
133+
134+
constmemoryLog=`[MEMORY:${context}] Node:${JSON.stringify(nodeMemoryInfo)} | System:${JSON.stringify(systemMemoryInfo)}`
135+
this.outputChannel.appendLine(memoryLog)
136+
this.writeToLogFile(memoryLog)
137+
}catch(err){
138+
this.outputChannel.appendLine(`[ERROR] Failed to log memory usage:${err}`)
139+
}
140+
}
141+
142+
/**
143+
* Log the current counts of active resources
144+
*/
145+
privatelogResourceCounts():void{
146+
constcounts=Array.from(this.resourceCounts.entries())
147+
.map(([type,count])=>`${type}=${count}`)
148+
.join(", ")
149+
150+
constmessage=`[RESOURCES] Active resources:${counts||"none"}`
151+
this.outputChannel.appendLine(message)
152+
this.writeToLogFile(message)
153+
}
154+
155+
/**
156+
* Write to log file
157+
*/
158+
privateasyncwriteToLogFile(message:string):Promise<void>{
159+
if(!this.logFile)return
160+
161+
try{
162+
consttimestamp=newDate().toISOString()
163+
awaitfs.appendFile(this.logFile,`${timestamp}${message}\n`)
164+
}catch(err){
165+
// Don't recursively call this.error to avoid potential loops
166+
this.outputChannel.appendLine(`[ERROR] Failed to write to log file:${err}`)
167+
}
168+
}
169+
170+
/**
171+
* Show the log in the output channel
172+
*/
173+
publicshow():void{
174+
this.outputChannel.show()
175+
}
176+
177+
/**
178+
* Dispose of the logger
179+
*/
180+
publicdispose():void{
181+
this.disposed=true
182+
if(this.logInterval){
183+
clearInterval(this.logInterval)
184+
this.logInterval=undefined
185+
}
186+
this.logMemoryUsage("DISPOSE")
187+
this.outputChannel.dispose()
188+
}
189+
}
190+
191+
/**
192+
* Format duration in milliseconds to a human-readable string
193+
*/
194+
functionformatDuration(ms:number):string{
195+
constseconds=Math.floor((ms/1000)%60)
196+
constminutes=Math.floor((ms/(1000*60))%60)
197+
consthours=Math.floor((ms/(1000*60*60))%24)
198+
constdays=Math.floor(ms/(1000*60*60*24))
199+
200+
return`${days}d${hours}h${minutes}m${seconds}s`
201+
}
202+
203+
// Singleton instance
204+
letinstance:MemoryLogger|undefined
205+
206+
/**
207+
* Get or initialize the memory logger instance
208+
*/
209+
exportfunctiongetMemoryLogger():MemoryLogger{
210+
if(!instance){
211+
instance=newMemoryLogger()
212+
}
213+
returninstance
214+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp