Skip to content

Commit 3870425

Browse files
authored
feat(scanner): emit stat event when api call is a success (#641)
1 parent 8534bda commit 3870425

8 files changed

Lines changed: 181 additions & 35 deletions

File tree

.changeset/khaki-terms-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nodesecure/scanner": minor
3+
---
4+
5+
feat(scanner): emit stat event when api call is a success

workspaces/scanner/docs/logger.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ logger.on("error", (error: Error, phase?: string) => {
7979
});
8080
```
8181

82+
### stat
83+
84+
Emitted when a successful API call is made:
85+
86+
```ts
87+
logger.on("stat", (stat: ApiStats) => {
88+
console.log(`API call: ${stat.name}`);
89+
console.log(`Duration: ${stat.executionTime}ms`);
90+
console.log(`Start at: ${stat.startedAt}`);
91+
});
92+
8293
### depWalkerFinished
8394

8495
Emitted when the dependency walker completes its analysis:
@@ -143,6 +154,10 @@ export interface LoggerEventData {
143154
/** Count of triggered event */
144155
count: number;
145156
}
157+
158+
export type LoggerEventError = {
159+
executionTime: number;
160+
} & Error;
146161
```
147162

148163
### LoggerEventsMap
@@ -153,6 +168,7 @@ export type LoggerEventsMap = {
153168
tick: [eventName: string];
154169
end: [eventName: string, data: LoggerEventData & { executionTime: number; }];
155170
depWalkerFinished: [];
156-
error: [error: Error, phase?: string];
171+
error: [error: LoggerEventError, phase?: string];
172+
stat: [stat: ApiStats];
157173
};
158174
```

workspaces/scanner/src/class/StatsCollector.class.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,32 @@ import { isHTTPError } from "@openally/httpie";
66

77
// Import Internal Dependencies
88
import { SystemDateProvider, type DateProvider } from "./DateProvider.class.ts";
9-
import type { LoggerEventsMap } from "./logger.class.ts";
9+
import { type LoggerEventsMap, Logger } from "./logger.class.ts";
1010
import type { ApiStats, Stats, Error } from "../types.ts";
1111

12+
export type Providers = {
13+
dateProvider?: DateProvider;
14+
logger?: EventEmitter<LoggerEventsMap>;
15+
};
16+
17+
export type Options = {
18+
isVerbose: boolean;
19+
};
20+
1221
export class StatsCollector {
1322
#logger: EventEmitter<LoggerEventsMap>;
1423
#dateProvider: DateProvider;
1524
#apiCalls: ApiStats[] = [];
1625
#startedAt: number;
1726
#errors: Error[] = [];
27+
#isVerbose: boolean;
1828

19-
constructor(logger: EventEmitter<LoggerEventsMap>, dateProvider: DateProvider = new SystemDateProvider()) {
29+
constructor(providers: Providers, options: Options) {
30+
const { dateProvider = new SystemDateProvider(), logger = new Logger() } = providers;
2031
this.#logger = logger;
2132
this.#dateProvider = dateProvider;
2233
this.#startedAt = this.#dateProvider.now();
34+
this.#isVerbose = options.isVerbose;
2335
}
2436

2537
track<T extends () => any>(name: string, phase: string, fn: T): ReturnType<T> {
@@ -29,7 +41,7 @@ export class StatsCollector {
2941
if (result instanceof Promise) {
3042
return result
3143
.then((res: ReturnType<T>) => {
32-
this.#addApiStat(name, startedAt, this.#calcExecutionTime(startedAt));
44+
this.#addApiStatVerbose(name, startedAt, this.#calcExecutionTime(startedAt));
3345

3446
return res;
3547
})
@@ -38,19 +50,26 @@ export class StatsCollector {
3850
this.#addError({
3951
name, err, executionTime, phase
4052
});
41-
this.#addApiStat(name, startedAt, executionTime);
42-
53+
this.#apiCalls.push({
54+
name,
55+
startedAt,
56+
executionTime
57+
});
4358
throw err;
4459
}) as ReturnType<T>;
4560
}
4661

47-
this.#addApiStat(name, startedAt, this.#calcExecutionTime(startedAt));
62+
this.#addApiStatVerbose(name, startedAt, this.#calcExecutionTime(startedAt));
4863

4964
return result;
5065
}
5166
catch (err) {
5267
const executionTime = this.#calcExecutionTime(startedAt);
53-
this.#addApiStat(name, startedAt, executionTime);
68+
this.#apiCalls.push({
69+
name,
70+
startedAt,
71+
executionTime
72+
});
5473
this.#addError({
5574
name, err, executionTime, phase
5675
});
@@ -62,12 +81,16 @@ export class StatsCollector {
6281
return this.#dateProvider.now() - startedAt;
6382
}
6483

65-
#addApiStat(name: string, startedAt: number, executionTime: number) {
66-
this.#apiCalls.push({
84+
#addApiStatVerbose(name: string, startedAt: number, executionTime: number) {
85+
const stat = {
6786
name,
6887
startedAt,
6988
executionTime
70-
});
89+
};
90+
this.#apiCalls.push(stat);
91+
if (this.#isVerbose) {
92+
this.#logger.emit("stat", stat);
93+
}
7194
}
7295

7396
#addError(params: {

workspaces/scanner/src/class/logger.class.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EventEmitter } from "node:events";
33
import { performance } from "node:perf_hooks";
44

55
// Import Internal Dependencies
6-
import type { Error } from "../types.ts";
6+
import type { Error, ApiStats } from "../types.ts";
77

88
export const ScannerLoggerEvents = {
99
error: "error",
@@ -36,6 +36,7 @@ export type LoggerEventsMap = {
3636
end: [eventName: string, data: LoggerEventData & { executionTime: number; }];
3737
depWalkerFinished: [];
3838
error: [error: LoggerEventError, phase?: string];
39+
stat: [stat: ApiStats];
3940
};
4041

4142
export class Logger extends EventEmitter<LoggerEventsMap> {

workspaces/scanner/src/depWalker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export async function depWalker(
115115
const {
116116
scanRootNode = false,
117117
includeDevDeps = false,
118+
isVerbose = false,
118119
packageLock,
119120
maxDepth,
120121
location,
@@ -123,7 +124,7 @@ export async function depWalker(
123124
npmRcConfig
124125
} = options;
125126

126-
const statsCollector = new StatsCollector(logger);
127+
const statsCollector = new StatsCollector({ logger }, { isVerbose });
127128

128129
const collectables = kCollectableTypes.map((type) => new CollectableSet<Metadata>(type));
129130

workspaces/scanner/src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,13 @@ export interface Options {
334334
* @default true for cwd() API
335335
*/
336336
readonly scanRootNode?: boolean;
337+
338+
/**
339+
* Enable verbose mode
340+
*
341+
* @default false
342+
*/
343+
isVerbose?: boolean;
337344
}
338345

339346
export interface TokenStore {

0 commit comments

Comments
 (0)