Skip to content

Commit 5a62e74

Browse files
author
Keegan Irby
committed
Add StatusBar Item
1 parent 66b2f46 commit 5a62e74

File tree

3 files changed

+131
-21
lines changed

3 files changed

+131
-21
lines changed

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

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ import { TailLogGroupWizard } from '../wizard/tailLogGroupWizard'
88
import { CancellationError } from '../../../shared/utilities/timeoutUtils'
99
import { LiveTailSession, LiveTailSessionConfiguration } from '../registry/liveTailSession'
1010
import { LiveTailSessionRegistry } from '../registry/liveTailSessionRegistry'
11-
import { LiveTailSessionLogEvent, StartLiveTailResponseStream } from '@aws-sdk/client-cloudwatch-logs'
12-
import { ToolkitError } from '../../../shared'
11+
import {
12+
LiveTailSessionLogEvent,
13+
LiveTailSessionUpdate,
14+
StartLiveTailResponseStream,
15+
} from '@aws-sdk/client-cloudwatch-logs'
16+
import { globals, ToolkitError } from '../../../shared'
1317

1418
export async function tailLogGroup(
1519
registry: LiveTailSessionRegistry,
@@ -35,13 +39,17 @@ export async function tailLogGroup(
3539
registry.set(session.uri, session)
3640

3741
const document = await prepareDocument(session)
38-
registerTabChangeCallback(session, registry, document)
42+
const timer = startSessionTimer(session)
43+
hideShowStatusBarItemsOnActiveEditor(session, document)
44+
registerTabChangeCallback(session, registry, document, timer)
45+
3946
const stream = await session.startLiveTailSession()
4047

41-
await handleSessionStream(stream, document, session)
48+
await handleSessionStream(stream, document, session, timer)
4249
}
4350

44-
export function closeSession(sessionUri: vscode.Uri, registry: LiveTailSessionRegistry) {
51+
export function closeSession(sessionUri: vscode.Uri, registry: LiveTailSessionRegistry, timer: NodeJS.Timer) {
52+
globals.clock.clearInterval(timer)
4553
const session = registry.get(sessionUri)
4654
if (session === undefined) {
4755
throw new ToolkitError(`No LiveTail session found for URI: ${sessionUri.toString()}`)
@@ -63,27 +71,34 @@ async function prepareDocument(session: LiveTailSession): Promise<vscode.TextDoc
6371
await clearDocument(textDocument)
6472
await vscode.window.showTextDocument(textDocument, { preview: false })
6573
await vscode.languages.setTextDocumentLanguage(textDocument, 'log')
74+
session.showStatusBarItem(true)
6675
return textDocument
6776
}
6877

6978
async function handleSessionStream(
7079
stream: AsyncIterable<StartLiveTailResponseStream>,
7180
document: vscode.TextDocument,
72-
session: LiveTailSession
81+
session: LiveTailSession,
82+
timer: NodeJS.Timer
7383
) {
74-
for await (const event of stream) {
75-
if (event.sessionUpdate !== undefined && event.sessionUpdate.sessionResults !== undefined) {
76-
const formattedLogEvents = event.sessionUpdate.sessionResults.map<string>((logEvent) =>
77-
formatLogEvent(logEvent)
78-
)
79-
if (formattedLogEvents.length !== 0) {
80-
//Determine should scroll before adding new lines to doc because adding large
81-
//amount of new lines can push bottom of file out of view before scrolling.
82-
const editorsToScroll = getTextEditorsToScroll(document)
83-
await updateTextDocumentWithNewLogEvents(formattedLogEvents, document, session.maxLines)
84-
editorsToScroll.forEach(scrollTextEditorToBottom)
84+
try {
85+
for await (const event of stream) {
86+
if (event.sessionUpdate !== undefined && event.sessionUpdate.sessionResults !== undefined) {
87+
const formattedLogEvents = event.sessionUpdate.sessionResults.map<string>((logEvent) =>
88+
formatLogEvent(logEvent)
89+
)
90+
if (formattedLogEvents.length !== 0) {
91+
//Determine should scroll before adding new lines to doc because adding large
92+
//amount of new lines can push bottom of file out of view before scrolling.
93+
const editorsToScroll = getTextEditorsToScroll(document)
94+
await updateTextDocumentWithNewLogEvents(formattedLogEvents, document, session.maxLines)
95+
editorsToScroll.forEach(scrollTextEditorToBottom)
96+
}
97+
updateStatusBarItemsOnStreamEvent(session, event.sessionUpdate)
8598
}
8699
}
100+
} finally {
101+
globals.clock.clearInterval(timer)
87102
}
88103
}
89104

@@ -147,6 +162,38 @@ function trimOldestLines(
147162
edit.delete(document.uri, range)
148163
}
149164

165+
function updateStatusBarItemsOnStreamEvent(session: LiveTailSession, event: LiveTailSessionUpdate) {
166+
updateIsSampled(session, event)
167+
updateEventRate(session, event)
168+
}
169+
170+
function updateIsSampled(session: LiveTailSession, event: LiveTailSessionUpdate) {
171+
session.isSampled =
172+
event.sessionMetadata === undefined || event.sessionMetadata.sampled === undefined
173+
? false
174+
: event.sessionMetadata.sampled
175+
}
176+
177+
function updateEventRate(session: LiveTailSession, event: LiveTailSessionUpdate) {
178+
session.eventRate = event.sessionResults === undefined ? 0 : event.sessionResults.length
179+
}
180+
181+
function hideShowStatusBarItemsOnActiveEditor(session: LiveTailSession, document: vscode.TextDocument) {
182+
vscode.window.onDidChangeActiveTextEditor((editor) => {
183+
if (editor?.document === document) {
184+
session.showStatusBarItem(true)
185+
} else {
186+
session.showStatusBarItem(false)
187+
}
188+
})
189+
}
190+
191+
function startSessionTimer(session: LiveTailSession): NodeJS.Timer {
192+
return globals.clock.setInterval(() => {
193+
session.updateStatusBarItemText()
194+
}, 500)
195+
}
196+
150197
/**
151198
* The LiveTail session should be automatically closed if the user does not have the session's
152199
* document in any Tab in their editor.
@@ -162,12 +209,13 @@ function trimOldestLines(
162209
function registerTabChangeCallback(
163210
session: LiveTailSession,
164211
registry: LiveTailSessionRegistry,
165-
document: vscode.TextDocument
212+
document: vscode.TextDocument,
213+
timer: NodeJS.Timer
166214
) {
167215
vscode.window.tabGroups.onDidChangeTabs((tabEvent) => {
168216
const isOpen = isLiveTailSessionOpenInAnyTab(session)
169217
if (!isOpen) {
170-
closeSession(session.uri, registry)
218+
closeSession(session.uri, registry, timer)
171219
void clearDocument(document)
172220
}
173221
})

packages/core/src/awsService/cloudWatchLogs/registry/liveTailSession.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from '@aws-sdk/client-cloudwatch-logs'
1111
import { LogStreamFilterResponse } from '../wizard/liveTailLogStreamSubmenu'
1212
import { CloudWatchLogsSettings } from '../cloudWatchLogsUtils'
13-
import { Settings, ToolkitError } from '../../../shared'
13+
import { convertToTimeString, Settings, ToolkitError } from '../../../shared'
1414
import { createLiveTailURIFromArgs } from './liveTailSessionRegistry'
1515
import { getUserAgent } from '../../../shared/telemetry/util'
1616

@@ -33,6 +33,11 @@ export class LiveTailSession {
3333
private logEventFilterPattern?: string
3434
private _maxLines: number
3535
private _uri: vscode.Uri
36+
private statusBarItem: vscode.StatusBarItem
37+
private startTime: number | undefined
38+
private endTime: number | undefined
39+
private _eventRate: number
40+
private _isSampled: boolean
3641

3742
static settings = new CloudWatchLogsSettings(Settings.instance)
3843

@@ -48,6 +53,9 @@ export class LiveTailSession {
4853
}
4954
this._maxLines = LiveTailSession.settings.get('limit', 10000)
5055
this._uri = createLiveTailURIFromArgs(configuration)
56+
this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 0)
57+
this._eventRate = 0
58+
this._isSampled = false
5159
}
5260

5361
public get maxLines() {
@@ -62,6 +70,14 @@ export class LiveTailSession {
6270
return this._logGroupName
6371
}
6472

73+
public set eventRate(rate: number) {
74+
this._eventRate = rate
75+
}
76+
77+
public set isSampled(isSampled: boolean) {
78+
this._isSampled = isSampled
79+
}
80+
6581
public async startLiveTailSession(): Promise<AsyncIterable<StartLiveTailResponseStream>> {
6682
const command = this.buildStartLiveTailCommand()
6783
try {
@@ -71,17 +87,33 @@ export class LiveTailSession {
7187
if (!commandOutput.responseStream) {
7288
throw new ToolkitError('LiveTail session response stream is undefined.')
7389
}
90+
this.startTime = Date.now()
91+
this.endTime = undefined
7492
return commandOutput.responseStream
7593
} catch (e) {
7694
throw new ToolkitError('Encountered error while trying to start LiveTail session.')
7795
}
7896
}
7997

8098
public stopLiveTailSession() {
99+
this.endTime = Date.now()
100+
this.statusBarItem.dispose()
81101
this.liveTailClient.abortController.abort()
82102
this.liveTailClient.cwlClient.destroy()
83103
}
84104

105+
public getLiveTailSessionDuration(): number {
106+
//Never started
107+
if (this.startTime === undefined) {
108+
return 0
109+
}
110+
//Currently running
111+
if (this.endTime === undefined) {
112+
return Date.now() - this.startTime
113+
}
114+
return this.endTime - this.startTime
115+
}
116+
85117
private buildStartLiveTailCommand(): StartLiveTailCommand {
86118
let logStreamNamePrefix = undefined
87119
let logStreamName = undefined
@@ -102,4 +134,15 @@ export class LiveTailSession {
102134
logEventFilterPattern: this.logEventFilterPattern ? this.logEventFilterPattern : undefined,
103135
})
104136
}
137+
138+
public showStatusBarItem(shouldShow: boolean) {
139+
shouldShow ? this.statusBarItem.show() : this.statusBarItem.hide()
140+
}
141+
142+
public updateStatusBarItemText() {
143+
const elapsedTime = this.getLiveTailSessionDuration()
144+
const timeString = convertToTimeString(elapsedTime)
145+
const sampledString = this._isSampled ? 'Yes' : 'No'
146+
this.statusBarItem.text = `Tailing Session: ${timeString}, ${this._eventRate} events/sec, Sampled: ${sampledString}`
147+
}
105148
}

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import * as sinon from 'sinon'
7+
import * as FakeTimers from '@sinonjs/fake-timers'
78
import * as vscode from 'vscode'
89

910
import assert from 'assert'
@@ -18,6 +19,7 @@ import {
1819
} from '../../../../awsService/cloudWatchLogs/wizard/tailLogGroupWizard'
1920
import { getTestWindow } from '../../../shared/vscode/window'
2021
import { CloudWatchLogsSettings } from '../../../../awsService/cloudWatchLogs/cloudWatchLogsUtils'
22+
import { installFakeClock } from '../../../testUtil'
2123

2224
describe('TailLogGroup', function () {
2325
const testLogGroup = 'test-log-group'
@@ -31,11 +33,22 @@ describe('TailLogGroup', function () {
3133
let cloudwatchSettingsSpy: sinon.SinonSpy
3234
let wizardSpy: sinon.SinonSpy
3335

36+
let clock: FakeTimers.InstalledClock
37+
38+
before(function () {
39+
clock = installFakeClock()
40+
})
41+
3442
beforeEach(function () {
43+
clock.reset()
3544
sandbox = sinon.createSandbox()
3645
registry = new LiveTailSessionRegistry()
3746
})
3847

48+
after(function () {
49+
clock.uninstall()
50+
})
51+
3952
afterEach(function () {
4053
sandbox.restore()
4154
})
@@ -112,15 +125,18 @@ describe('TailLogGroup', function () {
112125
.callsFake(async function () {
113126
return
114127
})
128+
// const fakeClock = installFakeClock()
129+
const timer = setInterval(() => {}, 1000)
115130
const session = new LiveTailSession({
116131
logGroupName: testLogGroup,
117132
region: testRegion,
118133
})
119134
registry.set(session.uri, session)
120135

121-
closeSession(session.uri, registry)
136+
closeSession(session.uri, registry, timer)
122137
assert.strictEqual(0, registry.size)
123138
assert.strictEqual(true, stopLiveTailSessionSpy.calledOnce)
139+
assert.strictEqual(0, clock.countTimers())
124140
})
125141

126142
it('clearDocument clears all text from document', async function () {
@@ -172,6 +188,9 @@ describe('TailLogGroup', function () {
172188
const updateFrames: StartLiveTailResponseStream[] = logEvents.map((event) => {
173189
return {
174190
sessionUpdate: {
191+
sessionMetadata: {
192+
sampled: false,
193+
},
175194
sessionResults: [event],
176195
},
177196
}

0 commit comments

Comments
 (0)