Skip to content

Commit f1e4268

Browse files
keeganirbykaranA-aws
authored andcommitted
feat(cwl): Add line trimming to LiveTail when limit is reached (aws#5837)
## Problem * LiveTail sessions can run for a long time, on LogGroups that have a high volume of LogEvents. We want to not infinitely add logs to a TextDocument, leading to memory issues within VSCode. ## Solution Users can configure a `limit` preference (default: 10000 , max 10000 , min: 1000). When the number of lines in a Live Tail session (number of LogEvents) reaches the limit, the 'N' oldest logEvents will be removed, to fit in the 'N' newest events coming in from the response stream.
1 parent 690135f commit f1e4268

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

packages/core/src/awsService/cloudWatchLogs/commands/tailLogGroup.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,25 @@ async function updateTextDocumentWithNewLogEvents(
108108
formattedLogEvents.forEach((formattedLogEvent) =>
109109
edit.insert(document.uri, new vscode.Position(document.lineCount, 0), formattedLogEvent)
110110
)
111+
if (document.lineCount + formattedLogEvents.length > maxLines) {
112+
trimOldestLines(formattedLogEvents.length, maxLines, document, edit)
113+
}
111114
await vscode.workspace.applyEdit(edit)
112115
}
113116

117+
function trimOldestLines(
118+
numNewLines: number,
119+
maxLines: number,
120+
document: vscode.TextDocument,
121+
edit: vscode.WorkspaceEdit
122+
) {
123+
const numLinesToTrim = document.lineCount + numNewLines - maxLines
124+
const startPosition = new vscode.Position(0, 0)
125+
const endPosition = new vscode.Position(numLinesToTrim, 0)
126+
const range = new vscode.Range(startPosition, endPosition)
127+
edit.delete(document.uri, range)
128+
}
129+
114130
/**
115131
* The LiveTail session should be automatically closed if the user does not have the session's
116132
* document in any Tab in their editor.

packages/core/src/test/awsService/cloudWatchLogs/commands/tailLogGroup.test.ts

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as vscode from 'vscode'
88

99
import assert from 'assert'
1010
import { clearDocument, closeSession, tailLogGroup } from '../../../../awsService/cloudWatchLogs/commands/tailLogGroup'
11-
import { StartLiveTailResponseStream } from '@aws-sdk/client-cloudwatch-logs'
11+
import { LiveTailSessionLogEvent, StartLiveTailResponseStream } from '@aws-sdk/client-cloudwatch-logs'
1212
import { LiveTailSessionRegistry } from '../../../../awsService/cloudWatchLogs/registry/liveTailSessionRegistry'
1313
import { LiveTailSession } from '../../../../awsService/cloudWatchLogs/registry/liveTailSession'
1414
import { asyncGenerator } from '../../../../shared/utilities/collectionUtils'
@@ -17,6 +17,7 @@ import {
1717
TailLogGroupWizardResponse,
1818
} from '../../../../awsService/cloudWatchLogs/wizard/tailLogGroupWizard'
1919
import { getTestWindow } from '../../../shared/vscode/window'
20+
import { CloudWatchLogsSettings } from '../../../../awsService/cloudWatchLogs/cloudWatchLogsUtils'
2021

2122
describe('TailLogGroup', function () {
2223
const testLogGroup = 'test-log-group'
@@ -27,6 +28,7 @@ describe('TailLogGroup', function () {
2728
let registry: LiveTailSessionRegistry
2829
let startLiveTailSessionSpy: sinon.SinonSpy
2930
let stopLiveTailSessionSpy: sinon.SinonSpy
31+
let cloudwatchSettingsSpy: sinon.SinonSpy
3032
let wizardSpy: sinon.SinonSpy
3133

3234
beforeEach(function () {
@@ -42,21 +44,42 @@ describe('TailLogGroup', function () {
4244
wizardSpy = sandbox.stub(TailLogGroupWizard.prototype, 'run').callsFake(async function () {
4345
return getTestWizardResponse()
4446
})
47+
const testMessage2 = `${testMessage}-2`
48+
const testMessage3 = `${testMessage}-3`
4549
startLiveTailSessionSpy = sandbox
4650
.stub(LiveTailSession.prototype, 'startLiveTailSession')
4751
.callsFake(async function () {
48-
return getTestResponseStream()
52+
return getTestResponseStream([
53+
{
54+
message: testMessage,
55+
timestamp: 876830400000,
56+
},
57+
{
58+
message: testMessage2,
59+
timestamp: 876830402000,
60+
},
61+
{
62+
message: testMessage3,
63+
timestamp: 876830403000,
64+
},
65+
])
4966
})
5067
stopLiveTailSessionSpy = sandbox
5168
.stub(LiveTailSession.prototype, 'stopLiveTailSession')
5269
.callsFake(async function () {
5370
return
5471
})
72+
73+
//Set maxLines to 1.
74+
cloudwatchSettingsSpy = sandbox.stub(CloudWatchLogsSettings.prototype, 'get').callsFake(() => {
75+
return 1
76+
})
5577
await tailLogGroup(registry, {
5678
groupName: testLogGroup,
5779
regionName: testRegion,
5880
})
5981
assert.strictEqual(wizardSpy.calledOnce, true)
82+
assert.strictEqual(cloudwatchSettingsSpy.calledOnce, true)
6083
assert.strictEqual(startLiveTailSessionSpy.calledOnce, true)
6184
assert.strictEqual(registry.size, 1)
6285

@@ -69,7 +92,8 @@ describe('TailLogGroup', function () {
6992
}
7093
const document = getTestWindow().activeTextEditor?.document
7194
assert.strictEqual(sessionUri.toString(), document?.uri.toString())
72-
assert.strictEqual(document?.getText().trim(), `12:00:00\t${testMessage}`)
95+
//Test responseStream has 3 events, maxLines is set to 1. Only 3rd event should be in doc.
96+
assert.strictEqual(document?.getText().trim(), `12:00:03\t${testMessage3}`)
7397

7498
//Test that closing all tabs the session's document is open in will cause the session to close
7599
const window = getTestWindow()
@@ -136,23 +160,23 @@ describe('TailLogGroup', function () {
136160
}
137161
}
138162

139-
function getTestResponseStream(): AsyncIterable<StartLiveTailResponseStream> {
163+
//Creates a test response stream. Each log event provided will be its own "frame" of the input stream.
164+
function getTestResponseStream(logEvents: LiveTailSessionLogEvent[]): AsyncIterable<StartLiveTailResponseStream> {
140165
const sessionStartFrame: StartLiveTailResponseStream = {
141166
sessionStart: {
142167
logGroupIdentifiers: [testLogGroup],
143168
},
144169
sessionUpdate: undefined,
145170
}
146-
const sessionUpdateFrame: StartLiveTailResponseStream = {
147-
sessionUpdate: {
148-
sessionResults: [
149-
{
150-
message: testMessage,
151-
timestamp: 876830400000,
152-
},
153-
],
154-
},
155-
}
156-
return asyncGenerator([sessionStartFrame, sessionUpdateFrame])
171+
172+
const updateFrames: StartLiveTailResponseStream[] = logEvents.map((event) => {
173+
return {
174+
sessionUpdate: {
175+
sessionResults: [event],
176+
},
177+
}
178+
})
179+
180+
return asyncGenerator([sessionStartFrame, ...updateFrames])
157181
}
158182
})

0 commit comments

Comments
 (0)