Skip to content

Commit 6de5dcb

Browse files
authored
add telemetry to ResourceStateManager and CcapiService (#150)
1 parent 6119afe commit 6de5dcb

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

src/resourceState/ResourceStateManager.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { CcapiService } from '../services/CcapiService';
66
import { ISettingsSubscriber, SettingsConfigurable, SettingsSubscription } from '../settings/ISettingsSubscriber';
77
import { DefaultSettings, ProfileSettings } from '../settings/Settings';
88
import { LoggerFactory } from '../telemetry/LoggerFactory';
9+
import { ScopedTelemetry } from '../telemetry/ScopedTelemetry';
10+
import { Telemetry, Measure } from '../telemetry/TelemetryDecorator';
911
import { Closeable } from '../utils/Closeable';
1012
import { ListResourcesResult, RefreshResourcesResult } from './ResourceStateTypes';
1113

@@ -32,6 +34,7 @@ type ResourceStateMap = Map<ResourceType, Map<ResourceId, ResourceState>>;
3234
type ResourceListMap = Map<ResourceType, ResourceList>;
3335

3436
export class ResourceStateManager implements SettingsConfigurable, Closeable {
37+
@Telemetry() private readonly telemetry!: ScopedTelemetry;
3538
private settingsSubscription?: SettingsSubscription;
3639
private settings: ProfileSettings = DefaultSettings.profile;
3740
private isRefreshing = false;
@@ -43,13 +46,20 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
4346
constructor(
4447
private readonly ccapiService: CcapiService,
4548
private readonly schemaRetriever: SchemaRetriever,
46-
) {}
49+
) {
50+
this.registerCacheGauges();
51+
this.initializeCounters();
52+
}
4753

54+
@Measure({ name: 'getResource' })
4855
public async getResource(typeName: ResourceType, identifier: ResourceId): Promise<ResourceState | undefined> {
4956
const cachedResources = this.getResourceState(typeName, identifier);
5057
if (cachedResources) {
58+
this.telemetry.count('state.hit', 1);
5159
return cachedResources;
5260
}
61+
this.telemetry.count('state.miss', 1);
62+
5363
let output: GetResourceCommandOutput | undefined = undefined;
5464

5565
try {
@@ -58,6 +68,7 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
5868
log.error(error, `CCAPI GetResource failed for type ${typeName} and identifier "${identifier}"`);
5969
if (error instanceof ResourceNotFoundException) {
6070
log.info(`No resource found for type ${typeName} and identifier "${identifier}"`);
71+
this.telemetry.count('state.fault', 1);
6172
}
6273
return;
6374
}
@@ -80,6 +91,7 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
8091
return value;
8192
}
8293

94+
@Measure({ name: 'listResources' })
8395
public async listResources(typeName: string, nextToken?: string): Promise<ResourceList | undefined> {
8496
const cached = this.resourceListMap.get(typeName);
8597

@@ -108,6 +120,7 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
108120
return resourceListNextPage;
109121
}
110122

123+
@Measure({ name: 'searchResourceByIdentifier' })
111124
public async searchResourceByIdentifier(
112125
typeName: string,
113126
identifier: string,
@@ -184,6 +197,7 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
184197
}
185198
}
186199

200+
@Measure({ name: 'refreshResourceList' })
187201
public async refreshResourceList(resourceTypes: string[]): Promise<RefreshResourcesResult> {
188202
if (this.isRefreshing) {
189203
// return cached resource list
@@ -233,6 +247,9 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
233247
nextToken: response.nextToken,
234248
});
235249
}
250+
if (anyRefreshFailed) {
251+
this.telemetry.count('refresh.fault', 1);
252+
}
236253
return { ...result, refreshFailed: anyRefreshFailed };
237254
} finally {
238255
this.isRefreshing = false;
@@ -259,12 +276,37 @@ export class ResourceStateManager implements SettingsConfigurable, Closeable {
259276
private onSettingsChanged(newSettings: ProfileSettings) {
260277
// clear cached resources if AWS profile or region changes as data is redundant
261278
if (newSettings.profile !== this.settings.profile || newSettings.region !== this.settings.region) {
279+
this.telemetry.count('state.invalidated', 1);
280+
this.telemetry.count('list.invalidated', 1);
262281
this.resourceStateMap.clear();
263282
this.resourceListMap.clear();
264283
}
265284
this.settings = newSettings;
266285
}
267286

287+
private initializeCounters(): void {
288+
this.telemetry.count('state.hit', 0);
289+
this.telemetry.count('state.miss', 0);
290+
this.telemetry.count('state.fault', 0);
291+
this.telemetry.count('state.invalidated', 0);
292+
this.telemetry.count('list.invalidated', 0);
293+
this.telemetry.count('refresh.fault', 0);
294+
}
295+
296+
private registerCacheGauges(): void {
297+
this.telemetry.registerGaugeProvider('state.types', () => this.resourceStateMap.size);
298+
299+
this.telemetry.registerGaugeProvider('list.types', () => this.resourceListMap.size);
300+
301+
this.telemetry.registerGaugeProvider('state.count', () => {
302+
let total = 0;
303+
for (const resourceMap of this.resourceStateMap.values()) {
304+
total += resourceMap.size;
305+
}
306+
return total;
307+
});
308+
}
309+
268310
static create(external: CfnExternal) {
269311
return new ResourceStateManager(external.ccapiService, external.schemaRetriever);
270312
}

src/services/CcapiService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ListResourcesCommand,
66
ListResourcesOutput,
77
} from '@aws-sdk/client-cloudcontrol';
8+
import { Measure } from '../telemetry/TelemetryDecorator';
89
import { AwsClient } from './AwsClient';
910

1011
export interface ListResourcesOptions {
@@ -20,6 +21,7 @@ export class CcapiService {
2021
return await request(client);
2122
}
2223

24+
@Measure({ name: 'listResources' })
2325
public async listResources(typeName: string, options?: ListResourcesOptions): Promise<ListResourcesOutput> {
2426
return await this.withClient(async (client) => {
2527
const response = await client.send(
@@ -38,6 +40,7 @@ export class CcapiService {
3840
});
3941
}
4042

43+
@Measure({ name: 'getResource' })
4144
public async getResource(typeName: string, identifier: string) {
4245
return await this.withClient(async (client) => {
4346
const getResourceInput: GetResourceInput = {

0 commit comments

Comments
 (0)