Skip to content

Commit 3ab3bb8

Browse files
committed
Fix metrics units and generate metrics using handlers
1 parent 8aee059 commit 3ab3bb8

File tree

15 files changed

+237
-190
lines changed

15 files changed

+237
-190
lines changed

src/app/standalone.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { createConnection, InitializeParams, ProposedFeatures } from 'vscode-languageserver/node';
1+
import { createConnection, ProposedFeatures } from 'vscode-languageserver/node';
22
import { InitializedParams } from 'vscode-languageserver-protocol';
33
import { LspCapabilities } from '../protocol/LspCapabilities';
44
import { LspConnection } from '../protocol/LspConnection';
5+
import { ExtendedInitializeParams } from '../server/InitParams';
56
import { LoggerFactory } from '../telemetry/LoggerFactory';
67
import { TelemetryService } from '../telemetry/TelemetryService';
78
import { AwsEnv, NodeEnv } from '../utils/Environment';
@@ -13,10 +14,10 @@ function getLogger() {
1314
return LoggerFactory.getLogger('Init');
1415
}
1516

16-
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment */
17-
async function onInitialize(params: InitializeParams) {
17+
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access */
18+
async function onInitialize(params: ExtendedInitializeParams) {
1819
const ClientInfo = params.clientInfo;
19-
const AwsMetadata = params.initializationOptions['aws'];
20+
const AwsMetadata = params.initializationOptions?.['aws'];
2021

2122
getLogger().info(
2223
{

src/datastore/LMDB.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,14 @@ export class LMDBStoreFactory implements DataStoreFactory {
136136
}
137137

138138
private registerLMDBGauges(): void {
139-
this.telemetry.registerGaugeProvider('version', () => VersionNumber, { unit: '1' });
139+
this.telemetry.registerGaugeProvider('version', () => VersionNumber);
140140
this.telemetry.registerGaugeProvider('global.size_mb', () => stats(this.env).totalSizeMB, { unit: 'MB' });
141141
this.telemetry.registerGaugeProvider('global.max_size_mb', () => stats(this.env).maxSizeMB, {
142142
unit: 'MB',
143143
});
144-
this.telemetry.registerGaugeProvider('global.entries', () => stats(this.env).entries, { unit: '1' });
145-
this.telemetry.registerGaugeProvider('global.readers', () => stats(this.env).numReaders, { unit: '1' });
146-
this.telemetry.registerGaugeProvider('stores.count', () => this.stores.size, { unit: '1' });
144+
this.telemetry.registerGaugeProvider('global.entries', () => stats(this.env).entries);
145+
this.telemetry.registerGaugeProvider('global.readers', () => stats(this.env).numReaders);
146+
this.telemetry.registerGaugeProvider('stores.count', () => this.stores.size);
147147
}
148148
}
149149

src/datastore/MemoryStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export class MemoryStoreFactory implements DataStoreFactory {
8787
}
8888

8989
private registerMemoryStoreGauges(): void {
90-
this.telemetry.registerGaugeProvider('stores.count', () => this.stores.size, { unit: '1' });
90+
this.telemetry.registerGaugeProvider('stores.count', () => this.stores.size);
9191
this.telemetry.registerGaugeProvider(
9292
'global.entries',
9393
() => {

src/document/DocumentManager.ts

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -136,40 +136,24 @@ export class DocumentManager implements SettingsConfigurable {
136136
}
137137

138138
private registerDocumentGauges(): void {
139-
this.telemetry.registerGaugeProvider('documents.open.total', () => this.documentMap.size, {
140-
unit: '1',
141-
});
139+
this.telemetry.registerGaugeProvider('documents.open.total', () => this.documentMap.size);
142140

143141
for (const type of Object.values(CloudFormationFileType)) {
144-
this.telemetry.registerGaugeProvider(
145-
`documents.open.cfn.type.${type}`,
146-
() => this.countDocumentsByCfnType(type),
147-
{
148-
unit: '1',
149-
},
142+
this.telemetry.registerGaugeProvider(`documents.open.cfn.type.${type}`, () =>
143+
this.countDocumentsByCfnType(type),
150144
);
151145
}
152146

153147
for (const type of Object.values(DocumentType)) {
154-
this.telemetry.registerGaugeProvider(
155-
`documents.open.doc.type.${type}`,
156-
() => this.countDocumentsByDocType(type),
157-
{
158-
unit: '1',
159-
},
148+
this.telemetry.registerGaugeProvider(`documents.open.doc.type.${type}`, () =>
149+
this.countDocumentsByDocType(type),
160150
);
161151
}
162152

163-
// eslint-disable-next-line unicorn/no-array-reduce
164-
const grouped = [...this.documentMap.values()].reduce<Record<string, number>>((acc, doc) => {
165-
acc[doc.extension] = (acc[doc.extension] || 0) + 1;
166-
return acc;
167-
}, {});
168-
169-
for (const [key, value] of Object.entries(grouped)) {
170-
this.telemetry.registerGaugeProvider(`documents.open.extension.type.${key}`, () => value, {
171-
unit: '1',
172-
});
153+
for (const ext of ['yaml', 'yml', 'json', 'template', 'cfn', 'txt', '']) {
154+
this.telemetry.registerGaugeProvider(`documents.open.extension.type.${ext}`, () =>
155+
this.countDocumentsByExtension(ext),
156+
);
173157
}
174158
}
175159

@@ -180,4 +164,8 @@ export class DocumentManager implements SettingsConfigurable {
180164
private countDocumentsByDocType(docType: DocumentType): number {
181165
return [...this.documentMap.values()].filter((doc) => doc.documentType === docType).length;
182166
}
167+
168+
private countDocumentsByExtension(extension: string): number {
169+
return [...this.documentMap.values()].filter((doc) => doc.isTemplate() && doc.extension === extension).length;
170+
}
183171
}

src/server/CfnInfraCore.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { InitializeParams } from 'vscode-languageserver/node';
21
import { AwsCredentials } from '../auth/AwsCredentials';
32
import { ContextManager } from '../context/ContextManager';
43
import { FileContextManager } from '../context/FileContextManager';
@@ -13,15 +12,7 @@ import { ClientMessage } from '../telemetry/ClientMessage';
1312
import { TelemetryService } from '../telemetry/TelemetryService';
1413
import { Closeable, closeSafely } from '../utils/Closeable';
1514
import { Configurable, Configurables } from '../utils/Configurable';
16-
17-
interface ExtendedInitializeParams extends InitializeParams {
18-
initializationOptions?: {
19-
encryption?: {
20-
key?: string;
21-
};
22-
[key: string]: unknown;
23-
};
24-
}
15+
import { ExtendedInitializeParams } from './InitParams';
2516

2617
/**
2718
* Core Infrastructure
@@ -59,11 +50,13 @@ export class CfnInfraCore implements Configurables, Closeable {
5950
this.contextManager = overrides.contextManager ?? new ContextManager(this.syntaxTreeManager);
6051
this.fileContextManager = overrides.fileContextManager ?? new FileContextManager(this.documentManager);
6152

62-
const encryptionKey = initializeParams.initializationOptions?.encryption?.key;
63-
6453
this.awsCredentials =
6554
overrides.awsCredentials ??
66-
new AwsCredentials(lspComponents.authHandlers, this.settingsManager, encryptionKey);
55+
new AwsCredentials(
56+
lspComponents.authHandlers,
57+
this.settingsManager,
58+
initializeParams.initializationOptions?.encryption?.key,
59+
);
6760

6861
this.diagnosticCoordinator =
6962
overrides.diagnosticCoordinator ??

src/server/InitParams.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { LevelWithSilent } from 'pino';
2+
import { InitializeParams } from 'vscode-languageserver/node';
3+
import { _InitializeParams } from 'vscode-languageserver-protocol';
4+
5+
export type ClientInfo = _InitializeParams['clientInfo'];
6+
7+
export type AwsMetadata = {
8+
clientInfo?: {
9+
extension: {
10+
name: string;
11+
version: string;
12+
};
13+
clientId: string;
14+
};
15+
telemetryEnabled?: boolean;
16+
logLevel?: LevelWithSilent;
17+
};
18+
19+
export interface ExtendedInitializeParams extends InitializeParams {
20+
initializationOptions?: {
21+
aws?: AwsMetadata;
22+
encryption?: {
23+
key: string;
24+
mode: string;
25+
};
26+
[key: string]: unknown;
27+
};
28+
}

src/services/cfnLint/CfnLintService.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,10 @@ export class CfnLintService implements SettingsConfigurable, Closeable {
138138
}
139139

140140
this.status = STATUS.Initialized;
141-
this.telemetry.count('initialized', 1, { unit: '1' });
141+
this.telemetry.count('initialized', 1);
142142
} catch (error) {
143143
this.status = STATUS.Uninitialized;
144-
this.telemetry.count('uninitialized', 1, { unit: '1' });
144+
this.telemetry.count('uninitialized', 1);
145145
throw new Error(`Failed to initialize Pyodide worker: ${extractErrorMessage(error)}`);
146146
}
147147
}
@@ -169,10 +169,10 @@ export class CfnLintService implements SettingsConfigurable, Closeable {
169169
try {
170170
await this.workerManager.mountFolder(fsDir, mountDir);
171171
this.mountedFolders.set(mountDir, folder);
172-
this.telemetry.count('mount.success', 1, { unit: '1' });
172+
this.telemetry.count('mount.success', 1);
173173
} catch (error) {
174174
this.logError('mounting folder', error);
175-
this.telemetry.count('mount.fault', 1, { unit: '1' });
175+
this.telemetry.count('mount.fault', 1);
176176
throw error; // Re-throw to notify caller
177177
}
178178
}
@@ -386,7 +386,7 @@ export class CfnLintService implements SettingsConfigurable, Closeable {
386386
const fileType = this.documentManager.get(uri)?.cfnFileType;
387387

388388
if (!fileType || fileType === CloudFormationFileType.Unknown) {
389-
this.telemetry.count(`lint.file.${CloudFormationFileType.Unknown}`, 1, { unit: '1' });
389+
this.telemetry.count(`lint.file.${CloudFormationFileType.Unknown}`, 1);
390390
this.publishDiagnostics(uri, []);
391391
return;
392392
}
@@ -395,22 +395,22 @@ export class CfnLintService implements SettingsConfigurable, Closeable {
395395
try {
396396
await this.waitForInitialization();
397397
} catch (error) {
398-
this.telemetry.count('lint.uninitialized', 1, { unit: '1' });
398+
this.telemetry.count('lint.uninitialized', 1);
399399
this.logError('waiting for CfnLintService initialization', error);
400400
throw error;
401401
}
402402

403403
// Redundant check but clears up TypeScript errors
404404
if (this.status === STATUS.Uninitialized) {
405-
this.telemetry.count('lint.uninitialized', 1, { unit: '1' });
405+
this.telemetry.count('lint.uninitialized', 1);
406406
throw new Error('CfnLintService not initialized. Call initialize() first.');
407407
}
408408

409409
const folder = this.workspace.getWorkspaceFolder(uri);
410410
if (folder === undefined || folder === null || forceUseContent) {
411411
// GitSync deployment files require workspace context to resolve relative template paths
412412
if (fileType === CloudFormationFileType.GitSyncDeployment) {
413-
this.telemetry.count(`lint.file.${CloudFormationFileType.GitSyncDeployment}`, 1, { unit: '1' });
413+
this.telemetry.count(`lint.file.${CloudFormationFileType.GitSyncDeployment}`, 1);
414414

415415
this.logError(
416416
`processing GitSync deployment file ${uri}`,
@@ -420,7 +420,7 @@ export class CfnLintService implements SettingsConfigurable, Closeable {
420420
return;
421421
}
422422

423-
this.telemetry.count(`lint.file.${CloudFormationFileType.Template}`, 1, { unit: '1' });
423+
this.telemetry.count(`lint.file.${CloudFormationFileType.Template}`, 1);
424424
// Standalone file (not in workspace) or forced to use content - lint as string
425425
await this.lintStandaloneFile(content, uri, fileType);
426426
} else {

src/services/guard/GuardService.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,10 @@ export class GuardService implements SettingsConfigurable, Closeable {
134134
try {
135135
// Initialize Guard engine only - rules are now statically available
136136
await this.guardEngine.initialize();
137-
this.telemetry.count('initialized', 1, { unit: '1' });
137+
this.telemetry.count('initialized', 1);
138138
} catch (error) {
139139
this.log.error(`Failed to initialize Guard service: ${extractErrorMessage(error)}`);
140-
this.telemetry.count('uninitialized', 1, { unit: '1' });
140+
this.telemetry.count('uninitialized', 1);
141141
throw error;
142142
}
143143
}
@@ -153,20 +153,20 @@ export class GuardService implements SettingsConfigurable, Closeable {
153153
const fileType = this.documentManager.get(uri)?.cfnFileType;
154154

155155
if (!fileType || fileType === CloudFormationFileType.Unknown) {
156-
this.telemetry.count(`validate.file.${CloudFormationFileType.Unknown}`, 1, { unit: '1' });
156+
this.telemetry.count(`validate.file.${CloudFormationFileType.Unknown}`, 1);
157157
// Not a CloudFormation file, publish empty diagnostics to clear any previous issues
158158
this.publishDiagnostics(uri, []);
159159
return;
160160
}
161161

162162
// Guard doesn't support GitSync deployment files (similar to cfn-lint handling)
163163
if (fileType === CloudFormationFileType.GitSyncDeployment) {
164-
this.telemetry.count(`validate.file.${CloudFormationFileType.GitSyncDeployment}`, 1, { unit: '1' });
164+
this.telemetry.count(`validate.file.${CloudFormationFileType.GitSyncDeployment}`, 1);
165165
this.publishDiagnostics(uri, []);
166166
return;
167167
}
168168

169-
this.telemetry.count(`validate.file.${CloudFormationFileType.Template}`, 1, { unit: '1' });
169+
this.telemetry.count(`validate.file.${CloudFormationFileType.Template}`, 1);
170170

171171
try {
172172
// Ensure Guard service is initialized

src/settings/SettingsManager.ts

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,15 @@ export class SettingsManager implements ISettingsSubscriber {
135135
private registerSettingsGauges(): void {
136136
const settings = this.getCurrentSettings();
137137

138-
this.telemetry.registerGaugeProvider('settings.hover.enabled', () => (settings.hover.enabled ? 1 : 0), {
139-
unit: '1',
140-
});
141-
this.telemetry.registerGaugeProvider(
142-
'settings.completion.enabled',
143-
() => (settings.completion.enabled ? 1 : 0),
144-
{ unit: '1' },
138+
this.telemetry.registerGaugeProvider('settings.hover.enabled', () => (settings.hover.enabled ? 1 : 0));
139+
this.telemetry.registerGaugeProvider('settings.completion.enabled', () =>
140+
settings.completion.enabled ? 1 : 0,
145141
);
146-
this.telemetry.registerGaugeProvider(
147-
'settings.diagnostics.cfnLint.enabled',
148-
() => (settings.diagnostics.cfnLint.enabled ? 1 : 0),
149-
{ unit: '1' },
142+
this.telemetry.registerGaugeProvider('settings.diagnostics.cfnLint.enabled', () =>
143+
settings.diagnostics.cfnLint.enabled ? 1 : 0,
150144
);
151-
this.telemetry.registerGaugeProvider(
152-
'settings.diagnostics.cfnGuard.enabled',
153-
() => (settings.diagnostics.cfnGuard.enabled ? 1 : 0),
154-
{ unit: '1' },
145+
this.telemetry.registerGaugeProvider('settings.diagnostics.cfnGuard.enabled', () =>
146+
settings.diagnostics.cfnGuard.enabled ? 1 : 0,
155147
);
156148
}
157149
}

src/telemetry/LoggerFactory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
22
import pino, { LevelWithSilent, Logger } from 'pino';
3+
import { AwsMetadata } from '../server/InitParams';
34
import { ExtensionName } from '../utils/ExtensionConfig';
4-
import { AwsMetadata, TelemetrySettings } from './TelemetryConfig';
5+
import { TelemetrySettings } from './TelemetryConfig';
56

67
export const LogLevel: Record<LevelWithSilent, number> = {
78
silent: 0,

0 commit comments

Comments
 (0)