@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.
- package/README.md +115 -0
- package/dist/console/index.d.ts +3 -0
- package/dist/console/index.js +2 -0
- package/dist/console/instrumentation.d.ts +21 -0
- package/dist/console/instrumentation.js +84 -0
- package/dist/console/instrumentation.js.map +1 -0
- package/dist/console/semconv.js +14 -0
- package/dist/console/semconv.js.map +1 -0
- package/dist/console/types.d.ts +25 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/index.js +3 -0
- package/dist/navigation/instrumentation.d.ts +29 -0
- package/dist/navigation/instrumentation.js +156 -0
- package/dist/navigation/instrumentation.js.map +1 -0
- package/dist/navigation/semconv.js +22 -0
- package/dist/navigation/semconv.js.map +1 -0
- package/dist/navigation/types.d.ts +21 -0
- package/dist/navigation/utils.d.ts +12 -0
- package/dist/navigation/utils.js +77 -0
- package/dist/navigation/utils.js.map +1 -0
- package/dist/navigation-timing/semconv.js +24 -24
- package/dist/navigation-timing/semconv.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/resource-timing/idle-callback-shim.js +35 -0
- package/dist/resource-timing/idle-callback-shim.js.map +1 -0
- package/dist/resource-timing/index.d.ts +3 -0
- package/dist/resource-timing/index.js +2 -0
- package/dist/resource-timing/instrumentation.d.ts +33 -0
- package/dist/resource-timing/instrumentation.js +160 -0
- package/dist/resource-timing/instrumentation.js.map +1 -0
- package/dist/resource-timing/semconv.js +131 -0
- package/dist/resource-timing/semconv.js.map +1 -0
- package/dist/resource-timing/types.d.ts +38 -0
- package/dist/utils/getElementCSSSelector.js.map +1 -1
- 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,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,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
|