@snokam/application-insights 1.3.1 → 1.3.2
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/src/Provider.tsx +5 -2
- package/src/app-router.tsx +5 -2
- package/src/server.ts +4 -0
- package/src/telemetry/cloudRole.ts +8 -0
- package/src/telemetry/exceptionEnvelope.ts +2 -0
- package/src/telemetry/operationId.ts +10 -0
- package/src/telemetry/telemetry.test.ts +54 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.3.2](https://github.com/snokam/components/compare/%40snokam%2Fapplication-insights%401.3.1...%40snokam%2Fapplication-insights%401.3.2) (2026-11-10)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- error pipeline noise filters, burst alerts, telemetry roles and per-activity fan-out logs ([#3496](https://github.com/snokam/components/issues/3496)) ([e41e941](https://github.com/snokam/components/commit/e41e9415a899f075585923989c87b2ea4f27f273))
|
|
11
|
+
|
|
6
12
|
## [1.3.1](https://github.com/snokam/components/compare/%40snokam%2Fapplication-insights%401.3.0...%40snokam%2Fapplication-insights%401.3.1) (2026-11-09)
|
|
7
13
|
|
|
8
14
|
### Bug Fixes
|
package/package.json
CHANGED
package/src/Provider.tsx
CHANGED
|
@@ -11,10 +11,11 @@ import {
|
|
|
11
11
|
IConfiguration,
|
|
12
12
|
ITelemetryPlugin,
|
|
13
13
|
} from "@microsoft/applicationinsights-web";
|
|
14
|
+
import { withCloudRole } from "./telemetry/cloudRole";
|
|
14
15
|
|
|
15
16
|
export interface ProviderProps {
|
|
16
17
|
children: ReactNode;
|
|
17
|
-
config: IConfiguration & IConfig;
|
|
18
|
+
config: IConfiguration & IConfig & { cloudRole?: string };
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export const Provider = ({ children, config }: ProviderProps) => {
|
|
@@ -28,6 +29,7 @@ export const Provider = ({ children, config }: ProviderProps) => {
|
|
|
28
29
|
|
|
29
30
|
useEffect(() => {
|
|
30
31
|
if (!appInsightsRef.current) {
|
|
32
|
+
const { cloudRole, ...sdkConfig } = config;
|
|
31
33
|
appInsightsRef.current = new ApplicationInsights({
|
|
32
34
|
config: {
|
|
33
35
|
maxBatchSizeInBytes: 10000,
|
|
@@ -37,11 +39,12 @@ export const Provider = ({ children, config }: ProviderProps) => {
|
|
|
37
39
|
extensionConfig: {
|
|
38
40
|
[reactPluginRef.current.identifier]: { history: browserHistory },
|
|
39
41
|
},
|
|
40
|
-
...
|
|
42
|
+
...sdkConfig,
|
|
41
43
|
},
|
|
42
44
|
});
|
|
43
45
|
|
|
44
46
|
appInsightsRef.current.loadAppInsights();
|
|
47
|
+
appInsightsRef.current.addTelemetryInitializer(withCloudRole(cloudRole));
|
|
45
48
|
|
|
46
49
|
appInsightsRef.current.addTelemetryInitializer((envelope) => {
|
|
47
50
|
const baseType = envelope.baseType || "";
|
package/src/app-router.tsx
CHANGED
|
@@ -13,10 +13,11 @@ import {
|
|
|
13
13
|
IConfiguration,
|
|
14
14
|
ITelemetryPlugin,
|
|
15
15
|
} from "@microsoft/applicationinsights-web";
|
|
16
|
+
import { withCloudRole } from "./telemetry/cloudRole";
|
|
16
17
|
|
|
17
18
|
export interface ProviderProps {
|
|
18
19
|
children: ReactNode;
|
|
19
|
-
config: IConfiguration & IConfig;
|
|
20
|
+
config: IConfiguration & IConfig & { cloudRole?: string };
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
function PageViewTracker({
|
|
@@ -45,6 +46,7 @@ function AppRouterProvider({ children, config }: ProviderProps) {
|
|
|
45
46
|
if (started.current) return;
|
|
46
47
|
started.current = true;
|
|
47
48
|
const browserHistory = createBrowserHistory();
|
|
49
|
+
const { cloudRole, ...sdkConfig } = config;
|
|
48
50
|
const appInsights = new ApplicationInsights({
|
|
49
51
|
config: {
|
|
50
52
|
maxBatchSizeInBytes: 10000,
|
|
@@ -55,11 +57,12 @@ function AppRouterProvider({ children, config }: ProviderProps) {
|
|
|
55
57
|
extensionConfig: {
|
|
56
58
|
[reactPluginRef.current.identifier]: { history: browserHistory },
|
|
57
59
|
},
|
|
58
|
-
...
|
|
60
|
+
...sdkConfig,
|
|
59
61
|
},
|
|
60
62
|
});
|
|
61
63
|
|
|
62
64
|
appInsights.loadAppInsights();
|
|
65
|
+
appInsights.addTelemetryInitializer(withCloudRole(cloudRole));
|
|
63
66
|
|
|
64
67
|
appInsights.addTelemetryInitializer((envelope) => {
|
|
65
68
|
const baseType = envelope.baseType || "";
|
package/src/server.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type RequestLocation,
|
|
5
5
|
type ServerError,
|
|
6
6
|
} from "./telemetry/exceptionEnvelope";
|
|
7
|
+
import { operationIdFrom } from "./telemetry/operationId";
|
|
7
8
|
|
|
8
9
|
type ErrorRequest = {
|
|
9
10
|
path?: string;
|
|
@@ -57,6 +58,9 @@ export async function onRequestError(
|
|
|
57
58
|
routePath: context.routePath,
|
|
58
59
|
routeType: context.routeType,
|
|
59
60
|
renderSource: context.renderSource,
|
|
61
|
+
operationId: operationIdFrom(request.headers?.["traceparent"], () =>
|
|
62
|
+
crypto.randomUUID().replaceAll("-", "")
|
|
63
|
+
),
|
|
60
64
|
};
|
|
61
65
|
console.error(
|
|
62
66
|
"[server-error]",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ITelemetryItem } from "@microsoft/applicationinsights-web";
|
|
2
|
+
|
|
3
|
+
export function withCloudRole(cloudRole: string | undefined) {
|
|
4
|
+
return (envelope: ITelemetryItem) => {
|
|
5
|
+
if (!cloudRole) return;
|
|
6
|
+
envelope.tags = { ...envelope.tags, "ai.cloud.role": cloudRole };
|
|
7
|
+
};
|
|
8
|
+
}
|
|
@@ -5,6 +5,7 @@ export type RequestLocation = {
|
|
|
5
5
|
routePath?: string;
|
|
6
6
|
routeType?: string;
|
|
7
7
|
renderSource?: string;
|
|
8
|
+
operationId?: string;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export type ServerError = {
|
|
@@ -86,6 +87,7 @@ export function exceptionEnvelope(
|
|
|
86
87
|
"ai.cloud.role": role.name,
|
|
87
88
|
"ai.cloud.roleInstance": role.instance,
|
|
88
89
|
"ai.operation.name": operationName || undefined,
|
|
90
|
+
"ai.operation.id": location.operationId,
|
|
89
91
|
}),
|
|
90
92
|
data: {
|
|
91
93
|
baseType: "ExceptionData",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const TRACEPARENT = /^[\da-f]{2}-([\da-f]{32})-[\da-f]{16}-[\da-f]{2}$/;
|
|
2
|
+
const INVALID_TRACE_ID = "0".repeat(32);
|
|
3
|
+
|
|
4
|
+
export function operationIdFrom(
|
|
5
|
+
traceparent: string | undefined,
|
|
6
|
+
newId: () => string
|
|
7
|
+
) {
|
|
8
|
+
const traceId = traceparent?.match(TRACEPARENT)?.[1];
|
|
9
|
+
return traceId && traceId !== INVALID_TRACE_ID ? traceId : newId();
|
|
10
|
+
}
|
|
@@ -2,6 +2,8 @@ import { test } from "node:test";
|
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import { parseConnectionString } from "./connectionString.ts";
|
|
4
4
|
import { exceptionEnvelope } from "./exceptionEnvelope.ts";
|
|
5
|
+
import { operationIdFrom } from "./operationId.ts";
|
|
6
|
+
import { withCloudRole } from "./cloudRole.ts";
|
|
5
7
|
|
|
6
8
|
const connectionString =
|
|
7
9
|
"InstrumentationKey=7e4c6e13-0000-0000-0000-000000000000;IngestionEndpoint=https://norwayeast-0.in.applicationinsights.azure.com/;LiveEndpoint=https://norwayeast.livediagnostics.monitor.azure.com/;ApplicationId=abc";
|
|
@@ -31,6 +33,7 @@ test("a render crash becomes an error-level exception for the site", () => {
|
|
|
31
33
|
path: "/skjer/julebord",
|
|
32
34
|
routePath: "/[host]/skjer/[slug]",
|
|
33
35
|
routeType: "render",
|
|
36
|
+
operationId: "4bf92f3577b34da6a3ce929d0e0e4736",
|
|
34
37
|
},
|
|
35
38
|
},
|
|
36
39
|
{ name: "app-plfm-web-t", instance: "web-1" },
|
|
@@ -42,6 +45,10 @@ test("a render crash becomes an error-level exception for the site", () => {
|
|
|
42
45
|
assert.equal(envelope.time, "2026-11-08T10:00:00.000Z");
|
|
43
46
|
assert.equal(envelope.tags["ai.cloud.role"], "app-plfm-web-t");
|
|
44
47
|
assert.equal(envelope.tags["ai.operation.name"], "GET /[host]/skjer/[slug]");
|
|
48
|
+
assert.equal(
|
|
49
|
+
envelope.tags["ai.operation.id"],
|
|
50
|
+
"4bf92f3577b34da6a3ce929d0e0e4736"
|
|
51
|
+
);
|
|
45
52
|
const data = envelope.data.baseData;
|
|
46
53
|
assert.equal(data.severityLevel, 3);
|
|
47
54
|
assert.equal(data.problemId, "ReferenceError at /[host]/skjer/[slug]");
|
|
@@ -49,6 +56,7 @@ test("a render crash becomes an error-level exception for the site", () => {
|
|
|
49
56
|
assert.equal(data.exceptions[0].message, "localStorage is not defined");
|
|
50
57
|
assert.equal(data.exceptions[0].hasFullStack, true);
|
|
51
58
|
assert.equal(data.properties.path, "/skjer/julebord");
|
|
59
|
+
assert.equal(data.properties.routePath, "/[host]/skjer/[slug]");
|
|
52
60
|
});
|
|
53
61
|
|
|
54
62
|
test("a thrown value that is not an Error is still reported", () => {
|
|
@@ -107,3 +115,49 @@ test("a request that never got a response names its cause", () => {
|
|
|
107
115
|
"TimeoutError: The operation was aborted due to timeout"
|
|
108
116
|
);
|
|
109
117
|
});
|
|
118
|
+
|
|
119
|
+
test("a server error joins the trace of the request that caused it", () => {
|
|
120
|
+
const id = operationIdFrom(
|
|
121
|
+
"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
|
|
122
|
+
() => "fresh"
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
assert.equal(id, "4bf92f3577b34da6a3ce929d0e0e4736");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("a server error without a usable trace gets its own operation id", () => {
|
|
129
|
+
assert.equal(
|
|
130
|
+
operationIdFrom(undefined, () => "fresh"),
|
|
131
|
+
"fresh"
|
|
132
|
+
);
|
|
133
|
+
assert.equal(
|
|
134
|
+
operationIdFrom("garbage", () => "fresh"),
|
|
135
|
+
"fresh"
|
|
136
|
+
);
|
|
137
|
+
assert.equal(
|
|
138
|
+
operationIdFrom(
|
|
139
|
+
"00-00000000000000000000000000000000-00f067aa0ba902b7-01",
|
|
140
|
+
() => "fresh"
|
|
141
|
+
),
|
|
142
|
+
"fresh"
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("browser telemetry carries the configured role", () => {
|
|
147
|
+
const envelope = { name: "PageView", tags: { "ai.session.id": "s" } };
|
|
148
|
+
|
|
149
|
+
withCloudRole("web-browser")(envelope);
|
|
150
|
+
|
|
151
|
+
assert.deepEqual(envelope.tags, {
|
|
152
|
+
"ai.session.id": "s",
|
|
153
|
+
"ai.cloud.role": "web-browser",
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("browser telemetry is left alone without a role", () => {
|
|
158
|
+
const envelope = { name: "PageView", tags: {} };
|
|
159
|
+
|
|
160
|
+
withCloudRole(undefined)(envelope);
|
|
161
|
+
|
|
162
|
+
assert.deepEqual(envelope.tags, {});
|
|
163
|
+
});
|