Skip to content

Commit 3471993

Browse files
authored
telemetry(vscode): MetricBase.awsRegion #765
Problem: In the generated `telemetry.gen.ts` for vscode toolkit, `MetricBase` does not have various common fields. This adds friction when setting these fields. Solution: - Update the generator to define `MetricBase.awsRegion`. - Change the 'with normal input' test so that it uses the "types" defined in `commonDefinitions.json`. This increases test coverage while also reducing the boilerplate needed when adding a new field to `MetricBase`.
1 parent 525b698 commit 3471993

File tree

7 files changed

+158
-90
lines changed

7 files changed

+158
-90
lines changed

telemetry/definitions/commonDefinitions.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@
127127
],
128128
"description": "Status of the an auth connection."
129129
},
130+
{
131+
"name": "awsAccount",
132+
"type": "string",
133+
"description": "AWS account ID associated with a metric. \"n/a\" if credentials are not available. \"not-set\" if credentials are not selected. \"invalid\" if account ID cannot be obtained."
134+
},
130135
{
131136
"name": "awsFiletype",
132137
"type": "string",
@@ -147,6 +152,11 @@
147152
],
148153
"description": "AWS filetype kind"
149154
},
155+
{
156+
"name": "awsRegion",
157+
"type": "string",
158+
"description": "AWS Region associated with a metric"
159+
},
150160
{
151161
"name": "causedBy",
152162
"allowedValues": [
@@ -1225,6 +1235,11 @@
12251235
"type": "string",
12261236
"description": "Language used for the project."
12271237
},
1238+
{
1239+
"name": "locale",
1240+
"type": "string",
1241+
"description": "User locale. Examples: en-US, en-GB, etc."
1242+
},
12281243
{
12291244
"name": "name",
12301245
"type": "string",
@@ -6061,4 +6076,4 @@
60616076
]
60626077
}
60636078
]
6064-
}
6079+
}

telemetry/vscode/src/generate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function getTypeOrThrow(types: MetadataType[] = [], name: string) {
121121
}
122122

