From 2ef8227aacd43ae8f820ae5bb7ad1f388e377c60 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 8 Dec 2020 19:04:38 +0100 Subject: [PATCH] Log extensions query telemetry data --- .../common/extensionGalleryService.ts | 106 +++++++++++++----- 1 file changed, 77 insertions(+), 29 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 3f0dd835cd366..45d3b68c48362 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -9,7 +9,7 @@ import { getGalleryExtensionId, getGalleryExtensionTelemetryData, adoptToGallery import { getOrDefault } from 'vs/base/common/objects'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IPager } from 'vs/base/common/paging'; -import { IRequestService, asJson, asText } from 'vs/platform/request/common/request'; +import { IRequestService, asJson, asText, isSuccess } from 'vs/platform/request/common/request'; import { IRequestOptions, IRequestContext, IHeaders } from 'vs/base/parts/request/common/request'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -147,6 +147,35 @@ const DefaultQueryState: IQueryState = { assetTypes: [] }; +type GalleryServiceQueryClassification = { + filterTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + sortBy: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + sortOrder: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', 'isMeasurement': true }; + success: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + requestBodySize: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + responseBodySize?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + statusCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + errorCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + count?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; +}; + +type QueryTelemetryData = { + filterTypes: string[]; + sortBy: string; + sortOrder: string; +}; + +type GalleryServiceQueryEvent = QueryTelemetryData & { + duration: number; + success: boolean; + requestBodySize: string; + responseBodySize?: string; + statusCode?: string; + errorCode?: string; + count?: string; +}; + class Query { constructor(private state = DefaultQueryState) { } @@ -196,6 +225,14 @@ class Query { const criterium = this.state.criteria.filter(criterium => criterium.filterType === FilterType.SearchText)[0]; return criterium && criterium.value ? criterium.value : ''; } + + get telemetryData(): QueryTelemetryData { + return { + filterTypes: this.state.criteria.map(criterium => String(criterium.filterType)), + sortBy: String(this.sortBy), + sortOrder: String(this.sortOrder) + }; + } } function getStatistic(statistics: IRawGalleryExtensionStatistics[], name: string): number { @@ -447,20 +484,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService { throw new Error('No extension gallery service configured.'); } - const type = options.names ? 'ids' : (options.text ? 'text' : 'all'); let text = options.text || ''; const pageSize = getOrDefault(options, o => o.pageSize, 50); - type GalleryServiceQueryClassification = { - type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - text: { classification: 'CustomerContent', purpose: 'FeatureInsight' }; - }; - type GalleryServiceQueryEvent = { - type: string; - text: string; - }; - this.telemetryService.publicLog2('galleryService:query', { type, text }); - let query = new Query() .withFlags(Flags.IncludeLatestVersionOnly, Flags.IncludeAssetUri, Flags.IncludeStatistics, Flags.IncludeFiles, Flags.IncludeVersionProperties) .withPage(1, pageSize) @@ -543,27 +569,49 @@ export class ExtensionGalleryService implements IExtensionGalleryService { 'Content-Length': String(data.length) }; - const context = await this.requestService.request({ - type: 'POST', - url: this.api('/extensionquery'), - data, - headers - }, token); + const startTime = new Date().getTime(); + let context: IRequestContext | undefined, error: any, total: number = 0; - if (context.res.statusCode && context.res.statusCode >= 400 && context.res.statusCode < 500) { - return { galleryExtensions: [], total: 0 }; - } + try { + context = await this.requestService.request({ + type: 'POST', + url: this.api('/extensionquery'), + data, + headers + }, token); - const result = await asJson(context); - if (result) { - const r = result.results[0]; - const galleryExtensions = r.extensions; - const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; - const total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; + if (context.res.statusCode && context.res.statusCode >= 400 && context.res.statusCode < 500) { + return { galleryExtensions: [], total }; + } + + const result = await asJson(context); + if (result) { + const r = result.results[0]; + const galleryExtensions = r.extensions; + const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; + total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; - return { galleryExtensions, total }; + return { galleryExtensions, total }; + } + return { galleryExtensions: [], total }; + + } catch (e) { + error = e; + throw e; + } finally { + this.telemetryService.publicLog2('galleryService:query', { + ...query.telemetryData, + requestBodySize: String(data.length), + duration: new Date().getTime() - startTime, + success: !!context && isSuccess(context), + responseBodySize: context?.res.headers['Content-Length'], + statusCode: context ? String(context.res.statusCode) : undefined, + errorCode: error + ? isPromiseCanceledError(error) ? 'canceled' : getErrorMessage(error).startsWith('XHR timeout') ? 'timeout' : 'failed' + : undefined, + count: String(total) + }); } - return { galleryExtensions: [], total: 0 }; } async reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise {