@opentelemetry/browser-instrumentation 0.2.0 → 0.4.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.
Files changed (35) hide show
  1. package/README.md +115 -0
  2. package/dist/console/index.d.ts +3 -0
  3. package/dist/console/index.js +2 -0
  4. package/dist/console/instrumentation.d.ts +21 -0
  5. package/dist/console/instrumentation.js +84 -0
  6. package/dist/console/instrumentation.js.map +1 -0
  7. package/dist/console/semconv.js +14 -0
  8. package/dist/console/semconv.js.map +1 -0
  9. package/dist/console/types.d.ts +25 -0
  10. package/dist/navigation/index.d.ts +4 -0
  11. package/dist/navigation/index.js +3 -0
  12. package/dist/navigation/instrumentation.d.ts +29 -0
  13. package/dist/navigation/instrumentation.js +156 -0
  14. package/dist/navigation/instrumentation.js.map +1 -0
  15. package/dist/navigation/semconv.js +22 -0
  16. package/dist/navigation/semconv.js.map +1 -0
  17. package/dist/navigation/types.d.ts +21 -0
  18. package/dist/navigation/utils.d.ts +12 -0
  19. package/dist/navigation/utils.js +77 -0
  20. package/dist/navigation/utils.js.map +1 -0
  21. package/dist/navigation-timing/semconv.js +24 -24
  22. package/dist/navigation-timing/semconv.js.map +1 -1
  23. package/dist/package.js +1 -1
  24. package/dist/resource-timing/idle-callback-shim.js +35 -0
  25. package/dist/resource-timing/idle-callback-shim.js.map +1 -0
  26. package/dist/resource-timing/index.d.ts +3 -0
  27. package/dist/resource-timing/index.js +2 -0
  28. package/dist/resource-timing/instrumentation.d.ts +33 -0
  29. package/dist/resource-timing/instrumentation.js +160 -0
  30. package/dist/resource-timing/instrumentation.js.map +1 -0
  31. package/dist/resource-timing/semconv.js +131 -0
  32. package/dist/resource-timing/semconv.js.map +1 -0
  33. package/dist/resource-timing/types.d.ts +38 -0
  34. package/dist/utils/getElementCSSSelector.js.map +1 -1
  35. package/package.json +14 -8
package/README.md CHANGED
@@ -13,7 +13,9 @@ npm install @opentelemetry/browser-instrumentation
13
13
 
14
14
  ## Instrumentations
15
15
 
