|
| 1 | +/*! |
| 2 | + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + */ |
| 5 | + |
| 6 | +import * as nls from 'vscode-nls' |
| 7 | +const localize = nls.loadMessageBundle() |
| 8 | + |
| 9 | +import * as vscode from 'vscode' |
| 10 | +import * as moment from 'moment' |
| 11 | +import * as picker from '../../shared/ui/picker' |
| 12 | +import { MultiStepWizard, WizardStep } from '../../shared/wizards/multiStepWizard' |
| 13 | +import { LogGroupNode } from '../explorer/logGroupNode' |
| 14 | +import { CloudWatchLogs } from 'aws-sdk' |
| 15 | +import { ext } from '../../shared/extensionGlobals' |
| 16 | +import { CloudWatchLogsClient } from '../../shared/clients/cloudWatchLogsClient' |
| 17 | +import * as telemetry from '../../shared/telemetry/telemetry' |
| 18 | +import { LOCALIZED_DATE_FORMAT } from '../../shared/constants' |
| 19 | +import { getPaginatedAwsCallIter, IteratorTransformer } from '../../shared/utilities/collectionUtils' |
| 20 | + |
| 21 | +export interface SelectLogStreamResponse { |
| 22 | + region: string |
| 23 | + logGroupName: string |
| 24 | + logStreamName: string |
| 25 | +} |
| 26 | + |
| 27 | +export async function viewLogStream(node: LogGroupNode): Promise<void> { |
| 28 | + let result: telemetry.Result = 'Succeeded' |
| 29 | + const logStreamResponse = await new SelectLogStreamWizard(node).run() |
| 30 | + if (logStreamResponse) { |
| 31 | + vscode.window.showInformationMessage( |
| 32 | + `Not implemented but here's the deets: |
| 33 | +region: ${logStreamResponse.region} |
| 34 | +logGroup: ${logStreamResponse.logGroupName} |
| 35 | +logStream: ${logStreamResponse.logStreamName}` |
| 36 | + ) |
| 37 | + } else { |
| 38 | + result = 'Cancelled' |
| 39 | + } |
| 40 | + |
| 41 | + telemetry.recordCloudwatchlogsOpenStream({ result }) |
| 42 | +} |
| 43 | + |
| 44 | +export interface SelectLogStreamWizardContext { |
| 45 | + pickLogStream(): Promise<string | undefined> |
| 46 | +} |
| 47 | + |
| 48 | +export class DefaultSelectLogStreamWizardContext implements SelectLogStreamWizardContext { |
| 49 | + public constructor(private readonly regionCode: string, private readonly logGroupName: string) {} |
| 50 | + |
| 51 | + public async pickLogStream(): Promise<string | undefined> { |
| 52 | + let telemetryResult: telemetry.Result = 'Succeeded' |
| 53 | + |
| 54 | + const client: CloudWatchLogsClient = ext.toolkitClientBuilder.createCloudWatchLogsClient(this.regionCode) |
| 55 | + const request: CloudWatchLogs.DescribeLogStreamsRequest = { |
| 56 | + logGroupName: this.logGroupName, |
| 57 | + orderBy: 'LastEventTime', |
| 58 | + descending: true, |
| 59 | + } |
| 60 | + const qp = picker.createQuickPick({}) |
| 61 | + const populator = new IteratorTransformer( |
| 62 | + () => |
| 63 | + getPaginatedAwsCallIter({ |
| 64 | + awsCall: request => client.describeLogStreams(request), |
| 65 | + nextTokenNames: { |
| 66 | + request: 'nextToken', |
| 67 | + response: 'nextToken', |
| 68 | + }, |
| 69 | + request, |
| 70 | + }), |
| 71 | + response => convertDescribeLogStreamsToQuickPickItems(response) |
| 72 | + ) |
| 73 | + |
| 74 | + const controller = new picker.IteratingQuickPickController(qp, populator) |
| 75 | + controller.startRequests() |
| 76 | + const choices = await picker.promptUser({ |
| 77 | + picker: qp, |
| 78 | + onDidTriggerButton: (button, resolve, reject) => |
| 79 | + controller.iteratingOnDidTriggerButton(button, resolve, reject), |
| 80 | + }) |
| 81 | + |
| 82 | + const val = picker.verifySinglePickerOutput(choices) |
| 83 | + |
| 84 | + let result = val?.label |
| 85 | + |
| 86 | + // handle no items for a group as a cancel |
| 87 | + if (!result || result === picker.IteratingQuickPickController.NO_ITEMS_ITEM.label) { |
| 88 | + result = undefined |
| 89 | + telemetryResult = 'Cancelled' |
| 90 | + } |
| 91 | + // retry handled by caller -- should this be a "Failed"? |
| 92 | + // of note: we don't track if an error pops up, we just track if the error is selected. |
| 93 | + if (result === picker.IteratingQuickPickController.ERROR_ITEM.label) { |
| 94 | + telemetryResult = 'Failed' |
| 95 | + } |
| 96 | + |
| 97 | + telemetry.recordCloudwatchlogsOpenGroup({ result: telemetryResult }) |
| 98 | + return result |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +export function convertDescribeLogStreamsToQuickPickItems( |
| 103 | + response: CloudWatchLogs.DescribeLogStreamsResponse |
| 104 | +): vscode.QuickPickItem[] { |
| 105 | + return (response.logStreams ?? []).map<vscode.QuickPickItem>(stream => ({ |
| 106 | + label: stream.logStreamName!, |
| 107 | + detail: stream.lastEventTimestamp |
| 108 | + ? moment(stream.lastEventTimestamp).format(LOCALIZED_DATE_FORMAT) |
| 109 | + : localize('aws.cloudWatchLogs.viewLogStream.workflow.noStreams', '[No Log Events found]'), |
| 110 | + })) |
| 111 | +} |
| 112 | + |
| 113 | +export class SelectLogStreamWizard extends MultiStepWizard<SelectLogStreamResponse> { |
| 114 | + private readonly response: Partial<SelectLogStreamResponse> |
| 115 | + |
| 116 | + public constructor( |
| 117 | + node: LogGroupNode, |
| 118 | + private readonly context: SelectLogStreamWizardContext = new DefaultSelectLogStreamWizardContext( |
| 119 | + node.regionCode, |
| 120 | + node.logGroup.logGroupName! |
| 121 | + ) |
| 122 | + ) { |
| 123 | + super() |
| 124 | + this.response = { |
| 125 | + region: node.regionCode, |
| 126 | + logGroupName: node.logGroup.logGroupName, |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + protected get startStep(): WizardStep { |
| 131 | + return this.SELECT_STREAM |
| 132 | + } |
| 133 | + |
| 134 | + protected getResult(): SelectLogStreamResponse | undefined { |
| 135 | + if (!this.response.region || !this.response.logGroupName || !this.response.logStreamName) { |
| 136 | + return undefined |
| 137 | + } |
| 138 | + |
| 139 | + return { |
| 140 | + region: this.response.region, |
| 141 | + logGroupName: this.response.logGroupName, |
| 142 | + logStreamName: this.response.logStreamName, |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + private readonly SELECT_STREAM: WizardStep = async () => { |
| 147 | + const returnVal = await this.context.pickLogStream() |
| 148 | + |
| 149 | + // retry on error |
| 150 | + if (returnVal === picker.IteratingQuickPickController.ERROR_ITEM.label) { |
| 151 | + return this.SELECT_STREAM |
| 152 | + } |
| 153 | + |
| 154 | + this.response.logStreamName = returnVal |
| 155 | + |
| 156 | + return undefined |
| 157 | + } |
| 158 | +} |
0 commit comments