@inversifyjs/http-instrumentation-core 5.8.0 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.npmignore +26 -0
- package/lib/actions/emitHttpInstrumentationEvent.d.ts +4 -0
- package/lib/actions/emitHttpInstrumentationEvent.d.ts.map +1 -0
- package/lib/actions/emitHttpInstrumentationEvent.js +20 -0
- package/lib/actions/emitHttpInstrumentationEvent.js.map +1 -0
- package/lib/actions/httpInstrumentationState.d.ts +5 -0
- package/lib/actions/httpInstrumentationState.d.ts.map +1 -0
- package/lib/actions/httpInstrumentationState.js +50 -0
- package/lib/actions/httpInstrumentationState.js.map +1 -0
- package/lib/actions/markHttpInstrumentedHandler.d.ts +3 -0
- package/lib/actions/markHttpInstrumentedHandler.d.ts.map +1 -0
- package/lib/actions/markHttpInstrumentedHandler.js +14 -0
- package/lib/actions/markHttpInstrumentedHandler.js.map +1 -0
- package/lib/actions/runInstrumentedHttpStage.d.ts +11 -0
- package/lib/actions/runInstrumentedHttpStage.d.ts.map +1 -0
- package/lib/actions/runInstrumentedHttpStage.js +28 -0
- package/lib/actions/runInstrumentedHttpStage.js.map +1 -0
- package/lib/calculations/buildHttpInstrumentationContext.d.ts +5 -0
- package/lib/calculations/buildHttpInstrumentationContext.d.ts.map +1 -0
- package/lib/calculations/buildHttpInstrumentationContext.js +10 -0
- package/lib/calculations/buildHttpInstrumentationContext.js.map +1 -0
- package/lib/calculations/redactHttpHeaders.d.ts +2 -0
- package/lib/calculations/redactHttpHeaders.d.ts.map +1 -0
- package/lib/calculations/redactHttpHeaders.js +28 -0
- package/lib/calculations/redactHttpHeaders.js.map +1 -0
- package/lib/calculations/startHttpStage.d.ts +4 -0
- package/lib/calculations/startHttpStage.d.ts.map +1 -0
- package/lib/calculations/startHttpStage.js +10 -0
- package/lib/calculations/startHttpStage.js.map +1 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/lib/models/EventSink.d.ts +4 -0
- package/lib/models/EventSink.d.ts.map +1 -0
- package/lib/models/EventSink.js +2 -0
- package/lib/models/EventSink.js.map +1 -0
- package/lib/models/HttpInstrumentationContext.d.ts +7 -0
- package/lib/models/HttpInstrumentationContext.d.ts.map +1 -0
- package/lib/models/HttpInstrumentationContext.js +2 -0
- package/lib/models/HttpInstrumentationContext.js.map +1 -0
- package/lib/models/HttpInstrumentationEvent.d.ts +91 -0
- package/lib/models/HttpInstrumentationEvent.d.ts.map +1 -0
- package/lib/models/HttpInstrumentationEvent.js +2 -0
- package/lib/models/HttpInstrumentationEvent.js.map +1 -0
- package/lib/models/HttpInstrumentationScope.d.ts +6 -0
- package/lib/models/HttpInstrumentationScope.d.ts.map +1 -0
- package/lib/models/HttpInstrumentationScope.js +2 -0
- package/lib/models/HttpInstrumentationScope.js.map +1 -0
- package/lib/models/HttpStageClock.d.ts +5 -0
- package/lib/models/HttpStageClock.d.ts.map +1 -0
- package/lib/models/HttpStageClock.js +2 -0
- package/lib/models/HttpStageClock.js.map +1 -0
- package/lib/models/httpInstrumentationStateSymbol.d.ts +6 -0
- package/lib/models/httpInstrumentationStateSymbol.d.ts.map +1 -0
- package/lib/models/httpInstrumentationStateSymbol.js +2 -0
- package/lib/models/httpInstrumentationStateSymbol.js.map +1 -0
- package/lib/models/httpInstrumentedHandlerSymbol.d.ts +2 -0
- package/lib/models/httpInstrumentedHandlerSymbol.d.ts.map +1 -0
- package/lib/models/httpInstrumentedHandlerSymbol.js +2 -0
- package/lib/models/httpInstrumentedHandlerSymbol.js.map +1 -0
- package/package.json +1 -1
- package/.lintstagedrc.json +0 -4
- package/CHANGELOG.md +0 -11
- package/eslint.config.mjs +0 -23
- package/prettier.config.mjs +0 -3
- package/src/actions/emitHttpInstrumentationEvent.spec.ts +0 -130
- package/src/actions/emitHttpInstrumentationEvent.ts +0 -28
- package/src/actions/httpInstrumentationState.spec.ts +0 -49
- package/src/actions/httpInstrumentationState.ts +0 -93
- package/src/actions/markHttpInstrumentedHandler.ts +0 -16
- package/src/actions/runInstrumentedHttpStage.ts +0 -76
- package/src/calculations/buildHttpInstrumentationContext.spec.ts +0 -37
- package/src/calculations/buildHttpInstrumentationContext.ts +0 -17
- package/src/calculations/redactHttpHeaders.spec.ts +0 -36
- package/src/calculations/redactHttpHeaders.ts +0 -38
- package/src/calculations/startHttpStage.ts +0 -12
- package/src/index.ts +0 -26
- package/src/models/EventSink.ts +0 -3
- package/src/models/HttpInstrumentationContext.ts +0 -7
- package/src/models/HttpInstrumentationEvent.ts +0 -187
- package/src/models/HttpInstrumentationScope.ts +0 -5
- package/src/models/HttpStageClock.ts +0 -4
- package/src/models/httpInstrumentationStateSymbol.ts +0 -8
- package/src/models/httpInstrumentedHandlerSymbol.ts +0 -3
- package/stryker.config.mjs +0 -3
- package/tsconfig.esm.json +0 -11
- package/tsconfig.json +0 -4
- package/vitest.config.mjs +0 -3
- package/vitest.config.stryker.mjs +0 -3
package/eslint.config.mjs
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { buildDefaultConfig } from '@inversifyjs/foundation-eslint-config';
|
|
2
|
-
|
|
3
|
-
import plugin from '@inversifyjs/eslint-plugin-require-extensions';
|
|
4
|
-
|
|
5
|
-
export default [
|
|
6
|
-
...buildDefaultConfig(
|
|
7
|
-
{
|
|
8
|
-
'@typescript-eslint/consistent-type-imports': [
|
|
9
|
-
'error',
|
|
10
|
-
{
|
|
11
|
-
disallowTypeAnnotations: true,
|
|
12
|
-
fixStyle: 'inline-type-imports',
|
|
13
|
-
prefer: 'type-imports',
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
'require-extensions/require-extensions': 'error',
|
|
17
|
-
'require-extensions/require-index': 'error',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
'require-extensions': plugin,
|
|
21
|
-
},
|
|
22
|
-
),
|
|
23
|
-
];
|
package/prettier.config.mjs
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
afterAll,
|
|
3
|
-
beforeAll,
|
|
4
|
-
describe,
|
|
5
|
-
expect,
|
|
6
|
-
it,
|
|
7
|
-
type Mock,
|
|
8
|
-
vitest,
|
|
9
|
-
} from 'vitest';
|
|
10
|
-
|
|
11
|
-
import { type EventSink } from '../models/EventSink.js';
|
|
12
|
-
import { type HttpInstrumentationEvent } from '../models/HttpInstrumentationEvent.js';
|
|
13
|
-
import { emitHttpInstrumentationEvent } from './emitHttpInstrumentationEvent.js';
|
|
14
|
-
|
|
15
|
-
describe(emitHttpInstrumentationEvent, () => {
|
|
16
|
-
describe('having three sinks and a middle sink that throws', () => {
|
|
17
|
-
let events: HttpInstrumentationEvent[];
|
|
18
|
-
let reportSinkError: Mock<(error: unknown) => void>;
|
|
19
|
-
let eventFixture: HttpInstrumentationEvent;
|
|
20
|
-
|
|
21
|
-
beforeAll(() => {
|
|
22
|
-
events = [];
|
|
23
|
-
reportSinkError = vitest.fn<(error: unknown) => void>();
|
|
24
|
-
eventFixture = {
|
|
25
|
-
executionId: 'execution-1',
|
|
26
|
-
headers: {},
|
|
27
|
-
method: 'GET',
|
|
28
|
-
requestId: 'request-1',
|
|
29
|
-
timestamp: 1,
|
|
30
|
-
type: 'http.request.started',
|
|
31
|
-
url: '/orders',
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const sinks: EventSink<HttpInstrumentationEvent>[] = [
|
|
35
|
-
{
|
|
36
|
-
emit: (event: HttpInstrumentationEvent): void => {
|
|
37
|
-
events.push(event);
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
emit: (): void => {
|
|
42
|
-
throw new Error('sink failed');
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
emit: (event: HttpInstrumentationEvent): void => {
|
|
47
|
-
events.push(event);
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
emitHttpInstrumentationEvent(sinks, eventFixture, reportSinkError);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
afterAll(() => {
|
|
56
|
-
vitest.clearAllMocks();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should deliver the event to the sinks that do not throw', () => {
|
|
60
|
-
expect(events).toStrictEqual([eventFixture, eventFixture]);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should freeze the event', () => {
|
|
64
|
-
expect(Object.isFrozen(eventFixture)).toBe(true);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should report the sink failure', () => {
|
|
68
|
-
expect(reportSinkError).toHaveBeenCalledExactlyOnceWith(
|
|
69
|
-
expect.any(Error),
|
|
70
|
-
);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
describe('having a sink that returns a rejected promise', () => {
|
|
75
|
-
let events: HttpInstrumentationEvent[];
|
|
76
|
-
let reportSinkError: Mock<(error: unknown) => void>;
|
|
77
|
-
let eventFixture: HttpInstrumentationEvent;
|
|
78
|
-
let sinkError: Error;
|
|
79
|
-
|
|
80
|
-
beforeAll(async () => {
|
|
81
|
-
events = [];
|
|
82
|
-
reportSinkError = vitest.fn<(error: unknown) => void>();
|
|
83
|
-
sinkError = new Error('async sink');
|
|
84
|
-
eventFixture = {
|
|
85
|
-
executionId: 'execution-1',
|
|
86
|
-
headers: {},
|
|
87
|
-
method: 'GET',
|
|
88
|
-
requestId: 'request-1',
|
|
89
|
-
timestamp: 1,
|
|
90
|
-
type: 'http.request.started',
|
|
91
|
-
url: '/orders',
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const fulfilledSink: {
|
|
95
|
-
emit: (event: HttpInstrumentationEvent) => Promise<void>;
|
|
96
|
-
} = {
|
|
97
|
-
emit: async (event: HttpInstrumentationEvent): Promise<void> => {
|
|
98
|
-
events.push(event);
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
const rejectedSink: { emit: () => Promise<void> } = {
|
|
102
|
-
emit: async (): Promise<void> => Promise.reject(sinkError),
|
|
103
|
-
};
|
|
104
|
-
const sinks: EventSink<HttpInstrumentationEvent>[] = [
|
|
105
|
-
fulfilledSink,
|
|
106
|
-
rejectedSink,
|
|
107
|
-
{
|
|
108
|
-
emit: (event: HttpInstrumentationEvent): void => {
|
|
109
|
-
events.push(event);
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
];
|
|
113
|
-
|
|
114
|
-
emitHttpInstrumentationEvent(sinks, eventFixture, reportSinkError);
|
|
115
|
-
await Promise.resolve();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
afterAll(() => {
|
|
119
|
-
vitest.clearAllMocks();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should deliver the event to the other sinks', () => {
|
|
123
|
-
expect(events).toStrictEqual([eventFixture, eventFixture]);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should report the rejection', () => {
|
|
127
|
-
expect(reportSinkError).toHaveBeenCalledExactlyOnceWith(sinkError);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { isPromise } from '@inversifyjs/common';
|
|
2
|
-
|
|
3
|
-
import { type EventSink } from '../models/EventSink.js';
|
|
4
|
-
import { type HttpInstrumentationEvent } from '../models/HttpInstrumentationEvent.js';
|
|
5
|
-
|
|
6
|
-
export function emitHttpInstrumentationEvent(
|
|
7
|
-
sinks: readonly EventSink<HttpInstrumentationEvent>[],
|
|
8
|
-
event: HttpInstrumentationEvent,
|
|
9
|
-
reportSinkError: (error: unknown) => void,
|
|
10
|
-
): void {
|
|
11
|
-
const publishedEvent: HttpInstrumentationEvent = Object.freeze(event);
|
|
12
|
-
|
|
13
|
-
for (const sink of sinks) {
|
|
14
|
-
try {
|
|
15
|
-
// EventSink.emit is typed as void, and an async implementation still type-checks.
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
17
|
-
const result: unknown = sink.emit(publishedEvent);
|
|
18
|
-
|
|
19
|
-
if (isPromise(result)) {
|
|
20
|
-
void result.then(undefined, (error: unknown): void => {
|
|
21
|
-
reportSinkError(error);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
} catch (error: unknown) {
|
|
25
|
-
reportSinkError(error);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { type HttpInstrumentationScope } from '../models/HttpInstrumentationScope.js';
|
|
4
|
-
import {
|
|
5
|
-
closeHttpInstrumentationScope,
|
|
6
|
-
initializeHttpInstrumentationRequest,
|
|
7
|
-
openHttpInstrumentationScope,
|
|
8
|
-
} from './httpInstrumentationState.js';
|
|
9
|
-
|
|
10
|
-
describe(openHttpInstrumentationScope, () => {
|
|
11
|
-
describe('having a request with a nested execution', () => {
|
|
12
|
-
describe('when called', () => {
|
|
13
|
-
it('should parent the inner scope to the outer execution', () => {
|
|
14
|
-
const request: object = {};
|
|
15
|
-
|
|
16
|
-
initializeHttpInstrumentationRequest(request, 'request-1');
|
|
17
|
-
|
|
18
|
-
const outer: HttpInstrumentationScope = openHttpInstrumentationScope(
|
|
19
|
-
request,
|
|
20
|
-
'execution-outer',
|
|
21
|
-
);
|
|
22
|
-
const inner: HttpInstrumentationScope = openHttpInstrumentationScope(
|
|
23
|
-
request,
|
|
24
|
-
'execution-inner',
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
expect(outer).toStrictEqual({
|
|
28
|
-
executionId: 'execution-outer',
|
|
29
|
-
parentExecutionId: undefined,
|
|
30
|
-
requestId: 'request-1',
|
|
31
|
-
});
|
|
32
|
-
expect(inner).toStrictEqual({
|
|
33
|
-
executionId: 'execution-inner',
|
|
34
|
-
parentExecutionId: 'execution-outer',
|
|
35
|
-
requestId: 'request-1',
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
closeHttpInstrumentationScope(request, inner.executionId);
|
|
39
|
-
|
|
40
|
-
const sibling: HttpInstrumentationScope = openHttpInstrumentationScope(
|
|
41
|
-
request,
|
|
42
|
-
'execution-sibling',
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
expect(sibling.parentExecutionId).toBe('execution-outer');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
import { type HttpInstrumentationScope } from '../models/HttpInstrumentationScope.js';
|
|
4
|
-
import {
|
|
5
|
-
type HttpInstrumentationState,
|
|
6
|
-
httpInstrumentationStateSymbol,
|
|
7
|
-
} from '../models/httpInstrumentationStateSymbol.js';
|
|
8
|
-
|
|
9
|
-
interface HttpInstrumentationStateCarrier {
|
|
10
|
-
[httpInstrumentationStateSymbol]?: HttpInstrumentationState | undefined;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function initializeHttpInstrumentationRequest(
|
|
14
|
-
request: object,
|
|
15
|
-
requestId: string,
|
|
16
|
-
): void {
|
|
17
|
-
const carrier: HttpInstrumentationStateCarrier = request;
|
|
18
|
-
|
|
19
|
-
if (carrier[httpInstrumentationStateSymbol] !== undefined) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
carrier[httpInstrumentationStateSymbol] = {
|
|
24
|
-
executionStack: [],
|
|
25
|
-
requestId,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function openHttpInstrumentationScope(
|
|
30
|
-
request: object,
|
|
31
|
-
executionId: string,
|
|
32
|
-
): HttpInstrumentationScope {
|
|
33
|
-
const state: HttpInstrumentationState =
|
|
34
|
-
getOrCreateHttpInstrumentationState(request);
|
|
35
|
-
const parentExecutionId: string | undefined = state.executionStack.at(-1);
|
|
36
|
-
|
|
37
|
-
state.executionStack.push(executionId);
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
executionId,
|
|
41
|
-
parentExecutionId,
|
|
42
|
-
requestId: state.requestId,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function closeHttpInstrumentationScope(
|
|
47
|
-
request: object,
|
|
48
|
-
executionId: string,
|
|
49
|
-
): void {
|
|
50
|
-
const state: HttpInstrumentationState | undefined =
|
|
51
|
-
readHttpInstrumentationState(request);
|
|
52
|
-
|
|
53
|
-
if (state === undefined) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const executionIndex: number = state.executionStack.lastIndexOf(executionId);
|
|
58
|
-
|
|
59
|
-
if (executionIndex === -1) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
state.executionStack.splice(executionIndex, 1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function getOrCreateHttpInstrumentationState(
|
|
67
|
-
request: object,
|
|
68
|
-
): HttpInstrumentationState {
|
|
69
|
-
const carrier: HttpInstrumentationStateCarrier = request;
|
|
70
|
-
const state: HttpInstrumentationState | undefined =
|
|
71
|
-
carrier[httpInstrumentationStateSymbol];
|
|
72
|
-
|
|
73
|
-
if (state !== undefined) {
|
|
74
|
-
return state;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const createdState: HttpInstrumentationState = {
|
|
78
|
-
executionStack: [],
|
|
79
|
-
requestId: randomUUID(),
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
carrier[httpInstrumentationStateSymbol] = createdState;
|
|
83
|
-
|
|
84
|
-
return createdState;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function readHttpInstrumentationState(
|
|
88
|
-
request: object,
|
|
89
|
-
): HttpInstrumentationState | undefined {
|
|
90
|
-
return (request as HttpInstrumentationStateCarrier)[
|
|
91
|
-
httpInstrumentationStateSymbol
|
|
92
|
-
];
|
|
93
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { httpInstrumentedHandlerSymbol } from '../models/httpInstrumentedHandlerSymbol.js';
|
|
2
|
-
|
|
3
|
-
export function markHttpInstrumentedHandler(handler: object): void {
|
|
4
|
-
Object.defineProperty(handler, httpInstrumentedHandlerSymbol, {
|
|
5
|
-
configurable: false,
|
|
6
|
-
enumerable: false,
|
|
7
|
-
value: true,
|
|
8
|
-
writable: false,
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function isHttpInstrumentedHandler(handler: object): boolean {
|
|
13
|
-
const record: Record<symbol, unknown> = handler as Record<symbol, unknown>;
|
|
14
|
-
|
|
15
|
-
return record[httpInstrumentedHandlerSymbol] === true;
|
|
16
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
import { startHttpStage } from '../calculations/startHttpStage.js';
|
|
4
|
-
import { type HttpInstrumentationContext } from '../models/HttpInstrumentationContext.js';
|
|
5
|
-
import { type HttpInstrumentationEvent } from '../models/HttpInstrumentationEvent.js';
|
|
6
|
-
import { type HttpInstrumentationScope } from '../models/HttpInstrumentationScope.js';
|
|
7
|
-
import { type HttpStageClock } from '../models/HttpStageClock.js';
|
|
8
|
-
import { emitHttpInstrumentationEvent } from './emitHttpInstrumentationEvent.js';
|
|
9
|
-
import {
|
|
10
|
-
closeHttpInstrumentationScope,
|
|
11
|
-
openHttpInstrumentationScope,
|
|
12
|
-
} from './httpInstrumentationState.js';
|
|
13
|
-
|
|
14
|
-
export type HttpStageOutcome<TResult> =
|
|
15
|
-
| {
|
|
16
|
-
readonly error: unknown;
|
|
17
|
-
}
|
|
18
|
-
| {
|
|
19
|
-
readonly result: TResult;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export async function runInstrumentedHttpStage<TResult>(
|
|
23
|
-
instrumentation: HttpInstrumentationContext,
|
|
24
|
-
request: object,
|
|
25
|
-
createStartedEvent: (
|
|
26
|
-
scope: HttpInstrumentationScope,
|
|
27
|
-
stage: HttpStageClock,
|
|
28
|
-
) => HttpInstrumentationEvent,
|
|
29
|
-
operation: () => Promise<TResult>,
|
|
30
|
-
createExecutedEvent: (
|
|
31
|
-
scope: HttpInstrumentationScope,
|
|
32
|
-
stage: HttpStageClock,
|
|
33
|
-
outcome: HttpStageOutcome<TResult>,
|
|
34
|
-
) => HttpInstrumentationEvent,
|
|
35
|
-
recover: (error: unknown) => Promise<TResult>,
|
|
36
|
-
): Promise<TResult> {
|
|
37
|
-
const scope: HttpInstrumentationScope = openHttpInstrumentationScope(
|
|
38
|
-
request,
|
|
39
|
-
randomUUID(),
|
|
40
|
-
);
|
|
41
|
-
const stage: HttpStageClock = startHttpStage();
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
emitHttpInstrumentationEvent(
|
|
45
|
-
instrumentation.sinks,
|
|
46
|
-
createStartedEvent(scope, stage),
|
|
47
|
-
instrumentation.reportSinkError,
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const result: TResult = await operation();
|
|
52
|
-
|
|
53
|
-
emitHttpInstrumentationEvent(
|
|
54
|
-
instrumentation.sinks,
|
|
55
|
-
createExecutedEvent(scope, stage, {
|
|
56
|
-
result,
|
|
57
|
-
}),
|
|
58
|
-
instrumentation.reportSinkError,
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
return result;
|
|
62
|
-
} catch (error: unknown) {
|
|
63
|
-
emitHttpInstrumentationEvent(
|
|
64
|
-
instrumentation.sinks,
|
|
65
|
-
createExecutedEvent(scope, stage, {
|
|
66
|
-
error,
|
|
67
|
-
}),
|
|
68
|
-
instrumentation.reportSinkError,
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
return await recover(error);
|
|
72
|
-
}
|
|
73
|
-
} finally {
|
|
74
|
-
closeHttpInstrumentationScope(request, scope.executionId);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { type EventSink } from '../models/EventSink.js';
|
|
4
|
-
import { type HttpInstrumentationEvent } from '../models/HttpInstrumentationEvent.js';
|
|
5
|
-
import { buildHttpInstrumentationContext } from './buildHttpInstrumentationContext.js';
|
|
6
|
-
|
|
7
|
-
describe(buildHttpInstrumentationContext, () => {
|
|
8
|
-
describe('having no sinks', () => {
|
|
9
|
-
describe('when called', () => {
|
|
10
|
-
it('should leave instrumentation disabled', () => {
|
|
11
|
-
expect(
|
|
12
|
-
buildHttpInstrumentationContext(undefined, (): void => undefined),
|
|
13
|
-
).toBeUndefined();
|
|
14
|
-
expect(
|
|
15
|
-
buildHttpInstrumentationContext([], (): void => undefined),
|
|
16
|
-
).toBeUndefined();
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
describe('having sinks', () => {
|
|
22
|
-
describe('when called', () => {
|
|
23
|
-
it('should keep the sinks', () => {
|
|
24
|
-
const sink: EventSink<HttpInstrumentationEvent> = {
|
|
25
|
-
emit: (): void => undefined,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
expect(
|
|
29
|
-
buildHttpInstrumentationContext([sink], (): void => undefined),
|
|
30
|
-
).toStrictEqual({
|
|
31
|
-
reportSinkError: expect.any(Function),
|
|
32
|
-
sinks: [sink],
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type EventSink } from '../models/EventSink.js';
|
|
2
|
-
import { type HttpInstrumentationContext } from '../models/HttpInstrumentationContext.js';
|
|
3
|
-
import { type HttpInstrumentationEvent } from '../models/HttpInstrumentationEvent.js';
|
|
4
|
-
|
|
5
|
-
export function buildHttpInstrumentationContext(
|
|
6
|
-
sinks: readonly EventSink<HttpInstrumentationEvent>[] | undefined,
|
|
7
|
-
reportSinkError: (error: unknown) => void,
|
|
8
|
-
): HttpInstrumentationContext | undefined {
|
|
9
|
-
if (sinks === undefined || sinks.length === 0) {
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
reportSinkError,
|
|
15
|
-
sinks,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { redactHttpHeaders } from './redactHttpHeaders.js';
|
|
4
|
-
|
|
5
|
-
describe(redactHttpHeaders, () => {
|
|
6
|
-
describe('having credential headers', () => {
|
|
7
|
-
describe('when called', () => {
|
|
8
|
-
it('should redact credential headers and keep the others', () => {
|
|
9
|
-
const headers: Readonly<Record<string, string | readonly string[]>> =
|
|
10
|
-
redactHttpHeaders({
|
|
11
|
-
authorization: 'secret',
|
|
12
|
-
'content-length': 12,
|
|
13
|
-
cookie: 'session=1',
|
|
14
|
-
'proxy-authorization': 'basic secret',
|
|
15
|
-
'set-cookie': ['a=1', 'b=2'],
|
|
16
|
-
'x-api-key': 'key-1',
|
|
17
|
-
'x-auth-token': 'token-1',
|
|
18
|
-
'x-empty': undefined,
|
|
19
|
-
'x-request-id': 'req-1',
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
expect(Object.isFrozen(headers)).toBe(true);
|
|
23
|
-
expect(headers).toStrictEqual({
|
|
24
|
-
authorization: '[redacted]',
|
|
25
|
-
'content-length': '12',
|
|
26
|
-
cookie: '[redacted]',
|
|
27
|
-
'proxy-authorization': '[redacted]',
|
|
28
|
-
'set-cookie': '[redacted]',
|
|
29
|
-
'x-api-key': '[redacted]',
|
|
30
|
-
'x-auth-token': '[redacted]',
|
|
31
|
-
'x-request-id': 'req-1',
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const REDACTED_HEADER_VALUE: string = '[redacted]';
|
|
2
|
-
|
|
3
|
-
const REDACTED_HTTP_HEADER_NAMES: ReadonlySet<string> = new Set([
|
|
4
|
-
'authorization',
|
|
5
|
-
'cookie',
|
|
6
|
-
'proxy-authorization',
|
|
7
|
-
'set-cookie',
|
|
8
|
-
'x-api-key',
|
|
9
|
-
'x-auth-token',
|
|
10
|
-
]);
|
|
11
|
-
|
|
12
|
-
export function redactHttpHeaders(
|
|
13
|
-
headers: Readonly<
|
|
14
|
-
Record<string, number | string | readonly string[] | undefined>
|
|
15
|
-
>,
|
|
16
|
-
): Record<string, string | readonly string[]> {
|
|
17
|
-
const redactedHeaders: Record<string, string | readonly string[]> = {};
|
|
18
|
-
|
|
19
|
-
for (const key in headers) {
|
|
20
|
-
if (!Object.hasOwn(headers, key)) {
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const value: number | string | readonly string[] | undefined = headers[key];
|
|
25
|
-
|
|
26
|
-
if (value === undefined) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
redactedHeaders[key] = REDACTED_HTTP_HEADER_NAMES.has(key.toLowerCase())
|
|
31
|
-
? REDACTED_HEADER_VALUE
|
|
32
|
-
: typeof value === 'number'
|
|
33
|
-
? value.toString()
|
|
34
|
-
: value;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return Object.freeze(redactedHeaders);
|
|
38
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type HttpStageClock } from '../models/HttpStageClock.js';
|
|
2
|
-
|
|
3
|
-
export function startHttpStage(): HttpStageClock {
|
|
4
|
-
return {
|
|
5
|
-
startedAt: Date.now(),
|
|
6
|
-
startTick: performance.now(),
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function readHttpStageDuration(stage: HttpStageClock): number {
|
|
11
|
-
return performance.now() - stage.startTick;
|
|
12
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export { emitHttpInstrumentationEvent } from './actions/emitHttpInstrumentationEvent.js';
|
|
2
|
-
export {
|
|
3
|
-
closeHttpInstrumentationScope,
|
|
4
|
-
initializeHttpInstrumentationRequest,
|
|
5
|
-
openHttpInstrumentationScope,
|
|
6
|
-
} from './actions/httpInstrumentationState.js';
|
|
7
|
-
export {
|
|
8
|
-
isHttpInstrumentedHandler,
|
|
9
|
-
markHttpInstrumentedHandler,
|
|
10
|
-
} from './actions/markHttpInstrumentedHandler.js';
|
|
11
|
-
export {
|
|
12
|
-
type HttpStageOutcome,
|
|
13
|
-
runInstrumentedHttpStage,
|
|
14
|
-
} from './actions/runInstrumentedHttpStage.js';
|
|
15
|
-
export { buildHttpInstrumentationContext } from './calculations/buildHttpInstrumentationContext.js';
|
|
16
|
-
export { redactHttpHeaders } from './calculations/redactHttpHeaders.js';
|
|
17
|
-
export {
|
|
18
|
-
readHttpStageDuration,
|
|
19
|
-
startHttpStage,
|
|
20
|
-
} from './calculations/startHttpStage.js';
|
|
21
|
-
export { type EventSink } from './models/EventSink.js';
|
|
22
|
-
export { type HttpInstrumentationContext } from './models/HttpInstrumentationContext.js';
|
|
23
|
-
export { type HttpInstrumentationEvent } from './models/HttpInstrumentationEvent.js';
|
|
24
|
-
export { type HttpInstrumentationScope } from './models/HttpInstrumentationScope.js';
|
|
25
|
-
export { httpInstrumentedHandlerSymbol } from './models/httpInstrumentedHandlerSymbol.js';
|
|
26
|
-
export { type HttpStageClock } from './models/HttpStageClock.js';
|
package/src/models/EventSink.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type EventSink } from './EventSink.js';
|
|
2
|
-
import { type HttpInstrumentationEvent } from './HttpInstrumentationEvent.js';
|
|
3
|
-
|
|
4
|
-
export interface HttpInstrumentationContext {
|
|
5
|
-
readonly reportSinkError: (error: unknown) => void;
|
|
6
|
-
readonly sinks: readonly EventSink<HttpInstrumentationEvent>[];
|
|
7
|
-
}
|