Skip to content

Commit 86fa9be

Browse files
authored
Add metrics (#76)
1 parent fc8795e commit 86fa9be

21 files changed

+321
-316
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ tools/*
1212
!tools/*.ts
1313
**/.aws-cfn-storage
1414
/oss-attribution
15+
/tmp-tst

src/autocomplete/CompletionRouter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { CfnLspProviders } from '../server/CfnLspProviders';
1313
import { SettingsConfigurable, ISettingsSubscriber, SettingsSubscription } from '../settings/ISettingsSubscriber';
1414
import { CompletionSettings, DefaultSettings } from '../settings/Settings';
1515
import { LoggerFactory } from '../telemetry/LoggerFactory';
16+
import { Track } from '../telemetry/TelemetryDecorator';
1617
import { Closeable } from '../utils/Closeable';
1718
import { CompletionFormatter } from './CompletionFormatter';
1819
import { CompletionProvider } from './CompletionProvider';
@@ -45,6 +46,7 @@ export class CompletionRouter implements SettingsConfigurable, Closeable {
4546
private readonly entityFieldCompletionProviderMap = createEntityFieldProviders(),
4647
) {}
4748

49+
@Track({ name: 'getCompletions' })
4850
getCompletions(params: CompletionParams): Promise<CompletionList> | CompletionList | undefined {
4951
if (!this.completionSettings.enabled) return;
5052

src/autocomplete/InlineCompletionRouter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { RelationshipSchemaService } from '../services/RelationshipSchemaService
77
import { SettingsConfigurable, ISettingsSubscriber, SettingsSubscription } from '../settings/ISettingsSubscriber';
88
import { CompletionSettings, DefaultSettings } from '../settings/Settings';
99
import { LoggerFactory } from '../telemetry/LoggerFactory';
10+
import { Track } from '../telemetry/TelemetryDecorator';
1011
import { Closeable } from '../utils/Closeable';
1112
import { InlineCompletionProvider } from './InlineCompletionProvider';
1213
import { RelatedResourcesInlineCompletionProvider } from './RelatedResourcesInlineCompletionProvider';
@@ -25,6 +26,7 @@ export class InlineCompletionRouter implements SettingsConfigurable, Closeable {
2526
private readonly documentManager: DocumentManager,
2627
) {}
2728

29+
@Track({ name: 'getInlineCompletions' })
2830
getInlineCompletions(params: InlineCompletionParams): Promise<ReturnType> | ReturnType {
2931
if (!this.completionSettings.enabled) return;
3032

src/context/ContextManager.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { SyntaxNode } from 'tree-sitter';
22
import { TextDocumentPositionParams } from 'vscode-languageserver-protocol/lib/common/protocol';
33
import { LoggerFactory } from '../telemetry/LoggerFactory';
4+
import { Track } from '../telemetry/TelemetryDecorator';
45
import { extractErrorMessage } from '../utils/Errors';
56
import { Context } from './Context';
67
import { ContextWithRelatedEntities } from './ContextWithRelatedEntities';
@@ -12,6 +13,7 @@ export class ContextManager {
1213

1314
constructor(private readonly syntaxTreeManager: SyntaxTreeManager) {}
1415

16+
@Track({ name: 'getContext' })
1517
public getContext(params: TextDocumentPositionParams): Context | undefined {
1618
const contextParams = this.getContextParams(params);
1719
if (!contextParams) {
@@ -40,6 +42,7 @@ export class ContextManager {
4042
return undefined;
4143
}
4244

45+
@Track({ name: 'getContextWithEntities' })
4346
public getContextAndRelatedEntities(
4447
params: TextDocumentPositionParams,
4548
fullEntitySearch: boolean = true,

src/context/FileContextManager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DocumentManager } from '../document/DocumentManager';
22
import { LoggerFactory } from '../telemetry/LoggerFactory';
3+
import { Track } from '../telemetry/TelemetryDecorator';
34
import { FileContext } from './FileContext';
45

56
/**
@@ -10,6 +11,7 @@ export class FileContextManager {
1011

1112
constructor(private readonly documentManager: DocumentManager) {}
1213

14+
@Track({ name: 'getFileContext' })
1315
public getFileContext(uri: string): FileContext | undefined {
1416
const document = this.documentManager.get(uri);
1517
if (!document) {

src/context/syntaxtree/SyntaxTreeManager.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Edit, Point } from 'tree-sitter';
22
import { CloudFormationFileType, DocumentType } from '../../document/Document';
33
import { detectDocumentType } from '../../document/DocumentUtils';
44
import { LoggerFactory } from '../../telemetry/LoggerFactory';
5+
import { Measure } from '../../telemetry/TelemetryDecorator';
56
import { extractErrorMessage } from '../../utils/Errors';
67
import { JsonSyntaxTree } from './JsonSyntaxTree';
78
import { SyntaxTree } from './SyntaxTree';
@@ -27,26 +28,28 @@ export class SyntaxTreeManager {
2728
return;
2829
}
2930

30-
this.log.info({ type, cfnFileType }, `Created tree ${uri}`);
3131
try {
32-
if (type === DocumentType.YAML) {
33-
this.createYamlSyntaxTree(uri, content);
34-
} else {
35-
this.createJsonSyntaxTree(uri, content);
36-
}
37-
this.log.debug(
38-
{
39-
uri,
40-
type,
41-
cfnFileType,
42-
},
43-
'Created SyntaxTree',
44-
);
32+
this.createTree(uri, content, type, cfnFileType);
4533
} catch (error) {
4634
logger.error(`Failed to create tree ${uri} ${type} ${cfnFileType}: ${extractErrorMessage(error)}`);
4735
}
4836
}
4937

38+
@Measure({ name: 'createTree' })
39+
private createTree(uri: string, content: string, type: DocumentType, cfnFileType: CloudFormationFileType) {
40+
if (cfnFileType !== CloudFormationFileType.Template) {
41+
throw new Error('Syntax tree can only be created for CloudFormation templates');
42+
}
43+
44+
if (type === DocumentType.YAML) {
45+
this.createYamlSyntaxTree(uri, content);
46+
} else {
47+
this.createJsonSyntaxTree(uri, content);
48+
}
49+
50+
this.log.info({ type, cfnFileType }, `Created tree ${uri}`);
51+
}
52+
5053
private createJsonSyntaxTree(uri: string, content: string) {
5154
this.syntaxTrees.set(uri, new JsonSyntaxTree(content));
5255
}

src/datastore/LMDB.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { open, Database, RootDatabase } from 'lmdb';
2+
import { ScopedTelemetry } from '../telemetry/ScopedTelemetry';
3+
import { Telemetry } from '../telemetry/TelemetryDecorator';
24
import { pathToArtifact } from '../utils/ArtifactsDir';
35
import { DataStore, DataStoreFactory } from './DataStore';
46

@@ -31,6 +33,8 @@ export class LMDBStore implements DataStore {
3133
}
3234

3335
export class LMDBStoreFactory implements DataStoreFactory {
36+
@Telemetry() private readonly telemetry!: ScopedTelemetry;
37+
3438
private readonly rootDir = pathToArtifact('lmdb');
3539
private readonly storePath = `${this.rootDir}/${Version}`;
3640

@@ -43,6 +47,10 @@ export class LMDBStoreFactory implements DataStoreFactory {
4347

4448
private readonly stores = new Map<string, LMDBStore>();
4549

50+
constructor() {
51+
this.registerLMDBGauges();
52+
}
53+
4654
getOrCreate(store: string): DataStore {
4755
let val = this.stores.get(store);
4856
if (val === undefined) {
@@ -85,6 +93,16 @@ export class LMDBStoreFactory implements DataStoreFactory {
8593
this.stores.clear();
8694
await this.env.close();
8795
}
96+
97+
private registerLMDBGauges(): void {
98+
this.telemetry.registerGaugeProvider('lmdb.global.size_mb', () => stats(this.env).totalSizeMB, { unit: 'MB' });
99+
this.telemetry.registerGaugeProvider('lmdb.global.max_size_mb', () => stats(this.env).maxSizeMB, {
100+
unit: 'MB',
101+
});
102+
this.telemetry.registerGaugeProvider('lmdb.global.entries', () => stats(this.env).entries, { unit: '1' });
103+
this.telemetry.registerGaugeProvider('lmdb.global.readers', () => stats(this.env).numReaders, { unit: '1' });
104+
this.telemetry.registerGaugeProvider('lmdb.stores.count', () => this.stores.size, { unit: '1' });
105+
}
88106
}
89107

90108
function bytesToMB(bytes: number) {

src/definition/DefinitionProvider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { DefinitionParams, Location, LocationLink } from 'vscode-languageserver';
22
import { ContextManager } from '../context/ContextManager';
33
import { LoggerFactory } from '../telemetry/LoggerFactory';
4+
import { Track } from '../telemetry/TelemetryDecorator';
45
import { pointToPosition } from '../utils/TypeConverters';
56

67
export class DefinitionProvider {
78
private readonly log = LoggerFactory.getLogger(DefinitionProvider);
89

910
constructor(private readonly contextManager: ContextManager) {}
1011

12+
@Track({ name: 'getDefinitions' })
1113
getDefinitions(params: DefinitionParams): Location | Location[] | LocationLink[] | undefined {
1214
const context = this.contextManager.getContextAndRelatedEntities(params);
1315
this.log.debug(

src/document/DocumentManager.ts

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ import { TextDocument } from 'vscode-languageserver-textdocument';
33
import { SettingsConfigurable, ISettingsSubscriber, SettingsSubscription } from '../settings/ISettingsSubscriber';
44
import { DefaultSettings, EditorSettings } from '../settings/Settings';
55
import { LoggerFactory } from '../telemetry/LoggerFactory';
6+
import { ScopedTelemetry } from '../telemetry/ScopedTelemetry';
7+
import { Telemetry } from '../telemetry/TelemetryDecorator';
68
import { Delayer } from '../utils/Delayer';
7-
import { Document } from './Document';
9+
import { CloudFormationFileType, Document, DocumentType, Extension } from './Document';
810
import { DocumentMetadata } from './DocumentProtocol';
911

1012
export class DocumentManager implements SettingsConfigurable {
1113
private readonly log = LoggerFactory.getLogger(DocumentManager);
14+
15+
@Telemetry() private readonly telemetry!: ScopedTelemetry;
1216
private readonly delayer = new Delayer(5 * 1000);
1317

1418
private editorSettings: EditorSettings = DefaultSettings.editor;
@@ -21,7 +25,9 @@ export class DocumentManager implements SettingsConfigurable {
2125
private readonly sendDocuments: (docs: DocumentMetadata[]) => Promise<void> = () => {
2226
return Promise.resolve();
2327
},
24-
) {}
28+
) {
29+
this.registerDocumentGauges();
30+
}
2531

2632
configure(settingsManager: ISettingsSubscriber): void {
2733
if (this.settingsSubscription) {
@@ -125,4 +131,52 @@ export class DocumentManager implements SettingsConfigurable {
125131
this.clearAllStoredIndentation();
126132
}
127133
}
134+
135+
private registerDocumentGauges(): void {
136+
this.telemetry.registerGaugeProvider('documents.open.total', () => this.documentMap.size, {
137+
unit: '1',
138+
});
139+
140+
for (const type of Object.values(CloudFormationFileType)) {
141+
this.telemetry.registerGaugeProvider(
142+
`documents.open.cfn.type.${type}`,
143+
() => this.countDocumentsByCfnType(type),
144+
{
145+
unit: '1',
146+
},
147+
);
148+
}
149+
150+
for (const type of Object.values(DocumentType)) {
151+
this.telemetry.registerGaugeProvider(
152+
`documents.open.doc.type.${type}`,
153+
() => this.countDocumentsByDocType(type),
154+
{
155+
unit: '1',
156+
},
157+
);
158+
}
159+
160+
for (const type of Object.values(Extension)) {
161+
this.telemetry.registerGaugeProvider(
162+
`documents.open.extension.type.${type}`,
163+
() => this.countDocumentsByExtension(type),
164+
{
165+
unit: '1',
166+
},
167+
);
168+
}
169+
}
170+
171+
private countDocumentsByCfnType(cfnType: CloudFormationFileType): number {
172+
return [...this.documentMap.values()].filter((doc) => doc.cfnFileType === cfnType).length;
173+
}
174+
175+
private countDocumentsByDocType(docType: DocumentType): number {
176+
return [...this.documentMap.values()].filter((doc) => doc.documentType === docType).length;
177+
}
178+
179+
private countDocumentsByExtension(extension: Extension): number {
180+
return [...this.documentMap.values()].filter((doc) => doc.extension === extension).length;
181+
}
128182
}

src/documentSymbol/DocumentSymbolRouter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { EntityType } from '../context/semantic/SemanticTypes';
77
import { SyntaxTreeManager } from '../context/syntaxtree/SyntaxTreeManager';
88
import { FieldNames } from '../context/syntaxtree/utils/TreeSitterTypes';
99
import { LoggerFactory } from '../telemetry/LoggerFactory';
10+
import { Track } from '../telemetry/TelemetryDecorator';
1011
import { extractErrorMessage } from '../utils/Errors';
1112
import { nodeToRange, pointToPosition } from '../utils/TypeConverters';
1213

@@ -95,6 +96,7 @@ export class DocumentSymbolRouter {
9596

9697
constructor(private readonly syntaxTreeManager: SyntaxTreeManager) {}
9798

99+
@Track({ name: 'getDocumentSymbols' })
98100
getDocumentSymbols(params: DocumentSymbolParams): DocumentSymbol[] {
99101
this.log.debug(
100102
{

0 commit comments

Comments
 (0)