1
>
/*---------------------------------------------------------------------------------------------
ahpJsonlLogger.ts
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 { VSBuffer } from '../../../base/common/buffer.js';
7
>
import { Disposable } from '../../../base/common/lifecycle.js';
8
>
import { MarshalledId } from '../../../base/common/marshallingIds.js';
9
>
import { joinPath } from '../../../base/common/resources.js';
10
>
import { isUriComponents, URI, UriComponents } from '../../../base/common/uri.js';
11
>
import { IFileService, IFileStatWithMetadata } from '../../files/common/files.js';
12
>
import { ILogService } from '../../log/common/log.js';
13
>
14
>
export type AhpLogDirection = 'c2s' | 's2c';
15
>
16
>
interface IAhpLogMeta {
17
>
readonly ts: string;
18
>
readonly dir: AhpLogDirection;
19
>
readonly connectionId: string;
20
>
readonly transport: string;
21
>
readonly byteLength?: number;
22
>
/** Set when oversized string values in the entry were elided (see {@link stringifyAhpLogEntryTruncated}). */
23
>
truncated?: boolean;
24
>
}
25
>
26
>
export interface IAhpJsonlLoggerOptions {
27
>
readonly logsHome: URI;
28
>
readonly connectionId: string;
29
>
readonly transport: string;
30
>
readonly maxFileSizeBytes?: number;
31
>
readonly maxFiles?: number;
32
>
}
33
>
34
>
const AHP_LOG_DIR = 'ahp';
35
>
const DEFAULT_MAX_FILE_SIZE_BYTES = 75 * 1024 * 1024;
36
>
const DEFAULT_MAX_FILES = 5;
37
>
// Cap the size of any single coalesced writeFile to avoid producing huge
38
>
// concatenated VSBuffers (which would just create the GC pressure we're
39
>
// trying to avoid). 1 MiB strikes a balance between amortizing IPC overhead
40
>
// and keeping per-write allocations modest.
41
>
const MAX_BATCH_BYTES = 1024 * 1024;
42
>
43
>
// A single AHP protocol message can be enormous (e.g. a `resourceRead` carrying
44
>
// a base64-encoded file, or an `action` carrying a full session snapshot). We
45
>
// don't want to write hundreds of MB on a single JSONL line — it bloats the log
46
>
// directory and, more importantly, building/holding that line creates exactly
47
>
// the GC pressure these logs are meant to help diagnose. When a serialized
48
>
// entry exceeds this size we re-serialize it with oversized string values
49
>
// elided so the line stays well-formed JSONL.
50
>
const MAX_LOG_LINE_LENGTH = 1024 * 1024;
51
>
// When trimming an oversized entry, individual string values are capped to this
52
>
// length. Generous enough to keep messages useful for debugging.
53
>
const MAX_LOGGED_STRING_LENGTH = 16 * 1024;
54
>
55
>
56
>
export class AhpJsonlLogger extends Disposable {
57
>
58
>
private readonly _directory: URI;
59
>
private readonly _baseName: string;
60
>
private readonly _maxFileSizeBytes: number;
61
>
private readonly _maxFiles: number;
62
>
private _currentFile: URI;
63
>
private _currentSize = 0;
64
>
private _segment = 0;
65
>
private _queue = Promise.resolve();
66
>
private _pending: VSBuffer[] = [];
67
>
private _drainScheduled = false;
68
>
private _folderCreated: Promise<IFileStatWithMetadata> | undefined;
69
>
70
>
constructor(
71
private readonly _options: IAhpJsonlLoggerOptions,
72
@IFileService private readonly _fileService: IFileService,