123123
const baseName = 'MetricBase'
124-
const commonMetadata = ['result', 'reason', 'reasonDesc', 'duration']
124+
const commonMetadata = ['result', 'reason', 'reasonDesc', 'duration', 'awsRegion']
125125
const passive: PropertySignatureStructure = {
126126
isReadonly: true,
127127
hasQuestionToken: true,

telemetry/vscode/test/generator.test.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,32 @@
55

66
import { generate } from '../src/generate'
77
import { tmpdir } from 'os'
8-
import { readFile } from 'fs-extra'
8+
import * as fs from 'fs-extra'
9+
10+
/**
11+
* Replaces the "types" field in the given json file with the "types" field
12+
* from `commonDefinitions.json`.
13+
*
14+
* @returns Original contents of `relPath`.
15+
*/
16+
async function writeCommonTypesToFile(relPath: string) {
17+
const testInputFile = `${__dirname}/${relPath}`
18+
const commonDefsStr = await fs.readFile(`${__dirname}/../../definitions/commonDefinitions.json`)
19+
const commonDefs = JSON.parse(commonDefsStr.toString())
20+
const commonTypes = commonDefs.types
21+
const testInputStr = (await fs.readFile(testInputFile)).toString()
22+
const testInputJson = JSON.parse(testInputStr)
23+
// Use the "types" array from commonDefinitions.json.
24+
testInputJson.types = commonTypes
25+
await fs.writeFile(testInputFile, JSON.stringify(testInputJson, undefined, 4))
26+
27+
return testInputStr
28+
}
29+
30+
async function restoreFile(relPath: string, data: string) {
31+
const testInputFile = `${__dirname}/${relPath}`
32+
await fs.writeFile(testInputFile, data)
33+
}
934

1035
describe('Generator', () => {
1136
let tempDir: string
@@ -18,22 +43,30 @@ describe('Generator', () => {
1843
})
1944

2045
test('with normal input', async () => {
21-
await testGenerator([`resources/generatorInput.json`], `resources/generatorOutput.ts`)
46+
const oldFileContent = await writeCommonTypesToFile('resources/generatorInput.json')
47+
48+
await testGenerator(['resources/generatorInput.json'], 'resources/generatorOutput.ts')
49+
50+
restoreFile('resources/generatorInput.json', oldFileContent)
2251
})
2352

2453
test('overrides', async () => {
54+
const oldFileContent = await writeCommonTypesToFile('resources/testOverrideInput.json')
55+
2556
await testGenerator(
2657
['resources/testOverrideInput.json', 'resources/testResultInput.json'],
2758
'resources/generatorOverrideOutput.ts'
2859
)
60+
61+
restoreFile('resources/testOverrideInput.json', oldFileContent)
2962
})
3063

3164
async function testGenerator(inputFiles: string[], expectedOutputFile: string) {
3265
const output = `${tempDir}/output`
3366
await generate({ inputFiles: inputFiles.map(item => `${__dirname}/${item}`), outputFile: output })
3467
// TODO remove spaces and line returns so that it matches more generally? pull in a better matching lib?
35-
const actualOutput = await readFile(output, 'utf-8')
36-
const expectedOutput = await readFile(`${__dirname}/${expectedOutputFile}`, 'utf-8')
68+
const actualOutput = await fs.readFile(output, 'utf-8')
69+
const expectedOutput = await fs.readFile(`${__dirname}/${expectedOutputFile}`, 'utf-8')
3770
expect(actualOutput).toEqual(expectedOutput)
3871
}
3972
})

telemetry/vscode/test/resources/generatorInput.json

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,45 @@
11
{
2-
"types": [
3-
{
4-
"name": "lambdaRuntime",
5-
"type": "string",
6-
"allowedValues": ["dotnetcore2.1", "nodejs12.x"],
7-
"description": "The lambda runtime"
8-
},
9-
{
10-
"name": "result",
11-
"allowedValues": ["Succeeded"],
12-
"description": "The result of the operation"
13-
},
14-
{
15-
"name": "reason",
16-
"type": "string",
17-
"description": "Reason code or name for an event (when result=Succeeded) or error (when result=Failed). Unlike the `reasonDesc` field, this should be a stable/predictable name for a class of events or errors (typically the exception name, e.g. FileIOException)."
18-
},
19-
{
20-
"name": "reasonDesc",
21-
"type": "string",
22-
"description": "Error message detail. May contain arbitrary message details (unlike the `reason` field), but should be truncated (recommendation: 200 chars)."
23-
},
24-
{
25-
"name": "duration",
26-
"type": "double",
27-
"description": "The duration of the operation in miliseconds"
28-
},
29-
{
30-
"name": "inttype",
31-
"description": "a test int type",
32-
"type": "int"
33-
},
34-
{
35-
"name": "booltype",
36-
"description": "a test boolean type",
37-
"type": "boolean"
38-
},
39-
{
40-
"name": "arbitraryString",
41-
"description": "untyped string type"
42-
}
43-
],
2+
"types": "will be replaced with `types` from commonDefinitions.json",
443
"metrics": [
454
{
465
"name": "lambda_delete",
476
"description": "called when deleting lambdas remotely",
487
"unit": "None",
49-
"metadata": [{ "type": "duration" }, { "type": "booltype" }]
8+
"metadata": [
9+
{
10+
"type": "duration"
11+
},
12+
{
13+
"type": "isRetry"
14+
}
15+
]
5016
},
5117
{
5218
"name": "lambda_create",
5319
"description": "called when creating lambdas remotely",
5420
"unit": "None",
55-
"metadata": [{ "type": "lambdaRuntime" }, { "type": "arbitraryString" }]
21+
"metadata": [
22+
{
23+
"type": "runtime"
24+
},
25+
{
26+
"type": "userId"
27+
}
28+
]
5629
},
5730
{
5831
"name": "lambda_remoteinvoke",
5932
"description": "called when invoking lambdas remotely",
6033
"unit": "None",
61-
"metadata": [{ "type": "lambdaRuntime", "required": false }, { "type": "inttype" }]
34+
"metadata": [
35+
{
36+
"type": "runtime",
37+
"required": false
38+
},
39+
{
40+
"type": "successCount"
41+
}
42+
]
6243
},
6344
{
6445
"name": "no_metadata",

telemetry/vscode/test/resources/generatorOutput.ts

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,69 @@ export interface MetricBase {
99
readonly reason?: string
1010
/** Error message detail. May contain arbitrary message details (unlike the `reason` field), but should be truncated (recommendation: 200 chars). */
1111
readonly reasonDesc?: string
12-
/** The duration of the operation in miliseconds */
12+
/** The duration of the operation in milliseconds */
1313
readonly duration?: number
14+
/** AWS Region associated with a metric */
15+
readonly awsRegion?: string
1416
/** A flag indicating that the metric was not caused by the user. */
1517
readonly passive?: boolean
1618
/** @deprecated Arbitrary "value" of the metric. */
1719
readonly value?: number
1820
}
1921

2022
export interface LambdaDelete extends MetricBase {
21-
/** a test boolean type */
22-
readonly booltype: boolean
23+
/** Whether or not the operation was a retry */
24+
readonly isRetry: boolean
2325
}
2426

2527
export interface LambdaCreate extends MetricBase {
2628
/** The lambda runtime */
27-
readonly lambdaRuntime: LambdaRuntime
28-
/** untyped string type */
29-
readonly arbitraryString: string
29+
readonly runtime: Runtime
30+
/** Opaque AWS Builder ID identifier */
31+
readonly userId: string
3032
}
3133

3234
export interface LambdaRemoteinvoke extends MetricBase {
3335
/** The lambda runtime */
34-
readonly lambdaRuntime?: LambdaRuntime
35-
/** a test int type */
36-
readonly inttype: number
36+
readonly runtime?: Runtime
37+
/** The number of successful operations */
38+
readonly successCount: number
3739
}
3840

3941
export interface NoMetadata extends MetricBase {}
4042

4143
export interface PassivePassive extends MetricBase {}
4244

43-
export type Result = 'Succeeded'
44-
export type LambdaRuntime = 'dotnetcore2.1' | 'nodejs12.x'
45+
export type Result = 'Succeeded' | 'Failed' | 'Cancelled'
46+
export type Runtime =
47+
| 'dotnetcore3.1'
48+
| 'dotnetcore2.1'
49+
| 'dotnet5.0'
50+
| 'dotnet6'
51+
| 'dotnet7'
52+
| 'dotnet8'
53+
| 'nodejs20.x'
54+
| 'nodejs18.x'
55+
| 'nodejs16.x'
56+
| 'nodejs14.x'
57+
| 'nodejs12.x'
58+
| 'nodejs10.x'
59+
| 'nodejs8.10'
60+
| 'ruby2.5'
61+
| 'java8'
62+
| 'java8.al2'
63+
| 'java11'
64+
| 'java17'
65+
| 'java21'
66+
| 'go1.x'
67+
| 'python3.12'
68+
| 'python3.11'
69+
| 'python3.10'
70+
| 'python3.9'
71+
| 'python3.8'
72+
| 'python3.7'
73+
| 'python3.6'
74+
| 'python2.7'
4575

4676
export interface MetricDefinition {
4777
readonly unit: string
@@ -60,9 +90,9 @@ export interface MetricShapes {
6090
export type MetricName = keyof MetricShapes
6191

6292
export const definitions: Record<string, MetricDefinition> = {
63-
lambda_delete: { unit: 'None', passive: false, requiredMetadata: ['booltype'] },
64-
lambda_create: { unit: 'None', passive: false, requiredMetadata: ['lambdaRuntime', 'arbitraryString'] },
65-
lambda_remoteinvoke: { unit: 'None', passive: false, requiredMetadata: ['inttype'] },
93+
lambda_delete: { unit: 'None', passive: false, requiredMetadata: ['isRetry'] },
94+
lambda_create: { unit: 'None', passive: false, requiredMetadata: ['runtime', 'userId'] },
95+
lambda_remoteinvoke: { unit: 'None', passive: false, requiredMetadata: ['successCount'] },
6696
no_metadata: { unit: 'None', passive: false, requiredMetadata: [] },
6797
passive_passive: { unit: 'None', passive: true, requiredMetadata: [] },
6898
}

telemetry/vscode/test/resources/generatorOverrideOutput.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ export interface MetricBase {
99
readonly reason?: string
1010
/** Error message detail. May contain arbitrary message details (unlike the `reason` field), but should be truncated (recommendation: 200 chars). */
1111
readonly reasonDesc?: string
12-
/** The duration of the operation in miliseconds */
12+
/** The duration of the operation in milliseconds */
1313
readonly duration?: number
14+
/** AWS Region associated with a metric */
15+
readonly awsRegion?: string
1416
/** A flag indicating that the metric was not caused by the user. */
1517
readonly passive?: boolean
1618
/** @deprecated Arbitrary "value" of the metric. */
@@ -19,8 +21,36 @@ export interface MetricBase {
1921

2022
export interface MetadataHasResult extends MetricBase {}
2123

22-
export type Result = 'Succeeded'
23-
export type LambdaRuntime = 'dotnetcore2.1' | 'nodejs12.x'
24+
export type Result = 'Succeeded' | 'Failed' | 'Cancelled'
25+
export type Runtime =
26+
| 'dotnetcore3.1'
27+
| 'dotnetcore2.1'
28+
| 'dotnet5.0'
29+
| 'dotnet6'
30+
| 'dotnet7'
31+
| 'dotnet8'
32+
| 'nodejs20.x'
33+
| 'nodejs18.x'
34+
| 'nodejs16.x'
35+
| 'nodejs14.x'
36+
| 'nodejs12.x'
37+
| 'nodejs10.x'
38+
| 'nodejs8.10'
39+
| 'ruby2.5'
40+
| 'java8'
41+
| 'java8.al2'
42+
| 'java11'
43+
| 'java17'
44+
| 'java21'
45+
| 'go1.x'
46+
| 'python3.12'
47+
| 'python3.11'
48+
| 'python3.10'
49+
| 'python3.9'
50+
| 'python3.8'
51+
| 'python3.7'
52+
| 'python3.6'
53+
| 'python2.7'
2454

2555
export interface MetricDefinition {
2656
readonly unit: string

telemetry/vscode/test/resources/testOverrideInput.json

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,5 @@
11
{
2-
"types": [
3-
{
4-
"name": "result",
5-
"allowedValues": ["Succeeded"],
6-
"description": "The result of the operation"
7-
},
8-
{
9-
"name": "reason",
10-
"type": "string",
11-
"description": "Reason code or name for an event (when result=Succeeded) or error (when result=Failed). Unlike the `reasonDesc` field, this should be a stable/predictable name for a class of events or errors (typically the exception name, e.g. FileIOException)."
12-
},
13-
{
14-
"name": "reasonDesc",
15-
"type": "string",
16-
"description": "Error message detail. May contain arbitrary message details (unlike the `reason` field), but should be truncated (recommendation: 200 chars)."
17-
},
18-
{
19-
"name": "duration",
20-
"type": "double",
21-
"description": "The duration of the operation in miliseconds"
22-
}
23-
],
2+
"types": "will be replaced with `types` from commonDefinitions.json",
243
"metrics": [
254
{
265
"name": "metadata_hasResult",

0 commit comments

Comments
 (0)