Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/log/common/fileLog.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { ThrottledDelayer } from '../../../base/common/async.js';
7
import { VSBuffer } from '../../../base/common/buffer.js';
8
import { basename, dirname, joinPath } from '../../../base/common/resources.js';
9
import { URI } from '../../../base/common/uri.js';
10
import { ByteSize, FileOperationError, FileOperationResult, IFileService, whenProviderRegistered } from '../../files/common/files.js';
11
import { BufferLogger } from './bufferLog.js';
12
import { AbstractLoggerService, AbstractMessageLogger, ILogger, ILoggerOptions, ILoggerService, LogLevel } from './log.js';
13
14
const MAX_FILE_SIZE = 5 * ByteSize.MB;
15
16
class FileLogger extends AbstractMessageLogger implements ILogger {
17
18
private readonly initializePromise: Promise<void>;
19
private readonly flushDelayer: ThrottledDelayer<void>;
20
private backupIndex: number = 1;
21
private buffer: string = '';
22
23
constructor(
24
private readonly resource: URI,
25
level: LogLevel,
26
private readonly donotUseFormatters: boolean,
27
@IFileService private readonly fileService: IFileService
28
) {
29
super();
30
this.setLevel(level);
31
this.flushDelayer = new ThrottledDelayer<void>(100 /* buffer saves over a short time */);
32
this.initializePromise = this.initialize();
33
}
34
35
override async flush(): Promise<void> {
36
if (!this.buffer) {
37
return;
38
}
39
await this.initializePromise;
40
let content = await this.loadContent();
41
if (content.length > MAX_FILE_SIZE) {
42
await this.fileService.writeFile(this.getBackupResource(), VSBuffer.fromString(content));
43
content = '';
44
}
45
if (this.buffer) {
46
content += this.buffer;
47
this.buffer = '';
48
await this.fileService.writeFile(this.resource, VSBuffer.fromString(content));
49
}
50
}
51
52
private async initialize(): Promise<void> {
53
try {
54
await this.fileService.createFile(this.resource);
55
} catch (error) {
56
if ((<FileOperationError>error).fileOperationResult !== FileOperationResult.FILE_MODIFIED_SINCE) {
57
throw error;
58
}
59
}
60
}
61
62
protected log(level: LogLevel, message: string): void {
63
if (this.donotUseFormatters) {
64
this.buffer += message;
65
} else {
66
this.buffer += `${this.getCurrentTimestamp()} [${this.stringifyLogLevel(level)}] ${message}\n`;
67
}
68
this.flushDelayer.trigger(() => this.flush());
69
}
70
71
private getCurrentTimestamp(): string {
72
const toTwoDigits = (v: number) => v < 10 ? `0${v}` : v;
73
const toThreeDigits = (v: number) => v < 10 ? `00${v}` : v < 100 ? `0${v}` : v;
74
const currentTime = new Date();
75
return `${currentTime.getFullYear()}-${toTwoDigits(currentTime.getMonth() + 1)}-${toTwoDigits(currentTime.getDate())} ${toTwoDigits(currentTime.getHours())}:${toTwoDigits(currentTime.getMinutes())}:${toTwoDigits(currentTime.getSeconds())}.${toThreeDigits(currentTime.getMilliseconds())}`;
76
}
77
78
private getBackupResource(): URI {
79
this.backupIndex = this.backupIndex > 5 ? 1 : this.backupIndex;
80
return joinPath(dirname(this.resource), `${basename(this.resource)}_${this.backupIndex++}`);
81
}
82
83
private async loadContent(): Promise<string> {
84
try {
85
const content = await this.fileService.readFile(this.resource);
86
return content.value.toString();
87
} catch (e) {
88
return '';
89
}
90
}
91
92
private stringifyLogLevel(level: LogLevel): string {
93
switch (level) {
94
case LogLevel.Debug: return 'debug';
95
case LogLevel.Error: return 'error';
96
case LogLevel.Info: return 'info';
97
case LogLevel.Trace: return 'trace';
98
case LogLevel.Warning: return 'warning';
99
}
100
return '';
101
}
102
103
}
104
105
export class FileLoggerService extends AbstractLoggerService implements ILoggerService {
106
107
constructor(
108
logLevel: LogLevel,
109
logsHome: URI,
110
private readonly fileService: IFileService,
111
) {
112
super(logLevel, logsHome);
113
}
114
115
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
116
const logger = new BufferLogger(logLevel);
117
whenProviderRegistered(resource, this.fileService).then(() => logger.logger = new FileLogger(resource, logger.getLevel(), !!options?.donotUseFormatters, this.fileService));
118
return logger;
119
}
120
}
121
122