Skip to content

Commit aa5488c

Browse files
satyakighZee2413
authored andcommitted
Fix metric and export logs to file to support customer reach outs
1 parent 5383b19 commit aa5488c

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

src/handlers/ConfigurationHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ const log = LoggerFactory.getLogger('ConfigurationHandler');
77

88
export function configurationHandler(components: ServerComponents): (params: DidChangeConfigurationParams) => void {
99
return (_params: DidChangeConfigurationParams): void => {
10+
TelemetryService.instance.get('ConfigurationHandler').count('count', 1);
1011
// Pull configuration from LSP workspace and notify all components via subscriptions (fire-and-forget)
1112
components.settingsManager.syncConfiguration().catch((error) => {
12-
TelemetryService.instance.get('ConfigurationHandler').count('count', 1);
1313
log.error(error, `Failed to sync configuration`);
1414
});
1515
};

src/telemetry/LoggerFactory.ts

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
2+
import { readdir, stat, unlink, readFile, writeFile } from 'fs/promises';
3+
import { join } from 'path';
4+
import { DateTime } from 'luxon';
25
import pino, { LevelWithSilent, Logger } from 'pino';
3-
import { ExtensionName } from '../utils/ExtensionConfig';
4-
import { AwsMetadata, TelemetrySettings } from './TelemetryConfig';
6+
import { pathToArtifact } from '../utils/ArtifactsDir';
7+
import { ExtensionId, ExtensionName } from '../utils/ExtensionConfig';
8+
import { TelemetrySettings, AwsMetadata } from './TelemetryConfig';
59

610
export const LogLevel: Record<LevelWithSilent, number> = {
711
silent: 0,
@@ -14,6 +18,9 @@ export const LogLevel: Record<LevelWithSilent, number> = {
1418
} as const;
1519

1620
export class LoggerFactory {
21+
private static readonly LogsDirectory = pathToArtifact('logs');
22+
private static readonly MaxFileSize = 100 * 1024 * 1024; // 100MB
23+
1724
private static readonly _instance: LoggerFactory = new LoggerFactory();
1825

1926
private readonly baseLogger: Logger;
@@ -27,15 +34,56 @@ export class LoggerFactory {
2734
name: ExtensionName,
2835
level: this.logLevel,
2936
transport: {
30-
target: 'pino-pretty',
31-
options: {
32-
colorize: false,
33-
translateTime: 'SYS:hh:MM:ss TT',
34-
ignore: 'pid,hostname,name,clazz',
35-
messageFormat: '[{clazz}] {msg}',
36-
},
37+
targets: [
38+
{
39+
target: 'pino-pretty',
40+
options: {
41+
colorize: false,
42+
translateTime: 'SYS:hh:MM:ss TT',
43+
ignore: 'pid,hostname,name,clazz',
44+
messageFormat: '[{clazz}] {msg}',
45+
},
46+
},
47+
{
48+
target: 'pino/file',
49+
options: {
50+
destination: join(
51+
LoggerFactory.LogsDirectory,
52+
`${ExtensionId}-${DateTime.utc().toFormat('yyyy-MM-dd')}.log`,
53+
),
54+
mkdir: true,
55+
},
56+
},
57+
],
3758
},
3859
});
60+
61+
void this.cleanOldLogs();
62+
}
63+
64+
private async cleanOldLogs() {
65+
try {
66+
const files = await readdir(LoggerFactory.LogsDirectory);
67+
const oneWeekAgo = DateTime.utc().minus({ weeks: 1 });
68+
69+
for (const file of files) {
70+
if (!file.endsWith('.log')) continue;
71+
72+
const filePath = join(LoggerFactory.LogsDirectory, file);
73+
const stats = await stat(filePath);
74+
75+
if (DateTime.fromJSDate(stats.mtime) < oneWeekAgo) {
76+
await unlink(filePath);
77+
} else if (stats.size > LoggerFactory.MaxFileSize) {
78+
const content = await readFile(filePath, 'utf8');
79+
const lines = content.split('\n');
80+
const trimmed = lines.slice(-Math.floor(lines.length / 2)).join('\n');
81+
await writeFile(filePath, trimmed);
82+
}
83+
}
84+
} catch (err) {
85+
this.baseLogger.error(err, 'Error cleaning up old logs');
86+
}
3987
}
4088

4189
private reconfigure(newLevel: LevelWithSilent) {

0 commit comments

Comments
 (0)