16
+ - [Navigation](#navigation) — automatic instrumentation for browser navigations (initial load and SPA route changes)
16
17
  - [Navigation Timing](#navigation-timing) — automatic instrumentation for navigation timing
18
+ - [Resource Timing](#resource-timing) — automatic instrumentation for resource timing
17
19
  - [User Action](#user-action) — automatic instrumentation for user actions (clicks)
18
20
  - [Web Vitals](#web-vitals) — automatic instrumentation for Core Web Vitals
19
21
 
@@ -27,7 +29,9 @@ import {
27
29
  SimpleLogRecordProcessor,
28
30
  } from '@opentelemetry/sdk-logs';
29
31
  import { registerInstrumentations } from '@opentelemetry/instrumentation';
32
+ import { NavigationInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/navigation';
30
33
  import { NavigationTimingInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/navigation-timing';
34
+ import { ResourceTimingInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/resource-timing';
31
35
  import { UserActionInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/user-action';
32
36
  import { WebVitalsInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/web-vitals';
33
37
 
@@ -40,7 +44,9 @@ logs.setGlobalLoggerProvider(logProvider);
40
44
 
41
45
  registerInstrumentations({
42
46
  instrumentations: [
47
+ new NavigationInstrumentation(),
43
48
  new NavigationTimingInstrumentation(),
49
+ new ResourceTimingInstrumentation(),
44
50
  new UserActionInstrumentation(),
45
51
  new WebVitalsInstrumentation(),
46
52
  ],
@@ -49,6 +55,62 @@ registerInstrumentations({
49
55
 
50
56
  ---
51
57
 
58
+ ### Navigation
59
+
60
+ ```typescript
61
+ import { NavigationInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/navigation';
62
+ ```
63
+
64
+ Emits a `browser.navigation` event for the initial page load (hard navigation) and for subsequent in-page navigations (soft navigations), including `history.pushState`, `history.replaceState`, `popstate`, and hash changes. When enabled via config, the [Navigation API](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API) is used in preference to patching `history`.
65
+
66
+ #### Configuration
67
+
68
+ ```typescript
69
+ import {
70
+ NavigationInstrumentation,
71
+ defaultSanitizeUrl,
72
+ } from '@opentelemetry/browser-instrumentation/experimental/navigation';
73
+
74
+ new NavigationInstrumentation({
75
+ // Use window.navigation (Navigation API) when available instead of
76
+ // patching history.pushState / history.replaceState. Default: false.
77
+ useNavigationApiIfAvailable: true,
78
+
79
+ // Rewrite the captured URL before it is emitted. Useful for stripping
80
+ // path segments, query parameters, or tokens that should not be exported.
81
+ sanitizeUrl: (url) => defaultSanitizeUrl(url),
82
+
83
+ // Mutate the log record before it is emitted (e.g. attach custom attributes).
84
+ applyCustomLogRecordData: (logRecord) => {
85
+ logRecord.attributes = {
86
+ ...logRecord.attributes,
87
+ 'app.route.id': '...',
88
+ };
89
+ },
90
+ });
91
+ ```
92
+
93
+ | Option | Type | Default | Description |
94
+ |--------|------|---------|-------------|
95
+ | `useNavigationApiIfAvailable` | `boolean` | `false` | When `true`, subscribes to the Navigation API (`currententrychange`) instead of patching `history.pushState` / `history.replaceState`. Falls back to history patching when the Navigation API is unavailable. |
96
+ | `sanitizeUrl` | `(url: string) => string` | — | Called before the URL is written to `url.full`. |
97
+ | `applyCustomLogRecordData` | `(logRecord: LogRecord) => void` | — | Hook to modify log records before they are emitted. Errors thrown from this hook are caught and logged via the instrumentation diag logger. |
98
+
99
+ `defaultSanitizeUrl` is exported for composition — it redacts `user:password@` credentials and a set of common sensitive query parameters (`api_key`, `token`, `password`, etc.).
100
+
101
+ #### Captured Attributes
102
+
103
+ Each `browser.navigation` event includes:
104
+
105
+ | Attribute | Description |
106
+ |-----------|-------------|
107
+ | `url.full` | The destination URL (after `sanitizeUrl` if configured). |
108
+ | `browser.navigation.same_document` | `true` for SPA route changes; `false` for full-page loads. |
109
+ | `browser.navigation.hash_change` | `true` when the navigation only adds or changes the URL fragment. |
110
+ | `browser.navigation.type` | One of `push`, `replace`, `reload`, `traverse` (omitted for the initial hard navigation). |
111
+
112
+ ---
113
+
52
114
  ### Navigation Timing
53
115
 
54
116
  ```typescript
@@ -59,6 +121,59 @@ Provides automatic instrumentation for [Navigation Timing](https://developer.moz
59
121
 
60
122
  ---
61
123
 
124
+ ### Resource Timing
125
+
126
+ ```typescript
127
+ import { ResourceTimingInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/resource-timing';
128
+ ```
129
+
130
+ Provides automatic instrumentation for [Resource Timing](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming) in web applications, capturing performance metrics for all resources loaded by the browser (scripts, stylesheets, images, fonts, XHR/fetch requests, etc.).
131
+
132
+ - Uses `requestIdleCallback` to avoid blocking the main thread (with automatic `setTimeout` fallback for Safari)
133
+ - Processes resources in configurable batches
134
+ - Captures historical resources loaded before instrumentation was enabled via buffered mode
135
+ - Flushes pending entries on visibility change to prevent data loss
136
+
137
+ #### Configuration
138
+
139
+ ```typescript
140
+ new ResourceTimingInstrumentation({
141
+ // Process 100 resources per batch (default: 50)
142
+ batchSize: 100,
143
+
144
+ // Wait max 2 seconds for idle time before forcing processing (default: 1000)
145
+ forceProcessingAfter: 2000,
146
+
147
+ // Spend max 100ms processing per idle callback (default: 50)
148
+ maxProcessingTime: 100,
149
+
150
+ // Maximum queue size before forcing immediate flush (default: 1000)
151
+ maxQueueSize: 2000,
152
+ });
153
+ ```
154
+
155
+ | Option | Type | Default | Description |
156
+ |--------|------|---------|-------------|
157
+ | `batchSize` | `number` | `50` | Number of resources to process per batch. |
158
+ | `forceProcessingAfter` | `number` | `1000` | Maximum time (ms) to wait for an idle callback before forcing processing. |
159
+ | `maxProcessingTime` | `number` | `50` | Maximum time (ms) to spend processing resources per idle callback. |
160
+ | `maxQueueSize` | `number` | `1000` | Maximum number of resources to queue before forcing immediate flush. |
161
+
162
+ #### Captured Data
163
+
164
+ Each resource timing event includes:
165
+
166
+ - **URL** and **Initiator Type** (script, css, img, xmlhttprequest, fetch, etc.)
167
+ - **Duration** — total resource load time
168
+ - **Timing Phases** — DNS lookup, TCP connection, TLS handshake, request, response
169
+ - **Size Metrics** — transfer size, encoded size, decoded size
170
+ - **Protocol** — HTTP version (h1, h2, h3)
171
+ - **Redirect Info** — redirect timing if applicable
172
+ - **Service Worker** — worker start time if intercepted
173
+ - **Render Blocking** — whether the resource blocked rendering (Chromium only)
174
+
175
+ ---
176
+
62
177
  ### User Action
63
178
 
64
179
  ```typescript
@@ -0,0 +1,3 @@
1
+ import { ConsoleInstrumentationConfig, ConsoleMethod } from "./types.js";
2
+ import { ConsoleInstrumentation } from "./instrumentation.js";
3
+ export { ConsoleInstrumentation, type ConsoleInstrumentationConfig, type ConsoleMethod };
@@ -0,0 +1,2 @@
1
+ import { ConsoleInstrumentation } from "./instrumentation.js";
2
+ export { ConsoleInstrumentation };
@@ -0,0 +1,21 @@
1
+ import { ConsoleInstrumentationConfig } from "./types.js";
2
+ import { InstrumentationBase } from "@opentelemetry/instrumentation";
3
+
4
+ //#region src/console/instrumentation.d.ts
5
+ /**
6
+ * OpenTelemetry instrumentation that captures console calls and emits them as OpenTelemetry logs.
7
+ */
8
+ declare class ConsoleInstrumentation extends InstrumentationBase<ConsoleInstrumentationConfig> {
9
+ private _isPatched;
10
+ private _active;
11
+ constructor(config?: ConsoleInstrumentationConfig);
12
+ protected init(): never[];
13
+ private _getMessageSerializer;
14
+ private _getLogMethods;
15
+ private _patchConsoleMethod;
16
+ enable(): void;
17
+ disable(): void;
18
+ }
19
+ //#endregion
20
+ export { ConsoleInstrumentation };
21
+ //# sourceMappingURL=instrumentation.d.ts.map
@@ -0,0 +1,84 @@
1
+ import { version } from "../package.js";
2
+ import { ATTR_CONSOLE_METHOD, CONSOLE_LOG_EVENT_NAME } from "./semconv.js";
3
+ import { context } from "@opentelemetry/api";
4
+ import { SeverityNumber } from "@opentelemetry/api-logs";
5
+ import { InstrumentationBase } from "@opentelemetry/instrumentation";
6
+ //#region src/console/instrumentation.ts
7
+ const DEFAULT_LOG_METHODS = [
8
+ "log",
9
+ "warn",
10
+ "error",
11
+ "info",
12
+ "debug"
13
+ ];
14
+ const SEVERITY_MAP = {
15
+ debug: SeverityNumber.DEBUG,
16
+ log: SeverityNumber.INFO,
17
+ info: SeverityNumber.INFO,
18
+ warn: SeverityNumber.WARN,
19
+ error: SeverityNumber.ERROR
20
+ };
21
+ /**
22
+ * Default serializer for console arguments.
23
+ * Joins arguments as strings.
24
+ */
25
+ function defaultMessageSerializer(args) {
26
+ return args.map((arg) => {
27
+ if (typeof arg === "object" && arg !== null) try {
28
+ return JSON.stringify(arg);
29
+ } catch {
30
+ return String(arg);
31
+ }
32
+ return String(arg);
33
+ }).join(" ");
34
+ }
35
+ /**
36
+ * OpenTelemetry instrumentation that captures console calls and emits them as OpenTelemetry logs.
37
+ */
38
+ var ConsoleInstrumentation = class extends InstrumentationBase {
39
+ constructor(config = {}) {
40
+ super("@opentelemetry/browser-instrumentation/console", version, config);
41
+ }
42
+ init() {
43
+ return [];
44
+ }
45
+ _getMessageSerializer() {
46
+ return this._config.messageSerializer ?? defaultMessageSerializer;
47
+ }
48
+ _getLogMethods() {
49
+ return this._config.logMethods ?? DEFAULT_LOG_METHODS;
50
+ }
51
+ _patchConsoleMethod(method) {
52
+ const instrumentation = this;
53
+ return function patchConsoleMethod(original) {
54
+ return function(...args) {
55
+ if (instrumentation._active && instrumentation._getLogMethods().includes(method)) {
56
+ const logContext = context.active();
57
+ const body = instrumentation._getMessageSerializer()(args);
58
+ instrumentation.logger.emit({
59
+ body,
60
+ eventName: CONSOLE_LOG_EVENT_NAME,
61
+ severityNumber: SEVERITY_MAP[method],
62
+ severityText: method,
63
+ context: logContext,
64
+ attributes: { [ATTR_CONSOLE_METHOD]: method }
65
+ });
66
+ }
67
+ return original.apply(this, args);
68
+ };
69
+ };
70
+ }
71
+ enable() {
72
+ this._active = true;
73
+ if (this._isPatched) return;
74
+ this._isPatched = true;
75
+ for (const method of DEFAULT_LOG_METHODS) if (typeof console[method] === "function") this._wrap(console, method, this._patchConsoleMethod(method));
76
+ }
77
+ disable() {
78
+ this._active = false;
79
+ }
80
+ };
81
+ //#endregion
82
+ export { ConsoleInstrumentation };
83
+
84
+ //# sourceMappingURL=instrumentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.js","names":[],"sources":["../../src/console/instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { context } from '@opentelemetry/api';\nimport { SeverityNumber } from '@opentelemetry/api-logs';\nimport { InstrumentationBase } from '@opentelemetry/instrumentation';\nimport { version } from '../../package.json' with { type: 'json' };\nimport { ATTR_CONSOLE_METHOD, CONSOLE_LOG_EVENT_NAME } from './semconv.ts';\nimport type { ConsoleInstrumentationConfig, ConsoleMethod } from './types.ts';\n\nconst DEFAULT_LOG_METHODS: ConsoleMethod[] = [\n 'log',\n 'warn',\n 'error',\n 'info',\n 'debug',\n];\n\nconst SEVERITY_MAP: Record<ConsoleMethod, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\n/**\n * Default serializer for console arguments.\n * Joins arguments as strings.\n */\nfunction defaultMessageSerializer(args: unknown[]): string {\n return args\n .map((arg) => {\n if (typeof arg === 'object' && arg !== null) {\n try {\n return JSON.stringify(arg);\n } catch {\n // Circular reference or other error, fallback to String\n return String(arg);\n }\n }\n return String(arg);\n })\n .join(' ');\n}\n\n/**\n * OpenTelemetry instrumentation that captures console calls and emits them as OpenTelemetry logs.\n */\nexport class ConsoleInstrumentation extends InstrumentationBase<ConsoleInstrumentationConfig> {\n private declare _isPatched: boolean;\n private declare _active: boolean;\n\n constructor(config: ConsoleInstrumentationConfig = {}) {\n super('@opentelemetry/browser-instrumentation/console', version, config);\n }\n\n protected override init() {\n return [];\n }\n\n private _getMessageSerializer(): (args: unknown[]) => string {\n return this._config.messageSerializer ?? defaultMessageSerializer;\n }\n\n private _getLogMethods(): ConsoleMethod[] {\n return this._config.logMethods ?? DEFAULT_LOG_METHODS;\n }\n\n private _patchConsoleMethod(\n method: ConsoleMethod,\n ): (original: Console[ConsoleMethod]) => Console[ConsoleMethod] {\n const instrumentation = this;\n\n return function patchConsoleMethod(original: Console[ConsoleMethod]) {\n return function (this: Console, ...args: unknown[]) {\n if (\n instrumentation._active &&\n instrumentation._getLogMethods().includes(method)\n ) {\n const logContext = context.active();\n const body = instrumentation._getMessageSerializer()(args);\n\n instrumentation.logger.emit({\n body,\n eventName: CONSOLE_LOG_EVENT_NAME,\n severityNumber: SEVERITY_MAP[method],\n severityText: method,\n context: logContext,\n attributes: {\n [ATTR_CONSOLE_METHOD]: method,\n },\n });\n }\n\n return original.apply(this, args);\n } as Console[ConsoleMethod];\n };\n }\n\n override enable(): void {\n this._active = true;\n if (this._isPatched) {\n return;\n }\n this._isPatched = true;\n for (const method of DEFAULT_LOG_METHODS) {\n if (typeof console[method] === 'function') {\n this._wrap(console, method, this._patchConsoleMethod(method));\n }\n }\n }\n\n override disable(): void {\n this._active = false;\n }\n}\n"],"mappings":";;;;;;AAYA,MAAM,sBAAuC;CAC3C;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,eAAsD;CAC1D,OAAO,eAAe;CACtB,KAAK,eAAe;CACpB,MAAM,eAAe;CACrB,MAAM,eAAe;CACrB,OAAO,eAAe;CACvB;;;;;AAMD,SAAS,yBAAyB,MAAyB;AACzD,QAAO,KACJ,KAAK,QAAQ;AACZ,MAAI,OAAO,QAAQ,YAAY,QAAQ,KACrC,KAAI;AACF,UAAO,KAAK,UAAU,IAAI;UACpB;AAEN,UAAO,OAAO,IAAI;;AAGtB,SAAO,OAAO,IAAI;GAClB,CACD,KAAK,IAAI;;;;;AAMd,IAAa,yBAAb,cAA4C,oBAAkD;CAI5F,YAAY,SAAuC,EAAE,EAAE;AACrD,QAAM,kDAAkD,SAAS,OAAO;;CAG1E,OAA0B;AACxB,SAAO,EAAE;;CAGX,wBAA6D;AAC3D,SAAO,KAAK,QAAQ,qBAAqB;;CAG3C,iBAA0C;AACxC,SAAO,KAAK,QAAQ,cAAc;;CAGpC,oBACE,QAC8D;EAC9D,MAAM,kBAAkB;AAExB,SAAO,SAAS,mBAAmB,UAAkC;AACnE,UAAO,SAAyB,GAAG,MAAiB;AAClD,QACE,gBAAgB,WAChB,gBAAgB,gBAAgB,CAAC,SAAS,OAAO,EACjD;KACA,MAAM,aAAa,QAAQ,QAAQ;KACnC,MAAM,OAAO,gBAAgB,uBAAuB,CAAC,KAAK;AAE1D,qBAAgB,OAAO,KAAK;MAC1B;MACA,WAAW;MACX,gBAAgB,aAAa;MAC7B,cAAc;MACd,SAAS;MACT,YAAY,GACT,sBAAsB,QACxB;MACF,CAAC;;AAGJ,WAAO,SAAS,MAAM,MAAM,KAAK;;;;CAKvC,SAAwB;AACtB,OAAK,UAAU;AACf,MAAI,KAAK,WACP;AAEF,OAAK,aAAa;AAClB,OAAK,MAAM,UAAU,oBACnB,KAAI,OAAO,QAAQ,YAAY,WAC7B,MAAK,MAAM,SAAS,QAAQ,KAAK,oBAAoB,OAAO,CAAC;;CAKnE,UAAyB;AACvB,OAAK,UAAU"}
@@ -0,0 +1,14 @@
1
+ //#region src/console/semconv.ts
2
+ /**
3
+ * Event name for console log events.
4
+ */
5
+ const CONSOLE_LOG_EVENT_NAME = "browser.console";
6
+ /**
7
+ * The console method that was called (e.g., 'log', 'warn', 'error', 'info', 'debug').
8
+ * @example 'error'
9
+ */
10
+ const ATTR_CONSOLE_METHOD = "browser.console.method";
11
+ //#endregion
12
+ export { ATTR_CONSOLE_METHOD, CONSOLE_LOG_EVENT_NAME };
13
+
14
+ //# sourceMappingURL=semconv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semconv.js","names":[],"sources":["../../src/console/semconv.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/*\n * This file contains a copy of unstable semantic convention definitions\n * used by this package.\n * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv\n */\n\n/**\n * Event name for console log events.\n */\nexport const CONSOLE_LOG_EVENT_NAME = 'browser.console';\n\n/**\n * The console method that was called (e.g., 'log', 'warn', 'error', 'info', 'debug').\n * @example 'error'\n */\nexport const ATTR_CONSOLE_METHOD = 'browser.console.method';\n"],"mappings":";;;;AAcA,MAAa,yBAAyB;;;;;AAMtC,MAAa,sBAAsB"}
@@ -0,0 +1,25 @@
1
+ import { InstrumentationConfig } from "@opentelemetry/instrumentation";
2
+
3
+ //#region src/console/types.d.ts
4
+ /**
5
+ * Console methods that can be instrumented.
6
+ */
7
+ type ConsoleMethod = 'log' | 'warn' | 'error' | 'info' | 'debug';
8
+ /**
9
+ * ConsoleInstrumentation Configuration
10
+ */
11
+ interface ConsoleInstrumentationConfig extends InstrumentationConfig {
12
+ /**
13
+ * Console methods to instrument.
14
+ * @default ['log', 'warn', 'error', 'info', 'debug']
15
+ */
16
+ logMethods?: ConsoleMethod[];
17
+ /**
18
+ * Custom serializer for console arguments.
19
+ * @default Joins args as strings
20
+ */
21
+ messageSerializer?: (args: unknown[]) => string;
22
+ }
23
+ //#endregion
24
+ export { ConsoleInstrumentationConfig, ConsoleMethod };
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { NavigationInstrumentationConfig, NavigationType } from "./types.js";
2
+ import { NavigationInstrumentation } from "./instrumentation.js";
3
+ import { defaultSanitizeUrl } from "./utils.js";
4
+ export { NavigationInstrumentation, type NavigationInstrumentationConfig, type NavigationType, defaultSanitizeUrl };
@@ -0,0 +1,3 @@
1
+ import { defaultSanitizeUrl } from "./utils.js";
2
+ import { NavigationInstrumentation } from "./instrumentation.js";
3
+ export { NavigationInstrumentation, defaultSanitizeUrl };
@@ -0,0 +1,29 @@
1
+ import { NavigationInstrumentationConfig } from "./types.js";
2
+ import { InstrumentationBase } from "@opentelemetry/instrumentation";
3
+
4
+ //#region src/navigation/instrumentation.d.ts
5
+ declare class NavigationInstrumentation extends InstrumentationBase<NavigationInstrumentationConfig> {
6
+ private _isEnabled;
7
+ private _isHistoryPatched;
8
+ private _hasProcessedInitialLoad;
9
+ private _lastUrl;
10
+ private _onDOMContentLoaded?;
11
+ private _onPopState?;
12
+ private _onCurrentEntryChange?;
13
+ constructor(config?: NavigationInstrumentationConfig);
14
+ protected init(): never[];
15
+ enable(): void;
16
+ disable(): void;
17
+ private _getNavigationApi;
18
+ private _onHardNavigation;
19
+ private _onSoftNavigation;
20
+ private _waitForPageLoad;
21
+ private _patchHistoryApi;
22
+ private _patchHistoryMethod;
23
+ private _applyCustomLogRecordData;
24
+ private _determineSameDocument;
25
+ private _mapChangeStateToType;
26
+ }
27
+ //#endregion
28
+ export { NavigationInstrumentation };
29
+ //# sourceMappingURL=instrumentation.d.ts.map
@@ -0,0 +1,156 @@
1
+ import { version } from "../package.js";
2
+ import { ATTR_BROWSER_NAVIGATION_HASH_CHANGE, ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT, ATTR_BROWSER_NAVIGATION_TYPE, ATTR_URL_FULL, BROWSER_NAVIGATION_EVENT_NAME } from "./semconv.js";
3
+ import { isHashChange } from "./utils.js";
4
+ import { SeverityNumber } from "@opentelemetry/api-logs";
5
+ import { InstrumentationBase, safeExecuteInTheMiddle } from "@opentelemetry/instrumentation";
6
+ //#region src/navigation/instrumentation.ts
7
+ var NavigationInstrumentation = class extends InstrumentationBase {
8
+ constructor(config = {}) {
9
+ super("@opentelemetry/browser-instrumentation/navigation", version, config);
10
+ this._lastUrl = location.href;
11
+ }
12
+ init() {
13
+ return [];
14
+ }
15
+ enable() {
16
+ if (this._isEnabled) return;
17
+ this._isEnabled = true;
18
+ const navigationApi = this._getNavigationApi();
19
+ if (!navigationApi && !this._isHistoryPatched) {
20
+ this._patchHistoryApi();
21
+ this._isHistoryPatched = true;
22
+ }
23
+ this._waitForPageLoad();
24
+ if (navigationApi) {
25
+ this._onCurrentEntryChange = (event) => {
26
+ this._onSoftNavigation("currententrychange", event);
27
+ };
28
+ navigationApi.addEventListener("currententrychange", this._onCurrentEntryChange);
29
+ } else {
30
+ this._onPopState = () => {
31
+ this._onSoftNavigation("popstate");
32
+ };
33
+ window.addEventListener("popstate", this._onPopState);
34
+ }
35
+ }
36
+ disable() {
37
+ if (!this._isEnabled) return;
38
+ this._isEnabled = false;
39
+ if (this._onDOMContentLoaded) {
40
+ document.removeEventListener("DOMContentLoaded", this._onDOMContentLoaded);
41
+ this._onDOMContentLoaded = void 0;
42
+ }
43
+ if (this._onPopState) {
44
+ window.removeEventListener("popstate", this._onPopState);
45
+ this._onPopState = void 0;
46
+ }
47
+ if (this._onCurrentEntryChange) {
48
+ this._getNavigationApi()?.removeEventListener("currententrychange", this._onCurrentEntryChange);
49
+ this._onCurrentEntryChange = void 0;
50
+ }
51
+ this._hasProcessedInitialLoad = false;
52
+ }
53
+ _getNavigationApi() {
54
+ if (!this.getConfig().useNavigationApiIfAvailable) return;
55
+ return window.navigation;
56
+ }
57
+ _onHardNavigation() {
58
+ const cfg = this.getConfig();
59
+ const logRecord = {
60
+ eventName: BROWSER_NAVIGATION_EVENT_NAME,
61
+ severityNumber: SeverityNumber.INFO,
62
+ attributes: {
63
+ [ATTR_URL_FULL]: cfg.sanitizeUrl ? cfg.sanitizeUrl(document.documentURI) : document.documentURI,
64
+ [ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT]: false,
65
+ [ATTR_BROWSER_NAVIGATION_HASH_CHANGE]: false
66
+ }
67
+ };
68
+ this._applyCustomLogRecordData(logRecord);
69
+ this.logger.emit(logRecord);
70
+ }
71
+ _onSoftNavigation(changeState, navigationEvent) {
72
+ const referrerUrl = this._lastUrl;
73
+ const currentUrl = changeState === "currententrychange" && navigationEvent?.target?.currentEntry?.url ? navigationEvent.target.currentEntry.url : location.href;
74
+ if (referrerUrl === currentUrl) return;
75
+ const navType = this._mapChangeStateToType(changeState, navigationEvent);
76
+ const sameDocument = this._determineSameDocument(referrerUrl, currentUrl);
77
+ const hashChange = isHashChange(referrerUrl, currentUrl);
78
+ const cfg = this.getConfig();
79
+ const logRecord = {
80
+ eventName: BROWSER_NAVIGATION_EVENT_NAME,
81
+ severityNumber: SeverityNumber.INFO,
82
+ attributes: {
83
+ [ATTR_URL_FULL]: cfg.sanitizeUrl ? cfg.sanitizeUrl(currentUrl) : currentUrl,
84
+ [ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT]: sameDocument,
85
+ [ATTR_BROWSER_NAVIGATION_HASH_CHANGE]: hashChange,
86
+ ...navType ? { [ATTR_BROWSER_NAVIGATION_TYPE]: navType } : {}
87
+ }
88
+ };
89
+ this._applyCustomLogRecordData(logRecord);
90
+ this.logger.emit(logRecord);
91
+ this._lastUrl = currentUrl;
92
+ }
93
+ _waitForPageLoad() {
94
+ if (document.readyState === "complete" && !this._hasProcessedInitialLoad) {
95
+ this._hasProcessedInitialLoad = true;
96
+ this._onHardNavigation();
97
+ return;
98
+ }
99
+ this._onDOMContentLoaded = () => {
100
+ if (!this._hasProcessedInitialLoad) {
101
+ this._hasProcessedInitialLoad = true;
102
+ this._onHardNavigation();
103
+ }
104
+ };
105
+ document.addEventListener("DOMContentLoaded", this._onDOMContentLoaded);
106
+ }
107
+ _patchHistoryApi() {
108
+ this._wrap(history, "replaceState", this._patchHistoryMethod("replaceState"));
109
+ this._wrap(history, "pushState", this._patchHistoryMethod("pushState"));
110
+ }
111
+ _patchHistoryMethod(changeState) {
112
+ const plugin = this;
113
+ return (original) => {
114
+ return function patchedHistoryMethod(...args) {
115
+ if (!plugin._isEnabled) return original.apply(this, args);
116
+ const result = original.apply(this, args);
117
+ if (location.href !== plugin._lastUrl) plugin._onSoftNavigation(changeState);
118
+ return result;
119
+ };
120
+ };
121
+ }
122
+ _applyCustomLogRecordData(logRecord) {
123
+ const hook = this.getConfig().applyCustomLogRecordData;
124
+ if (!hook) return;
125
+ safeExecuteInTheMiddle(() => hook(logRecord), (error) => {
126
+ if (error) this._diag.error("applyCustomLogRecordData hook failed", error);
127
+ }, true);
128
+ }
129
+ _determineSameDocument(fromUrl, toUrl) {
130
+ try {
131
+ const fromURL = new URL(fromUrl);
132
+ const toURL = new URL(toUrl);
133
+ return fromURL.origin === toURL.origin;
134
+ } catch {
135
+ return true;
136
+ }
137
+ }
138
+ _mapChangeStateToType(changeState, navigationEvent) {
139
+ if (changeState === "currententrychange") switch (navigationEvent?.navigationType) {
140
+ case "traverse": return "traverse";
141
+ case "replace": return "replace";
142
+ case "reload": return "reload";
143
+ default: return "push";
144
+ }
145
+ switch (changeState) {
146
+ case "pushState": return "push";
147
+ case "replaceState": return "replace";
148
+ case "popstate": return "traverse";
149
+ default: return;
150
+ }
151
+ }
152
+ };
153
+ //#endregion
154
+ export { NavigationInstrumentation };
155
+
156
+ //# sourceMappingURL=instrumentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.js","names":[],"sources":["../../src/navigation/instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { LogRecord } from '@opentelemetry/api-logs';\nimport { SeverityNumber } from '@opentelemetry/api-logs';\nimport {\n InstrumentationBase,\n safeExecuteInTheMiddle,\n} from '@opentelemetry/instrumentation';\nimport { version } from '../../package.json' with { type: 'json' };\nimport {\n ATTR_BROWSER_NAVIGATION_HASH_CHANGE,\n ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT,\n ATTR_BROWSER_NAVIGATION_TYPE,\n ATTR_URL_FULL,\n BROWSER_NAVIGATION_EVENT_NAME,\n} from './semconv.ts';\nimport type {\n NavigationInstrumentationConfig,\n NavigationType,\n} from './types.ts';\nimport { isHashChange } from './utils.ts';\n\ntype ChangeState =\n | 'pushState'\n | 'replaceState'\n | 'popstate'\n | 'currententrychange';\n\ninterface NavigationApiEntry {\n url?: string;\n}\n\ninterface NavigationApiTarget {\n currentEntry?: NavigationApiEntry;\n}\n\ninterface NavigationApiEvent extends Event {\n navigationType?: NavigationType;\n target: NavigationApiTarget & EventTarget;\n}\n\ninterface NavigationApi {\n addEventListener(\n type: 'currententrychange',\n listener: (event: NavigationApiEvent) => void,\n ): void;\n removeEventListener(\n type: 'currententrychange',\n listener: (event: NavigationApiEvent) => void,\n ): void;\n}\n\nexport class NavigationInstrumentation extends InstrumentationBase<NavigationInstrumentationConfig> {\n // Use `declare` to prevent JS class field initializers from running after\n // super(), which would reset values set by the enable() call that\n // InstrumentationBase makes during its constructor.\n private declare _isEnabled: boolean;\n private declare _isHistoryPatched: boolean;\n private declare _hasProcessedInitialLoad: boolean;\n private declare _lastUrl: string;\n private declare _onDOMContentLoaded?: () => void;\n private declare _onPopState?: (event: PopStateEvent) => void;\n private declare _onCurrentEntryChange?: (event: NavigationApiEvent) => void;\n\n constructor(config: NavigationInstrumentationConfig = {}) {\n super('@opentelemetry/browser-instrumentation/navigation', version, config);\n this._lastUrl = location.href;\n }\n\n protected override init() {\n return [];\n }\n\n override enable(): void {\n if (this._isEnabled) {\n return;\n }\n this._isEnabled = true;\n\n const navigationApi = this._getNavigationApi();\n\n // Only patch history API if Navigation API is not being used.\n if (!navigationApi && !this._isHistoryPatched) {\n this._patchHistoryApi();\n this._isHistoryPatched = true;\n }\n\n this._waitForPageLoad();\n\n if (navigationApi) {\n this._onCurrentEntryChange = (event) => {\n this._onSoftNavigation('currententrychange', event);\n };\n navigationApi.addEventListener(\n 'currententrychange',\n this._onCurrentEntryChange,\n );\n } else {\n this._onPopState = () => {\n this._onSoftNavigation('popstate');\n };\n window.addEventListener('popstate', this._onPopState);\n }\n }\n\n override disable(): void {\n if (!this._isEnabled) {\n return;\n }\n this._isEnabled = false;\n\n if (this._onDOMContentLoaded) {\n document.removeEventListener(\n 'DOMContentLoaded',\n this._onDOMContentLoaded,\n );\n this._onDOMContentLoaded = undefined;\n }\n if (this._onPopState) {\n window.removeEventListener('popstate', this._onPopState);\n this._onPopState = undefined;\n }\n if (this._onCurrentEntryChange) {\n const navigationApi = this._getNavigationApi();\n navigationApi?.removeEventListener(\n 'currententrychange',\n this._onCurrentEntryChange,\n );\n this._onCurrentEntryChange = undefined;\n }\n // Reset the initial-load flag so it can be processed again if re-enabled.\n this._hasProcessedInitialLoad = false;\n }\n\n private _getNavigationApi(): NavigationApi | undefined {\n const cfg = this.getConfig();\n if (!cfg.useNavigationApiIfAvailable) {\n return undefined;\n }\n return (window as unknown as { navigation?: NavigationApi }).navigation;\n }\n\n private _onHardNavigation(): void {\n const cfg = this.getConfig();\n const logRecord: LogRecord = {\n eventName: BROWSER_NAVIGATION_EVENT_NAME,\n severityNumber: SeverityNumber.INFO,\n attributes: {\n [ATTR_URL_FULL]: cfg.sanitizeUrl\n ? cfg.sanitizeUrl(document.documentURI)\n : document.documentURI,\n [ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT]: false,\n [ATTR_BROWSER_NAVIGATION_HASH_CHANGE]: false,\n },\n };\n this._applyCustomLogRecordData(logRecord);\n this.logger.emit(logRecord);\n }\n\n private _onSoftNavigation(\n changeState: ChangeState,\n navigationEvent?: NavigationApiEvent,\n ): void {\n const referrerUrl = this._lastUrl;\n const currentUrl =\n changeState === 'currententrychange' &&\n navigationEvent?.target?.currentEntry?.url\n ? navigationEvent.target.currentEntry.url\n : location.href;\n\n if (referrerUrl === currentUrl) {\n return;\n }\n\n const navType = this._mapChangeStateToType(changeState, navigationEvent);\n const sameDocument = this._determineSameDocument(referrerUrl, currentUrl);\n const hashChange = isHashChange(referrerUrl, currentUrl);\n const cfg = this.getConfig();\n\n const logRecord: LogRecord = {\n eventName: BROWSER_NAVIGATION_EVENT_NAME,\n severityNumber: SeverityNumber.INFO,\n attributes: {\n [ATTR_URL_FULL]: cfg.sanitizeUrl\n ? cfg.sanitizeUrl(currentUrl)\n : currentUrl,\n [ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT]: sameDocument,\n [ATTR_BROWSER_NAVIGATION_HASH_CHANGE]: hashChange,\n ...(navType ? { [ATTR_BROWSER_NAVIGATION_TYPE]: navType } : {}),\n },\n };\n this._applyCustomLogRecordData(logRecord);\n this.logger.emit(logRecord);\n\n this._lastUrl = currentUrl;\n }\n\n private _waitForPageLoad(): void {\n if (document.readyState === 'complete' && !this._hasProcessedInitialLoad) {\n this._hasProcessedInitialLoad = true;\n this._onHardNavigation();\n return;\n }\n\n this._onDOMContentLoaded = () => {\n if (!this._hasProcessedInitialLoad) {\n this._hasProcessedInitialLoad = true;\n this._onHardNavigation();\n }\n };\n document.addEventListener('DOMContentLoaded', this._onDOMContentLoaded);\n }\n\n private _patchHistoryApi(): void {\n this._wrap(\n history,\n 'replaceState',\n this._patchHistoryMethod('replaceState'),\n );\n this._wrap(history, 'pushState', this._patchHistoryMethod('pushState'));\n }\n\n private _patchHistoryMethod(changeState: 'pushState' | 'replaceState') {\n const plugin = this;\n return (original: History['pushState' | 'replaceState']) => {\n return function patchedHistoryMethod(\n this: History,\n ...args: Parameters<History['pushState' | 'replaceState']>\n ) {\n if (!plugin._isEnabled) {\n return original.apply(this, args);\n }\n const result = original.apply(this, args);\n if (location.href !== plugin._lastUrl) {\n plugin._onSoftNavigation(changeState);\n }\n return result;\n };\n };\n }\n\n private _applyCustomLogRecordData(logRecord: LogRecord): void {\n const cfg = this.getConfig();\n const hook = cfg.applyCustomLogRecordData;\n if (!hook) {\n return;\n }\n safeExecuteInTheMiddle(\n () => hook(logRecord),\n (error) => {\n if (error) {\n this._diag.error('applyCustomLogRecordData hook failed', error);\n }\n },\n true,\n );\n }\n\n private _determineSameDocument(fromUrl: string, toUrl: string): boolean {\n try {\n const fromURL = new URL(fromUrl);\n const toURL = new URL(toUrl);\n return fromURL.origin === toURL.origin;\n } catch {\n // Fallback: assume same document for relative URLs or parsing errors.\n // In SPAs, route changes via pushState/replaceState are same-document.\n return true;\n }\n }\n\n private _mapChangeStateToType(\n changeState: ChangeState,\n navigationEvent?: NavigationApiEvent,\n ): NavigationType | undefined {\n if (changeState === 'currententrychange') {\n const navType = navigationEvent?.navigationType;\n switch (navType) {\n case 'traverse':\n return 'traverse';\n case 'replace':\n return 'replace';\n case 'reload':\n return 'reload';\n default:\n // Default to 'push' for programmatic navigations (history.pushState,\n // link clicks) when no explicit type info is available.\n return 'push';\n }\n }\n\n switch (changeState) {\n case 'pushState':\n return 'push';\n case 'replaceState':\n return 'replace';\n case 'popstate':\n return 'traverse';\n default:\n return undefined;\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ //#region src/navigation/semconv.ts
2
+ const BROWSER_NAVIGATION_EVENT_NAME = "browser.navigation";
3
+ /**
4
+ * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
5
+ */
6
+ const ATTR_URL_FULL = "url.full";
7
+ /**
8
+ * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
9
+ */
10
+ const ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT = "browser.navigation.same_document";
11
+ /**
12
+ * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
13
+ */
14
+ const ATTR_BROWSER_NAVIGATION_HASH_CHANGE = "browser.navigation.hash_change";
15
+ /**
16
+ * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
17
+ */
18
+ const ATTR_BROWSER_NAVIGATION_TYPE = "browser.navigation.type";
19
+ //#endregion
20
+ export { ATTR_BROWSER_NAVIGATION_HASH_CHANGE, ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT, ATTR_BROWSER_NAVIGATION_TYPE, ATTR_URL_FULL, BROWSER_NAVIGATION_EVENT_NAME };
21
+
22
+ //# sourceMappingURL=semconv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semconv.js","names":[],"sources":["../../src/navigation/semconv.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/*\n * This file contains a copy of unstable semantic convention definitions\n * used by this package.\n * @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv\n */\n\nexport const BROWSER_NAVIGATION_EVENT_NAME = 'browser.navigation';\n\n/**\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_URL_FULL = 'url.full';\n\n/**\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_BROWSER_NAVIGATION_SAME_DOCUMENT =\n 'browser.navigation.same_document';\n\n/**\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_BROWSER_NAVIGATION_HASH_CHANGE =\n 'browser.navigation.hash_change';\n\n/**\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_BROWSER_NAVIGATION_TYPE = 'browser.navigation.type';\n"],"mappings":";AAWA,MAAa,gCAAgC;;;;AAK7C,MAAa,gBAAgB;;;;AAK7B,MAAa,wCACX;;;;AAKF,MAAa,sCACX;;;;AAKF,MAAa,+BAA+B"}
@@ -0,0 +1,21 @@
1
+ import { LogRecord } from "@opentelemetry/api-logs";
2
+ import { InstrumentationConfig } from "@opentelemetry/instrumentation";
3
+
4
+ //#region src/navigation/types.d.ts
5
+ type ApplyCustomLogRecordDataFunction = (logRecord: LogRecord) => void;
6
+ type SanitizeUrlFunction = (url: string) => string;
7
+ type NavigationType = 'push' | 'replace' | 'reload' | 'traverse';
8
+ /**
9
+ * NavigationInstrumentation Configuration
10
+ */
11
+ interface NavigationInstrumentationConfig extends InstrumentationConfig {
12
+ /** Hook to modify log records before they are emitted. */
13
+ applyCustomLogRecordData?: ApplyCustomLogRecordDataFunction;
14
+ /** Use the Navigation API `currententrychange` event if available (experimental). Defaults to false. */
15
+ useNavigationApiIfAvailable?: boolean;
16
+ /** Custom function to sanitize URLs before adding to log records. */
17
+ sanitizeUrl?: SanitizeUrlFunction;
18
+ }
19
+ //#endregion
20
+ export { NavigationInstrumentationConfig, NavigationType };
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,12 @@
1
+ //#region src/navigation/utils.d.ts
2
+ /**
3
+ * Default URL sanitization function that redacts credentials and sensitive query parameters.
4
+ * This is the default implementation used when no custom sanitizeUrl callback is provided.
5
+ *
6
+ * @param url - The URL to sanitize
7
+ * @returns The sanitized URL with credentials and sensitive parameters redacted
8
+ */
9
+ declare function defaultSanitizeUrl(url: string): string;
10
+ //#endregion
11
+ export { defaultSanitizeUrl };
12
+ //# sourceMappingURL=utils.d.ts.map