@opentelemetry/browser-instrumentation 0.2.0 → 0.3.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 +56 -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 +9 -7
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ npm install @opentelemetry/browser-instrumentation
|
|
|
14
14
|
## Instrumentations
|
|
15
15
|
|
|
16
16
|
- [Navigation Timing](#navigation-timing) — automatic instrumentation for navigation timing
|
|
17
|
+
- [Resource Timing](#resource-timing) — automatic instrumentation for resource timing
|
|
17
18
|
- [User Action](#user-action) — automatic instrumentation for user actions (clicks)
|
|
18
19
|
- [Web Vitals](#web-vitals) — automatic instrumentation for Core Web Vitals
|
|
19
20
|
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
} from '@opentelemetry/sdk-logs';
|
|
29
30
|
import { registerInstrumentations } from '@opentelemetry/instrumentation';
|
|
30
31
|
import { NavigationTimingInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/navigation-timing';
|
|
32
|
+
import { ResourceTimingInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/resource-timing';
|
|
31
33
|
import { UserActionInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/user-action';
|
|
32
34
|
import { WebVitalsInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/web-vitals';
|
|
33
35
|
|
|
@@ -41,6 +43,7 @@ logs.setGlobalLoggerProvider(logProvider);
|
|
|
41
43
|
registerInstrumentations({
|
|
42
44
|
instrumentations: [
|
|
43
45
|
new NavigationTimingInstrumentation(),
|
|
46
|
+
new ResourceTimingInstrumentation(),
|
|
44
47
|
new UserActionInstrumentation(),
|
|
45
48
|
new WebVitalsInstrumentation(),
|
|
46
49
|
],
|
|
@@ -59,6 +62,59 @@ Provides automatic instrumentation for [Navigation Timing](https://developer.moz
|
|
|
59
62
|
|
|
60
63
|
---
|
|
61
64
|
|
|
65
|
+
### Resource Timing
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { ResourceTimingInstrumentation } from '@opentelemetry/browser-instrumentation/experimental/resource-timing';
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
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.).
|
|
72
|
+
|
|
73
|
+
- Uses `requestIdleCallback` to avoid blocking the main thread (with automatic `setTimeout` fallback for Safari)
|
|
74
|
+
- Processes resources in configurable batches
|
|
75
|
+
- Captures historical resources loaded before instrumentation was enabled via buffered mode
|
|
76
|
+
- Flushes pending entries on visibility change to prevent data loss
|
|
77
|
+
|
|
78
|
+
#### Configuration
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
new ResourceTimingInstrumentation({
|
|
82
|
+
// Process 100 resources per batch (default: 50)
|
|
83
|
+
batchSize: 100,
|
|
84
|
+
|
|
85
|
+
// Wait max 2 seconds for idle time before forcing processing (default: 1000)
|
|
86
|
+
forceProcessingAfter: 2000,
|
|
87
|
+
|
|
88
|
+
// Spend max 100ms processing per idle callback (default: 50)
|
|
89
|
+
maxProcessingTime: 100,
|
|
90
|
+
|
|
91
|
+
// Maximum queue size before forcing immediate flush (default: 1000)
|
|
92
|
+
maxQueueSize: 2000,
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
| Option | Type | Default | Description |
|
|
97
|
+
|--------|------|---------|-------------|
|
|
98
|
+
| `batchSize` | `number` | `50` | Number of resources to process per batch. |
|
|
99
|
+
| `forceProcessingAfter` | `number` | `1000` | Maximum time (ms) to wait for an idle callback before forcing processing. |
|
|
100
|
+
| `maxProcessingTime` | `number` | `50` | Maximum time (ms) to spend processing resources per idle callback. |
|
|
101
|
+
| `maxQueueSize` | `number` | `1000` | Maximum number of resources to queue before forcing immediate flush. |
|
|
102
|
+
|
|
103
|
+
#### Captured Data
|
|
104
|
+
|
|
105
|
+
Each resource timing event includes:
|
|
106
|
+
|
|
107
|
+
- **URL** and **Initiator Type** (script, css, img, xmlhttprequest, fetch, etc.)
|
|
108
|
+
- **Duration** — total resource load time
|
|
109
|
+
- **Timing Phases** — DNS lookup, TCP connection, TLS handshake, request, response
|
|
110
|
+
- **Size Metrics** — transfer size, encoded size, decoded size
|
|
111
|
+
- **Protocol** — HTTP version (h1, h2, h3)
|
|
112
|
+
- **Redirect Info** — redirect timing if applicable
|
|
113
|
+
- **Service Worker** — worker start time if intercepted
|
|
114
|
+
- **Render Blocking** — whether the resource blocked rendering (Chromium only)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
62
118
|
### User Action
|
|
63
119
|
|
|
64
120
|
```typescript
|
|
@@ -3,99 +3,99 @@ const NAVIGATION_TIMING_EVENT_NAME = "browser.navigation_timing";
|
|
|
3
3
|
/**
|
|
4
4
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
5
5
|
*/
|
|
6
|
-
const ATTR_NAVIGATION_TYPE = "
|
|
6
|
+
const ATTR_NAVIGATION_TYPE = "browser.navigation_timing.type";
|
|
7
7
|
/**
|
|
8
8
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
9
9
|
*/
|
|
10
|
-
const ATTR_NAVIGATION_URL = "
|
|
10
|
+
const ATTR_NAVIGATION_URL = "url.full";
|
|
11
11
|
/**
|
|
12
12
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
13
13
|
*/
|
|
14
|
-
const
|
|
14
|
+
const ATTR_NAVIGATION_DOM_COMPLETE = "browser.navigation_timing.dom_complete";
|
|
15
15
|
/**
|
|
16
16
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
17
17
|
*/
|
|
18
|
-
const
|
|
18
|
+
const ATTR_NAVIGATION_DOM_CONTENT_LOADED_EVENT_END = "browser.navigation_timing.dom_content_loaded_event_end";
|
|
19
19
|
/**
|
|
20
20
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
21
21
|
*/
|
|
22
|
-
const
|
|
22
|
+
const ATTR_NAVIGATION_DOM_CONTENT_LOADED_EVENT_START = "browser.navigation_timing.dom_content_loaded_event_start";
|
|
23
23
|
/**
|
|
24
24
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
25
25
|
*/
|
|
26
|
-
const
|
|
26
|
+
const ATTR_NAVIGATION_DOM_INTERACTIVE = "browser.navigation_timing.dom_interactive";
|
|
27
27
|
/**
|
|
28
28
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
29
29
|
*/
|
|
30
|
-
const
|
|
30
|
+
const ATTR_NAVIGATION_LOAD_EVENT_END = "browser.navigation_timing.load_event_end";
|
|
31
31
|
/**
|
|
32
32
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
33
33
|
*/
|
|
34
|
-
const
|
|
34
|
+
const ATTR_NAVIGATION_LOAD_EVENT_START = "browser.navigation_timing.load_event_start";
|
|
35
35
|
/**
|
|
36
36
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
37
37
|
*/
|
|
38
|
-
const
|
|
38
|
+
const ATTR_NAVIGATION_REDIRECT_COUNT = "browser.navigation_timing.redirect_count";
|
|
39
39
|
/**
|
|
40
40
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
41
41
|
*/
|
|
42
|
-
const
|
|
42
|
+
const ATTR_NAVIGATION_UNLOAD_EVENT_END = "browser.navigation_timing.unload_event_end";
|
|
43
43
|
/**
|
|
44
44
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
45
45
|
*/
|
|
46
|
-
const
|
|
46
|
+
const ATTR_NAVIGATION_UNLOAD_EVENT_START = "browser.navigation_timing.unload_event_start";
|
|
47
47
|
/**
|
|
48
48
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
49
49
|
*/
|
|
50
|
-
const
|
|
50
|
+
const ATTR_NAVIGATION_DURATION = "browser.resource_timing.duration";
|
|
51
51
|
/**
|
|
52
52
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
53
53
|
*/
|
|
54
|
-
const ATTR_NAVIGATION_FETCH_START = "
|
|
54
|
+
const ATTR_NAVIGATION_FETCH_START = "browser.resource_timing.fetch_start";
|
|
55
55
|
/**
|
|
56
56
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
57
57
|
*/
|
|
58
|
-
const ATTR_NAVIGATION_DOMAIN_LOOKUP_START = "
|
|
58
|
+
const ATTR_NAVIGATION_DOMAIN_LOOKUP_START = "browser.resource_timing.domain_lookup_start";
|
|
59
59
|
/**
|
|
60
60
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
61
61
|
*/
|
|
62
|
-
const ATTR_NAVIGATION_DOMAIN_LOOKUP_END = "
|
|
62
|
+
const ATTR_NAVIGATION_DOMAIN_LOOKUP_END = "browser.resource_timing.domain_lookup_end";
|
|
63
63
|
/**
|
|
64
64
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
65
65
|
*/
|
|
66
|
-
const ATTR_NAVIGATION_CONNECT_START = "
|
|
66
|
+
const ATTR_NAVIGATION_CONNECT_START = "browser.resource_timing.connect_start";
|
|
67
67
|
/**
|
|
68
68
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
69
69
|
*/
|
|
70
|
-
const ATTR_NAVIGATION_CONNECT_END = "
|
|
70
|
+
const ATTR_NAVIGATION_CONNECT_END = "browser.resource_timing.connect_end";
|
|
71
71
|
/**
|
|
72
72
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
73
73
|
*/
|
|
74
|
-
const ATTR_NAVIGATION_SECURE_CONNECTION_START = "
|
|
74
|
+
const ATTR_NAVIGATION_SECURE_CONNECTION_START = "browser.resource_timing.secure_connection_start";
|
|
75
75
|
/**
|
|
76
76
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
77
77
|
*/
|
|
78
|
-
const ATTR_NAVIGATION_REQUEST_START = "
|
|
78
|
+
const ATTR_NAVIGATION_REQUEST_START = "browser.resource_timing.request_start";
|
|
79
79
|
/**
|
|
80
80
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
81
81
|
*/
|
|
82
|
-
const ATTR_NAVIGATION_RESPONSE_START = "
|
|
82
|
+
const ATTR_NAVIGATION_RESPONSE_START = "browser.resource_timing.response_start";
|
|
83
83
|
/**
|
|
84
84
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
85
85
|
*/
|
|
86
|
-
const ATTR_NAVIGATION_RESPONSE_END = "
|
|
86
|
+
const ATTR_NAVIGATION_RESPONSE_END = "browser.resource_timing.response_end";
|
|
87
87
|
/**
|
|
88
88
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
89
89
|
*/
|
|
90
|
-
const ATTR_NAVIGATION_TRANSFER_SIZE = "
|
|
90
|
+
const ATTR_NAVIGATION_TRANSFER_SIZE = "browser.resource_timing.transfer_size";
|
|
91
91
|
/**
|
|
92
92
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
93
93
|
*/
|
|
94
|
-
const ATTR_NAVIGATION_ENCODED_BODY_SIZE = "
|
|
94
|
+
const ATTR_NAVIGATION_ENCODED_BODY_SIZE = "browser.resource_timing.encoded_body_size";
|
|
95
95
|
/**
|
|
96
96
|
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
97
97
|
*/
|
|
98
|
-
const ATTR_NAVIGATION_DECODED_BODY_SIZE = "
|
|
98
|
+
const ATTR_NAVIGATION_DECODED_BODY_SIZE = "browser.resource_timing.decoded_body_size";
|
|
99
99
|
//#endregion
|
|
100
100
|
export { ATTR_NAVIGATION_CONNECT_END, ATTR_NAVIGATION_CONNECT_START, ATTR_NAVIGATION_DECODED_BODY_SIZE, ATTR_NAVIGATION_DOMAIN_LOOKUP_END, ATTR_NAVIGATION_DOMAIN_LOOKUP_START, ATTR_NAVIGATION_DOM_COMPLETE, ATTR_NAVIGATION_DOM_CONTENT_LOADED_EVENT_END, ATTR_NAVIGATION_DOM_CONTENT_LOADED_EVENT_START, ATTR_NAVIGATION_DOM_INTERACTIVE, ATTR_NAVIGATION_DURATION, ATTR_NAVIGATION_ENCODED_BODY_SIZE, ATTR_NAVIGATION_FETCH_START, ATTR_NAVIGATION_LOAD_EVENT_END, ATTR_NAVIGATION_LOAD_EVENT_START, ATTR_NAVIGATION_REDIRECT_COUNT, ATTR_NAVIGATION_REQUEST_START, ATTR_NAVIGATION_RESPONSE_END, ATTR_NAVIGATION_RESPONSE_START, ATTR_NAVIGATION_SECURE_CONNECTION_START, ATTR_NAVIGATION_TRANSFER_SIZE, ATTR_NAVIGATION_TYPE, ATTR_NAVIGATION_UNLOAD_EVENT_END, ATTR_NAVIGATION_UNLOAD_EVENT_START, ATTR_NAVIGATION_URL, NAVIGATION_TIMING_EVENT_NAME };
|
|
101
101
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semconv.js","names":[],"sources":["../../src/navigation-timing/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 NAVIGATION_TIMING_EVENT_NAME = 'browser.navigation_timing';\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_NAVIGATION_TYPE = '
|
|
1
|
+
{"version":3,"file":"semconv.js","names":[],"sources":["../../src/navigation-timing/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 NAVIGATION_TIMING_EVENT_NAME = 'browser.navigation_timing';\n\n// Navigation-specific attributes (from PerformanceNavigationTiming).\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_NAVIGATION_TYPE = 'browser.navigation_timing.type';\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_NAVIGATION_URL = '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_NAVIGATION_DOM_COMPLETE =\n 'browser.navigation_timing.dom_complete';\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_NAVIGATION_DOM_CONTENT_LOADED_EVENT_END =\n 'browser.navigation_timing.dom_content_loaded_event_end';\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_NAVIGATION_DOM_CONTENT_LOADED_EVENT_START =\n 'browser.navigation_timing.dom_content_loaded_event_start';\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_NAVIGATION_DOM_INTERACTIVE =\n 'browser.navigation_timing.dom_interactive';\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_NAVIGATION_LOAD_EVENT_END =\n 'browser.navigation_timing.load_event_end';\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_NAVIGATION_LOAD_EVENT_START =\n 'browser.navigation_timing.load_event_start';\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_NAVIGATION_REDIRECT_COUNT =\n 'browser.navigation_timing.redirect_count';\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_NAVIGATION_UNLOAD_EVENT_END =\n 'browser.navigation_timing.unload_event_end';\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_NAVIGATION_UNLOAD_EVENT_START =\n 'browser.navigation_timing.unload_event_start';\n\n// Shared timing attributes inherited from PerformanceResourceTiming.\n// PerformanceNavigationTiming extends PerformanceResourceTiming, so these\n// values mirror resource timing. TODO: extract to a shared module to avoid\n// duplication.\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_NAVIGATION_DURATION = 'browser.resource_timing.duration';\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_NAVIGATION_FETCH_START =\n 'browser.resource_timing.fetch_start';\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_NAVIGATION_DOMAIN_LOOKUP_START =\n 'browser.resource_timing.domain_lookup_start';\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_NAVIGATION_DOMAIN_LOOKUP_END =\n 'browser.resource_timing.domain_lookup_end';\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_NAVIGATION_CONNECT_START =\n 'browser.resource_timing.connect_start';\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_NAVIGATION_CONNECT_END =\n 'browser.resource_timing.connect_end';\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_NAVIGATION_SECURE_CONNECTION_START =\n 'browser.resource_timing.secure_connection_start';\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_NAVIGATION_REQUEST_START =\n 'browser.resource_timing.request_start';\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_NAVIGATION_RESPONSE_START =\n 'browser.resource_timing.response_start';\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_NAVIGATION_RESPONSE_END =\n 'browser.resource_timing.response_end';\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_NAVIGATION_TRANSFER_SIZE =\n 'browser.resource_timing.transfer_size';\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_NAVIGATION_ENCODED_BODY_SIZE =\n 'browser.resource_timing.encoded_body_size';\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_NAVIGATION_DECODED_BODY_SIZE =\n 'browser.resource_timing.decoded_body_size';\n"],"mappings":";AAWA,MAAa,+BAA+B;;;;AAO5C,MAAa,uBAAuB;;;;AAKpC,MAAa,sBAAsB;;;;AAKnC,MAAa,+BACX;;;;AAKF,MAAa,+CACX;;;;AAKF,MAAa,iDACX;;;;AAKF,MAAa,kCACX;;;;AAKF,MAAa,iCACX;;;;AAKF,MAAa,mCACX;;;;AAKF,MAAa,iCACX;;;;AAKF,MAAa,mCACX;;;;AAKF,MAAa,qCACX;;;;AAUF,MAAa,2BAA2B;;;;AAKxC,MAAa,8BACX;;;;AAKF,MAAa,sCACX;;;;AAKF,MAAa,oCACX;;;;AAKF,MAAa,gCACX;;;;AAKF,MAAa,8BACX;;;;AAKF,MAAa,0CACX;;;;AAKF,MAAa,gCACX;;;;AAKF,MAAa,iCACX;;;;AAKF,MAAa,+BACX;;;;AAKF,MAAa,gCACX;;;;AAKF,MAAa,oCACX;;;;AAKF,MAAa,oCACX"}
|
package/dist/package.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/resource-timing/idle-callback-shim.ts
|
|
2
|
+
const IDLE_DEADLINE_MS = 50;
|
|
3
|
+
const supportsIdleCallback = typeof window.requestIdleCallback === "function";
|
|
4
|
+
/**
|
|
5
|
+
* Schedules a callback during idle time, using the native requestIdleCallback
|
|
6
|
+
* when available. Falls back to setTimeout with a synthetic IdleDeadline that
|
|
7
|
+
* reports ~50ms of available time (per the W3C spec recommendation).
|
|
8
|
+
*/
|
|
9
|
+
function requestIdleCallbackShim(callback, options) {
|
|
10
|
+
if (supportsIdleCallback) return {
|
|
11
|
+
id: window.requestIdleCallback(callback, options),
|
|
12
|
+
native: true
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
id: window.setTimeout(() => {
|
|
16
|
+
const start = performance.now();
|
|
17
|
+
callback({
|
|
18
|
+
didTimeout: false,
|
|
19
|
+
timeRemaining: () => Math.max(0, IDLE_DEADLINE_MS - (performance.now() - start))
|
|
20
|
+
});
|
|
21
|
+
}, 1),
|
|
22
|
+
native: false
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Cancels a previously scheduled idle callback.
|
|
27
|
+
*/
|
|
28
|
+
function cancelIdleCallbackShim(handle) {
|
|
29
|
+
if (handle.native) window.cancelIdleCallback(handle.id);
|
|
30
|
+
else clearTimeout(handle.id);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { cancelIdleCallbackShim, requestIdleCallbackShim };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=idle-callback-shim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-callback-shim.js","names":[],"sources":["../../src/resource-timing/idle-callback-shim.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nconst IDLE_DEADLINE_MS = 50;\n\n// requestIdleCallback is not yet Baseline (not supported in Safari).\n// Feature-detect here so we can shim it below for unsupported browsers.\n// eslint-disable-next-line baseline-js/use-baseline\nconst supportsIdleCallback = typeof window.requestIdleCallback === 'function';\n\nexport interface IdleCallbackHandle {\n id: number;\n native: boolean;\n}\n\n/**\n * Schedules a callback during idle time, using the native requestIdleCallback\n * when available. Falls back to setTimeout with a synthetic IdleDeadline that\n * reports ~50ms of available time (per the W3C spec recommendation).\n */\nexport function requestIdleCallbackShim(\n callback: IdleRequestCallback,\n options?: IdleRequestOptions,\n): IdleCallbackHandle {\n if (supportsIdleCallback) {\n // requestIdleCallback is not yet Baseline (not supported in Safari).\n // eslint-disable-next-line baseline-js/use-baseline\n const id = window.requestIdleCallback(callback, options);\n return { id, native: true };\n }\n\n const id = window.setTimeout(() => {\n const start = performance.now();\n callback({\n didTimeout: false,\n timeRemaining: () =>\n Math.max(0, IDLE_DEADLINE_MS - (performance.now() - start)),\n });\n }, 1);\n return { id, native: false };\n}\n\n/**\n * Cancels a previously scheduled idle callback.\n */\nexport function cancelIdleCallbackShim(handle: IdleCallbackHandle): void {\n if (handle.native) {\n // eslint-disable-next-line baseline-js/use-baseline\n window.cancelIdleCallback(handle.id);\n } else {\n clearTimeout(handle.id);\n }\n}\n"],"mappings":";AAKA,MAAM,mBAAmB;AAKzB,MAAM,uBAAuB,OAAO,OAAO,wBAAwB;;;;;;AAYnE,SAAgB,wBACd,UACA,SACoB;AACpB,KAAI,qBAIF,QAAO;EAAE,IADE,OAAO,oBAAoB,UAAU,QACrC;EAAE,QAAQ;EAAM;AAW7B,QAAO;EAAE,IARE,OAAO,iBAAiB;GACjC,MAAM,QAAQ,YAAY,KAAK;AAC/B,YAAS;IACP,YAAY;IACZ,qBACE,KAAK,IAAI,GAAG,oBAAoB,YAAY,KAAK,GAAG,OAAO;IAC9D,CAAC;KACD,EACQ;EAAE,QAAQ;EAAO;;;;;AAM9B,SAAgB,uBAAuB,QAAkC;AACvE,KAAI,OAAO,OAET,QAAO,mBAAmB,OAAO,GAAG;KAEpC,cAAa,OAAO,GAAG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ResourceTimingInstrumentationConfig } from "./types.js";
|
|
2
|
+
import { InstrumentationBase } from "@opentelemetry/instrumentation";
|
|
3
|
+
|
|
4
|
+
//#region src/resource-timing/instrumentation.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* OpenTelemetry instrumentation for resource timing for browser applications.
|
|
7
|
+
*
|
|
8
|
+
* This instrumentation captures resource timing data using PerformanceObserver
|
|
9
|
+
* and batches emissions to avoid overwhelming the main thread. It uses
|
|
10
|
+
* requestIdleCallback when available (with fallback for Safari) to ensure
|
|
11
|
+
* processing happens during idle periods.
|
|
12
|
+
*/
|
|
13
|
+
declare class ResourceTimingInstrumentation extends InstrumentationBase<ResourceTimingInstrumentationConfig> {
|
|
14
|
+
private _observer?;
|
|
15
|
+
private _pendingEntries;
|
|
16
|
+
private _idleHandle?;
|
|
17
|
+
private _isEnabled;
|
|
18
|
+
private _loadHandler;
|
|
19
|
+
private _visibilityChangeHandler;
|
|
20
|
+
constructor(config?: ResourceTimingInstrumentationConfig);
|
|
21
|
+
protected init(): never[];
|
|
22
|
+
enable(): void;
|
|
23
|
+
disable(): void;
|
|
24
|
+
private _setupObserver;
|
|
25
|
+
private _scheduleProcessing;
|
|
26
|
+
private _processChunk;
|
|
27
|
+
private _emitResource;
|
|
28
|
+
private _flush;
|
|
29
|
+
private _cancelScheduledProcessing;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { ResourceTimingInstrumentation };
|
|
33
|
+
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { version } from "../package.js";
|
|
2
|
+
import { cancelIdleCallbackShim, requestIdleCallbackShim } from "./idle-callback-shim.js";
|
|
3
|
+
import { ATTR_RESOURCE_CONNECT_END, ATTR_RESOURCE_CONNECT_START, ATTR_RESOURCE_DECODED_BODY_SIZE, ATTR_RESOURCE_DOMAIN_LOOKUP_END, ATTR_RESOURCE_DOMAIN_LOOKUP_START, ATTR_RESOURCE_DURATION, ATTR_RESOURCE_ENCODED_BODY_SIZE, ATTR_RESOURCE_FETCH_START, ATTR_RESOURCE_INITIATOR_TYPE, ATTR_RESOURCE_NEXT_HOP_PROTOCOL, ATTR_RESOURCE_REDIRECT_END, ATTR_RESOURCE_REDIRECT_START, ATTR_RESOURCE_RENDER_BLOCKING_STATUS, ATTR_RESOURCE_REQUEST_START, ATTR_RESOURCE_RESPONSE_END, ATTR_RESOURCE_RESPONSE_START, ATTR_RESOURCE_SECURE_CONNECTION_START, ATTR_RESOURCE_TRANSFER_SIZE, ATTR_RESOURCE_URL, ATTR_RESOURCE_WORKER_START, RESOURCE_TIMING_EVENT_NAME } from "./semconv.js";
|
|
4
|
+
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
5
|
+
import { InstrumentationBase } from "@opentelemetry/instrumentation";
|
|
6
|
+
//#region src/resource-timing/instrumentation.ts
|
|
7
|
+
const DEFAULT_BATCH_SIZE = 50;
|
|
8
|
+
const DEFAULT_FORCE_PROCESSING_AFTER = 1e3;
|
|
9
|
+
const DEFAULT_MAX_PROCESSING_TIME = 50;
|
|
10
|
+
const DEFAULT_MAX_QUEUE_SIZE = 1e3;
|
|
11
|
+
const MIN_BATCH_SIZE = 1;
|
|
12
|
+
const MIN_FORCE_PROCESSING_AFTER = 0;
|
|
13
|
+
const MIN_PROCESSING_TIME = 0;
|
|
14
|
+
const MIN_QUEUE_SIZE = 1;
|
|
15
|
+
/**
|
|
16
|
+
* OpenTelemetry instrumentation for resource timing for browser applications.
|
|
17
|
+
*
|
|
18
|
+
* This instrumentation captures resource timing data using PerformanceObserver
|
|
19
|
+
* and batches emissions to avoid overwhelming the main thread. It uses
|
|
20
|
+
* requestIdleCallback when available (with fallback for Safari) to ensure
|
|
21
|
+
* processing happens during idle periods.
|
|
22
|
+
*/
|
|
23
|
+
var ResourceTimingInstrumentation = class extends InstrumentationBase {
|
|
24
|
+
_observer;
|
|
25
|
+
_pendingEntries = [];
|
|
26
|
+
_idleHandle;
|
|
27
|
+
constructor(config = {}) {
|
|
28
|
+
super("@opentelemetry/browser-instrumentation/resource-timing", version, config);
|
|
29
|
+
}
|
|
30
|
+
init() {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
enable() {
|
|
34
|
+
if (this._isEnabled) return;
|
|
35
|
+
if (!("PerformanceObserver" in window)) {
|
|
36
|
+
this._diag.debug("PerformanceObserver is not supported, resource timings will not be collected");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this._isEnabled = true;
|
|
40
|
+
if (document.readyState === "complete") this._setupObserver();
|
|
41
|
+
else {
|
|
42
|
+
this._loadHandler = () => this._setupObserver();
|
|
43
|
+
window.addEventListener("load", this._loadHandler, { once: true });
|
|
44
|
+
}
|
|
45
|
+
this._visibilityChangeHandler = () => {
|
|
46
|
+
if (document.hidden) this._flush();
|
|
47
|
+
};
|
|
48
|
+
document.addEventListener("visibilitychange", this._visibilityChangeHandler);
|
|
49
|
+
}
|
|
50
|
+
disable() {
|
|
51
|
+
this._isEnabled = false;
|
|
52
|
+
this._flush();
|
|
53
|
+
this._observer?.disconnect();
|
|
54
|
+
this._observer = void 0;
|
|
55
|
+
if (this._loadHandler) {
|
|
56
|
+
window.removeEventListener("load", this._loadHandler);
|
|
57
|
+
this._loadHandler = void 0;
|
|
58
|
+
}
|
|
59
|
+
if (this._visibilityChangeHandler) {
|
|
60
|
+
document.removeEventListener("visibilitychange", this._visibilityChangeHandler);
|
|
61
|
+
this._visibilityChangeHandler = void 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
_setupObserver() {
|
|
65
|
+
if (!this._isEnabled) return;
|
|
66
|
+
try {
|
|
67
|
+
const observer = new PerformanceObserver((list) => {
|
|
68
|
+
if (!this._isEnabled) return;
|
|
69
|
+
const maxQueueSize = Math.max(this._config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE, MIN_QUEUE_SIZE);
|
|
70
|
+
const entries = list.getEntries();
|
|
71
|
+
const initiatorTypes = this._config.initiatorTypes;
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
if (initiatorTypes !== void 0 && !initiatorTypes.includes(entry.initiatorType)) continue;
|
|
74
|
+
if (this._pendingEntries.length >= maxQueueSize) this._flush();
|
|
75
|
+
this._pendingEntries.push(entry);
|
|
76
|
+
}
|
|
77
|
+
if (this._pendingEntries.length > 0) this._scheduleProcessing();
|
|
78
|
+
});
|
|
79
|
+
this._observer = observer;
|
|
80
|
+
observer.observe({
|
|
81
|
+
type: "resource",
|
|
82
|
+
buffered: true
|
|
83
|
+
});
|
|
84
|
+
} catch {
|
|
85
|
+
this._diag.warn("PerformanceObserver not supported, resource timings will not be collected");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
_scheduleProcessing() {
|
|
89
|
+
if (this._idleHandle !== void 0) return;
|
|
90
|
+
const timeout = Math.max(this._config.forceProcessingAfter ?? DEFAULT_FORCE_PROCESSING_AFTER, MIN_FORCE_PROCESSING_AFTER);
|
|
91
|
+
this._idleHandle = requestIdleCallbackShim((deadline) => this._processChunk(deadline), { timeout });
|
|
92
|
+
}
|
|
93
|
+
_processChunk(deadline) {
|
|
94
|
+
this._idleHandle = void 0;
|
|
95
|
+
if (!this._isEnabled || this._pendingEntries.length === 0) return;
|
|
96
|
+
const maxTime = Math.max(this._config.maxProcessingTime ?? DEFAULT_MAX_PROCESSING_TIME, MIN_PROCESSING_TIME);
|
|
97
|
+
const batchSize = Math.max(this._config.batchSize ?? DEFAULT_BATCH_SIZE, MIN_BATCH_SIZE);
|
|
98
|
+
const startTime = performance.now();
|
|
99
|
+
let cursor = 0;
|
|
100
|
+
try {
|
|
101
|
+
for (let i = 0; i < batchSize; i++) {
|
|
102
|
+
const entry = this._pendingEntries[cursor];
|
|
103
|
+
if (entry === void 0) break;
|
|
104
|
+
if (performance.now() - startTime >= maxTime || deadline.timeRemaining() < 1) break;
|
|
105
|
+
cursor++;
|
|
106
|
+
this._emitResource(entry);
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
this._pendingEntries.splice(0, cursor);
|
|
110
|
+
if (this._pendingEntries.length > 0) this._scheduleProcessing();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_emitResource(entry) {
|
|
114
|
+
try {
|
|
115
|
+
this.logger.emit({
|
|
116
|
+
eventName: RESOURCE_TIMING_EVENT_NAME,
|
|
117
|
+
severityNumber: SeverityNumber.INFO,
|
|
118
|
+
attributes: {
|
|
119
|
+
[ATTR_RESOURCE_URL]: entry.name,
|
|
120
|
+
[ATTR_RESOURCE_INITIATOR_TYPE]: entry.initiatorType,
|
|
121
|
+
[ATTR_RESOURCE_DURATION]: entry.duration,
|
|
122
|
+
[ATTR_RESOURCE_FETCH_START]: entry.fetchStart,
|
|
123
|
+
[ATTR_RESOURCE_DOMAIN_LOOKUP_START]: entry.domainLookupStart,
|
|
124
|
+
[ATTR_RESOURCE_DOMAIN_LOOKUP_END]: entry.domainLookupEnd,
|
|
125
|
+
[ATTR_RESOURCE_CONNECT_START]: entry.connectStart,
|
|
126
|
+
[ATTR_RESOURCE_CONNECT_END]: entry.connectEnd,
|
|
127
|
+
[ATTR_RESOURCE_SECURE_CONNECTION_START]: entry.secureConnectionStart,
|
|
128
|
+
[ATTR_RESOURCE_REQUEST_START]: entry.requestStart,
|
|
129
|
+
[ATTR_RESOURCE_RESPONSE_START]: entry.responseStart,
|
|
130
|
+
[ATTR_RESOURCE_RESPONSE_END]: entry.responseEnd,
|
|
131
|
+
[ATTR_RESOURCE_TRANSFER_SIZE]: entry.transferSize,
|
|
132
|
+
[ATTR_RESOURCE_ENCODED_BODY_SIZE]: entry.encodedBodySize,
|
|
133
|
+
[ATTR_RESOURCE_DECODED_BODY_SIZE]: entry.decodedBodySize,
|
|
134
|
+
[ATTR_RESOURCE_REDIRECT_START]: entry.redirectStart,
|
|
135
|
+
[ATTR_RESOURCE_REDIRECT_END]: entry.redirectEnd,
|
|
136
|
+
[ATTR_RESOURCE_WORKER_START]: entry.workerStart,
|
|
137
|
+
[ATTR_RESOURCE_NEXT_HOP_PROTOCOL]: entry.nextHopProtocol,
|
|
138
|
+
[ATTR_RESOURCE_RENDER_BLOCKING_STATUS]: entry.renderBlockingStatus
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
this._diag.error(`Failed to emit resource timing entry for "${entry.name}"`, error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
_flush() {
|
|
146
|
+
this._cancelScheduledProcessing();
|
|
147
|
+
for (const entry of this._pendingEntries) this._emitResource(entry);
|
|
148
|
+
this._pendingEntries = [];
|
|
149
|
+
}
|
|
150
|
+
_cancelScheduledProcessing() {
|
|
151
|
+
if (this._idleHandle !== void 0) {
|
|
152
|
+
cancelIdleCallbackShim(this._idleHandle);
|
|
153
|
+
this._idleHandle = void 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
//#endregion
|
|
158
|
+
export { ResourceTimingInstrumentation };
|
|
159
|
+
|
|
160
|
+
//# sourceMappingURL=instrumentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.js","names":[],"sources":["../../src/resource-timing/instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { SeverityNumber } from '@opentelemetry/api-logs';\nimport { InstrumentationBase } from '@opentelemetry/instrumentation';\nimport { version } from '../../package.json' with { type: 'json' };\nimport type { IdleCallbackHandle } from './idle-callback-shim.ts';\nimport {\n cancelIdleCallbackShim,\n requestIdleCallbackShim,\n} from './idle-callback-shim.ts';\nimport {\n ATTR_RESOURCE_CONNECT_END,\n ATTR_RESOURCE_CONNECT_START,\n ATTR_RESOURCE_DECODED_BODY_SIZE,\n ATTR_RESOURCE_DOMAIN_LOOKUP_END,\n ATTR_RESOURCE_DOMAIN_LOOKUP_START,\n ATTR_RESOURCE_DURATION,\n ATTR_RESOURCE_ENCODED_BODY_SIZE,\n ATTR_RESOURCE_FETCH_START,\n ATTR_RESOURCE_INITIATOR_TYPE,\n ATTR_RESOURCE_NEXT_HOP_PROTOCOL,\n ATTR_RESOURCE_REDIRECT_END,\n ATTR_RESOURCE_REDIRECT_START,\n ATTR_RESOURCE_RENDER_BLOCKING_STATUS,\n ATTR_RESOURCE_REQUEST_START,\n ATTR_RESOURCE_RESPONSE_END,\n ATTR_RESOURCE_RESPONSE_START,\n ATTR_RESOURCE_SECURE_CONNECTION_START,\n ATTR_RESOURCE_TRANSFER_SIZE,\n ATTR_RESOURCE_URL,\n ATTR_RESOURCE_WORKER_START,\n RESOURCE_TIMING_EVENT_NAME,\n} from './semconv.ts';\nimport type { ResourceTimingInstrumentationConfig } from './types.ts';\n\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FORCE_PROCESSING_AFTER = 1000;\nconst DEFAULT_MAX_PROCESSING_TIME = 50;\nconst DEFAULT_MAX_QUEUE_SIZE = 1000;\n\nconst MIN_BATCH_SIZE = 1;\nconst MIN_FORCE_PROCESSING_AFTER = 0;\nconst MIN_PROCESSING_TIME = 0;\nconst MIN_QUEUE_SIZE = 1;\n\n/**\n * OpenTelemetry instrumentation for resource timing for browser applications.\n *\n * This instrumentation captures resource timing data using PerformanceObserver\n * and batches emissions to avoid overwhelming the main thread. It uses\n * requestIdleCallback when available (with fallback for Safari) to ensure\n * processing happens during idle periods.\n */\nexport class ResourceTimingInstrumentation extends InstrumentationBase<ResourceTimingInstrumentationConfig> {\n private _observer?: PerformanceObserver;\n private _pendingEntries: PerformanceResourceTiming[] = [];\n private _idleHandle?: IdleCallbackHandle;\n\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 _loadHandler: (() => void) | undefined;\n private declare _visibilityChangeHandler: (() => void) | undefined;\n\n constructor(config: ResourceTimingInstrumentationConfig = {}) {\n super(\n '@opentelemetry/browser-instrumentation/resource-timing',\n version,\n config,\n );\n }\n\n protected override init() {\n return [];\n }\n\n override enable(): void {\n if (this._isEnabled) {\n return;\n }\n\n if (!('PerformanceObserver' in window)) {\n this._diag.debug(\n 'PerformanceObserver is not supported, resource timings will not be collected',\n );\n return;\n }\n\n this._isEnabled = true;\n\n if (document.readyState === 'complete') {\n this._setupObserver();\n } else {\n this._loadHandler = () => this._setupObserver();\n window.addEventListener('load', this._loadHandler, { once: true });\n }\n\n this._visibilityChangeHandler = () => {\n if (document.hidden) {\n this._flush();\n }\n };\n document.addEventListener(\n 'visibilitychange',\n this._visibilityChangeHandler,\n );\n }\n\n override disable(): void {\n this._isEnabled = false;\n this._flush();\n this._observer?.disconnect();\n this._observer = undefined;\n if (this._loadHandler) {\n window.removeEventListener('load', this._loadHandler);\n this._loadHandler = undefined;\n }\n if (this._visibilityChangeHandler) {\n document.removeEventListener(\n 'visibilitychange',\n this._visibilityChangeHandler,\n );\n this._visibilityChangeHandler = undefined;\n }\n }\n\n private _setupObserver(): void {\n if (!this._isEnabled) {\n return;\n }\n\n try {\n const observer = new PerformanceObserver((list) => {\n if (!this._isEnabled) {\n return;\n }\n\n const maxQueueSize = Math.max(\n this._config.maxQueueSize ?? DEFAULT_MAX_QUEUE_SIZE,\n MIN_QUEUE_SIZE,\n );\n const entries = list.getEntries() as PerformanceResourceTiming[];\n const initiatorTypes = this._config.initiatorTypes;\n\n for (const entry of entries) {\n if (\n initiatorTypes !== undefined &&\n !initiatorTypes.includes(entry.initiatorType)\n ) {\n continue;\n }\n\n if (this._pendingEntries.length >= maxQueueSize) {\n this._flush();\n }\n this._pendingEntries.push(entry);\n }\n\n if (this._pendingEntries.length > 0) {\n this._scheduleProcessing();\n }\n });\n\n this._observer = observer;\n observer.observe({ type: 'resource', buffered: true });\n } catch {\n this._diag.warn(\n 'PerformanceObserver not supported, resource timings will not be collected',\n );\n }\n }\n\n private _scheduleProcessing(): void {\n if (this._idleHandle !== undefined) {\n return;\n }\n\n const timeout = Math.max(\n this._config.forceProcessingAfter ?? DEFAULT_FORCE_PROCESSING_AFTER,\n MIN_FORCE_PROCESSING_AFTER,\n );\n this._idleHandle = requestIdleCallbackShim(\n (deadline) => this._processChunk(deadline),\n { timeout },\n );\n }\n\n private _processChunk(deadline: IdleDeadline): void {\n this._idleHandle = undefined;\n if (!this._isEnabled || this._pendingEntries.length === 0) {\n return;\n }\n\n const maxTime = Math.max(\n this._config.maxProcessingTime ?? DEFAULT_MAX_PROCESSING_TIME,\n MIN_PROCESSING_TIME,\n );\n const batchSize = Math.max(\n this._config.batchSize ?? DEFAULT_BATCH_SIZE,\n MIN_BATCH_SIZE,\n );\n const startTime = performance.now();\n\n let cursor = 0;\n try {\n for (let i = 0; i < batchSize; i++) {\n const entry = this._pendingEntries[cursor];\n if (entry === undefined) {\n break;\n }\n\n const elapsed = performance.now() - startTime;\n // timeRemaining() is not Baseline widely available (no Safari support),\n // compatibility is handled by idle-callback-shim.ts.\n // eslint-disable-next-line baseline-js/use-baseline\n if (elapsed >= maxTime || deadline.timeRemaining() < 1) {\n break;\n }\n\n cursor++;\n this._emitResource(entry);\n }\n } finally {\n this._pendingEntries.splice(0, cursor);\n if (this._pendingEntries.length > 0) {\n this._scheduleProcessing();\n }\n }\n }\n\n private _emitResource(entry: PerformanceResourceTiming): void {\n try {\n this.logger.emit({\n eventName: RESOURCE_TIMING_EVENT_NAME,\n severityNumber: SeverityNumber.INFO,\n attributes: {\n [ATTR_RESOURCE_URL]: entry.name,\n [ATTR_RESOURCE_INITIATOR_TYPE]: entry.initiatorType,\n [ATTR_RESOURCE_DURATION]: entry.duration,\n [ATTR_RESOURCE_FETCH_START]: entry.fetchStart,\n [ATTR_RESOURCE_DOMAIN_LOOKUP_START]: entry.domainLookupStart,\n [ATTR_RESOURCE_DOMAIN_LOOKUP_END]: entry.domainLookupEnd,\n [ATTR_RESOURCE_CONNECT_START]: entry.connectStart,\n [ATTR_RESOURCE_CONNECT_END]: entry.connectEnd,\n [ATTR_RESOURCE_SECURE_CONNECTION_START]: entry.secureConnectionStart,\n [ATTR_RESOURCE_REQUEST_START]: entry.requestStart,\n [ATTR_RESOURCE_RESPONSE_START]: entry.responseStart,\n [ATTR_RESOURCE_RESPONSE_END]: entry.responseEnd,\n [ATTR_RESOURCE_TRANSFER_SIZE]: entry.transferSize,\n [ATTR_RESOURCE_ENCODED_BODY_SIZE]: entry.encodedBodySize,\n [ATTR_RESOURCE_DECODED_BODY_SIZE]: entry.decodedBodySize,\n [ATTR_RESOURCE_REDIRECT_START]: entry.redirectStart,\n [ATTR_RESOURCE_REDIRECT_END]: entry.redirectEnd,\n [ATTR_RESOURCE_WORKER_START]: entry.workerStart,\n [ATTR_RESOURCE_NEXT_HOP_PROTOCOL]: entry.nextHopProtocol,\n // @ts-expect-error renderBlockingStatus is only available in Chromium as of March 2026\n [ATTR_RESOURCE_RENDER_BLOCKING_STATUS]: entry.renderBlockingStatus,\n },\n });\n } catch (error) {\n this._diag.error(\n `Failed to emit resource timing entry for \"${entry.name}\"`,\n error,\n );\n }\n }\n\n private _flush(): void {\n this._cancelScheduledProcessing();\n\n for (const entry of this._pendingEntries) {\n this._emitResource(entry);\n }\n this._pendingEntries = [];\n }\n\n private _cancelScheduledProcessing(): void {\n if (this._idleHandle !== undefined) {\n cancelIdleCallbackShim(this._idleHandle);\n this._idleHandle = undefined;\n }\n }\n}\n"],"mappings":";;;;;;AAsCA,MAAM,qBAAqB;AAC3B,MAAM,iCAAiC;AACvC,MAAM,8BAA8B;AACpC,MAAM,yBAAyB;AAE/B,MAAM,iBAAiB;AACvB,MAAM,6BAA6B;AACnC,MAAM,sBAAsB;AAC5B,MAAM,iBAAiB;;;;;;;;;AAUvB,IAAa,gCAAb,cAAmD,oBAAyD;CAC1G;CACA,kBAAuD,EAAE;CACzD;CASA,YAAY,SAA8C,EAAE,EAAE;AAC5D,QACE,0DACA,SACA,OACD;;CAGH,OAA0B;AACxB,SAAO,EAAE;;CAGX,SAAwB;AACtB,MAAI,KAAK,WACP;AAGF,MAAI,EAAE,yBAAyB,SAAS;AACtC,QAAK,MAAM,MACT,+EACD;AACD;;AAGF,OAAK,aAAa;AAElB,MAAI,SAAS,eAAe,WAC1B,MAAK,gBAAgB;OAChB;AACL,QAAK,qBAAqB,KAAK,gBAAgB;AAC/C,UAAO,iBAAiB,QAAQ,KAAK,cAAc,EAAE,MAAM,MAAM,CAAC;;AAGpE,OAAK,iCAAiC;AACpC,OAAI,SAAS,OACX,MAAK,QAAQ;;AAGjB,WAAS,iBACP,oBACA,KAAK,yBACN;;CAGH,UAAyB;AACvB,OAAK,aAAa;AAClB,OAAK,QAAQ;AACb,OAAK,WAAW,YAAY;AAC5B,OAAK,YAAY,KAAA;AACjB,MAAI,KAAK,cAAc;AACrB,UAAO,oBAAoB,QAAQ,KAAK,aAAa;AACrD,QAAK,eAAe,KAAA;;AAEtB,MAAI,KAAK,0BAA0B;AACjC,YAAS,oBACP,oBACA,KAAK,yBACN;AACD,QAAK,2BAA2B,KAAA;;;CAIpC,iBAA+B;AAC7B,MAAI,CAAC,KAAK,WACR;AAGF,MAAI;GACF,MAAM,WAAW,IAAI,qBAAqB,SAAS;AACjD,QAAI,CAAC,KAAK,WACR;IAGF,MAAM,eAAe,KAAK,IACxB,KAAK,QAAQ,gBAAgB,wBAC7B,eACD;IACD,MAAM,UAAU,KAAK,YAAY;IACjC,MAAM,iBAAiB,KAAK,QAAQ;AAEpC,SAAK,MAAM,SAAS,SAAS;AAC3B,SACE,mBAAmB,KAAA,KACnB,CAAC,eAAe,SAAS,MAAM,cAAc,CAE7C;AAGF,SAAI,KAAK,gBAAgB,UAAU,aACjC,MAAK,QAAQ;AAEf,UAAK,gBAAgB,KAAK,MAAM;;AAGlC,QAAI,KAAK,gBAAgB,SAAS,EAChC,MAAK,qBAAqB;KAE5B;AAEF,QAAK,YAAY;AACjB,YAAS,QAAQ;IAAE,MAAM;IAAY,UAAU;IAAM,CAAC;UAChD;AACN,QAAK,MAAM,KACT,4EACD;;;CAIL,sBAAoC;AAClC,MAAI,KAAK,gBAAgB,KAAA,EACvB;EAGF,MAAM,UAAU,KAAK,IACnB,KAAK,QAAQ,wBAAwB,gCACrC,2BACD;AACD,OAAK,cAAc,yBAChB,aAAa,KAAK,cAAc,SAAS,EAC1C,EAAE,SAAS,CACZ;;CAGH,cAAsB,UAA8B;AAClD,OAAK,cAAc,KAAA;AACnB,MAAI,CAAC,KAAK,cAAc,KAAK,gBAAgB,WAAW,EACtD;EAGF,MAAM,UAAU,KAAK,IACnB,KAAK,QAAQ,qBAAqB,6BAClC,oBACD;EACD,MAAM,YAAY,KAAK,IACrB,KAAK,QAAQ,aAAa,oBAC1B,eACD;EACD,MAAM,YAAY,YAAY,KAAK;EAEnC,IAAI,SAAS;AACb,MAAI;AACF,QAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;IAClC,MAAM,QAAQ,KAAK,gBAAgB;AACnC,QAAI,UAAU,KAAA,EACZ;AAOF,QAJgB,YAAY,KAAK,GAAG,aAIrB,WAAW,SAAS,eAAe,GAAG,EACnD;AAGF;AACA,SAAK,cAAc,MAAM;;YAEnB;AACR,QAAK,gBAAgB,OAAO,GAAG,OAAO;AACtC,OAAI,KAAK,gBAAgB,SAAS,EAChC,MAAK,qBAAqB;;;CAKhC,cAAsB,OAAwC;AAC5D,MAAI;AACF,QAAK,OAAO,KAAK;IACf,WAAW;IACX,gBAAgB,eAAe;IAC/B,YAAY;MACT,oBAAoB,MAAM;MAC1B,+BAA+B,MAAM;MACrC,yBAAyB,MAAM;MAC/B,4BAA4B,MAAM;MAClC,oCAAoC,MAAM;MAC1C,kCAAkC,MAAM;MACxC,8BAA8B,MAAM;MACpC,4BAA4B,MAAM;MAClC,wCAAwC,MAAM;MAC9C,8BAA8B,MAAM;MACpC,+BAA+B,MAAM;MACrC,6BAA6B,MAAM;MACnC,8BAA8B,MAAM;MACpC,kCAAkC,MAAM;MACxC,kCAAkC,MAAM;MACxC,+BAA+B,MAAM;MACrC,6BAA6B,MAAM;MACnC,6BAA6B,MAAM;MACnC,kCAAkC,MAAM;MAExC,uCAAuC,MAAM;KAC/C;IACF,CAAC;WACK,OAAO;AACd,QAAK,MAAM,MACT,6CAA6C,MAAM,KAAK,IACxD,MACD;;;CAIL,SAAuB;AACrB,OAAK,4BAA4B;AAEjC,OAAK,MAAM,SAAS,KAAK,gBACvB,MAAK,cAAc,MAAM;AAE3B,OAAK,kBAAkB,EAAE;;CAG3B,6BAA2C;AACzC,MAAI,KAAK,gBAAgB,KAAA,GAAW;AAClC,0BAAuB,KAAK,YAAY;AACxC,QAAK,cAAc,KAAA"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//#region src/resource-timing/semconv.ts
|
|
2
|
+
/**
|
|
3
|
+
* Event name for resource timing
|
|
4
|
+
*
|
|
5
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
6
|
+
*/
|
|
7
|
+
const RESOURCE_TIMING_EVENT_NAME = "browser.resource_timing";
|
|
8
|
+
/**
|
|
9
|
+
* The URL of the resource
|
|
10
|
+
*
|
|
11
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
12
|
+
*/
|
|
13
|
+
const ATTR_RESOURCE_URL = "url.full";
|
|
14
|
+
/**
|
|
15
|
+
* The type of resource (script, stylesheet, img, xmlhttprequest, fetch, etc.)
|
|
16
|
+
*
|
|
17
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
18
|
+
*/
|
|
19
|
+
const ATTR_RESOURCE_INITIATOR_TYPE = "browser.resource_timing.initiator_type";
|
|
20
|
+
/**
|
|
21
|
+
* Total duration of the resource load (in milliseconds)
|
|
22
|
+
*
|
|
23
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
24
|
+
*/
|
|
25
|
+
const ATTR_RESOURCE_DURATION = "browser.resource_timing.duration";
|
|
26
|
+
/**
|
|
27
|
+
* Start time of the resource fetch (relative to navigation start)
|
|
28
|
+
*
|
|
29
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
30
|
+
*/
|
|
31
|
+
const ATTR_RESOURCE_FETCH_START = "browser.resource_timing.fetch_start";
|
|
32
|
+
/**
|
|
33
|
+
* Domain lookup start time
|
|
34
|
+
*
|
|
35
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
36
|
+
*/
|
|
37
|
+
const ATTR_RESOURCE_DOMAIN_LOOKUP_START = "browser.resource_timing.domain_lookup_start";
|
|
38
|
+
/**
|
|
39
|
+
* Domain lookup end time
|
|
40
|
+
*
|
|
41
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
42
|
+
*/
|
|
43
|
+
const ATTR_RESOURCE_DOMAIN_LOOKUP_END = "browser.resource_timing.domain_lookup_end";
|
|
44
|
+
/**
|
|
45
|
+
* Connection start time
|
|
46
|
+
*
|
|
47
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
48
|
+
*/
|
|
49
|
+
const ATTR_RESOURCE_CONNECT_START = "browser.resource_timing.connect_start";
|
|
50
|
+
/**
|
|
51
|
+
* Connection end time
|
|
52
|
+
*
|
|
53
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
54
|
+
*/
|
|
55
|
+
const ATTR_RESOURCE_CONNECT_END = "browser.resource_timing.connect_end";
|
|
56
|
+
/**
|
|
57
|
+
* Secure connection start time (HTTPS)
|
|
58
|
+
*
|
|
59
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
60
|
+
*/
|
|
61
|
+
const ATTR_RESOURCE_SECURE_CONNECTION_START = "browser.resource_timing.secure_connection_start";
|
|
62
|
+
/**
|
|
63
|
+
* Request start time
|
|
64
|
+
*
|
|
65
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
66
|
+
*/
|
|
67
|
+
const ATTR_RESOURCE_REQUEST_START = "browser.resource_timing.request_start";
|
|
68
|
+
/**
|
|
69
|
+
* Response start time
|
|
70
|
+
*
|
|
71
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
72
|
+
*/
|
|
73
|
+
const ATTR_RESOURCE_RESPONSE_START = "browser.resource_timing.response_start";
|
|
74
|
+
/**
|
|
75
|
+
* Response end time
|
|
76
|
+
*
|
|
77
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
78
|
+
*/
|
|
79
|
+
const ATTR_RESOURCE_RESPONSE_END = "browser.resource_timing.response_end";
|
|
80
|
+
/**
|
|
81
|
+
* Transfer size in bytes (including headers)
|
|
82
|
+
*
|
|
83
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
84
|
+
*/
|
|
85
|
+
const ATTR_RESOURCE_TRANSFER_SIZE = "browser.resource_timing.transfer_size";
|
|
86
|
+
/**
|
|
87
|
+
* Encoded body size in bytes (compressed)
|
|
88
|
+
*
|
|
89
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
90
|
+
*/
|
|
91
|
+
const ATTR_RESOURCE_ENCODED_BODY_SIZE = "browser.resource_timing.encoded_body_size";
|
|
92
|
+
/**
|
|
93
|
+
* Decoded body size in bytes (uncompressed)
|
|
94
|
+
*
|
|
95
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
96
|
+
*/
|
|
97
|
+
const ATTR_RESOURCE_DECODED_BODY_SIZE = "browser.resource_timing.decoded_body_size";
|
|
98
|
+
/**
|
|
99
|
+
* Redirect start time
|
|
100
|
+
*
|
|
101
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
102
|
+
*/
|
|
103
|
+
const ATTR_RESOURCE_REDIRECT_START = "browser.resource_timing.redirect_start";
|
|
104
|
+
/**
|
|
105
|
+
* Redirect end time
|
|
106
|
+
*
|
|
107
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
108
|
+
*/
|
|
109
|
+
const ATTR_RESOURCE_REDIRECT_END = "browser.resource_timing.redirect_end";
|
|
110
|
+
/**
|
|
111
|
+
* Worker start time (for Service Worker interception)
|
|
112
|
+
*
|
|
113
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
114
|
+
*/
|
|
115
|
+
const ATTR_RESOURCE_WORKER_START = "browser.resource_timing.worker_start";
|
|
116
|
+
/**
|
|
117
|
+
* Next hop protocol (h2, h3, http/1.1, etc.)
|
|
118
|
+
*
|
|
119
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
120
|
+
*/
|
|
121
|
+
const ATTR_RESOURCE_NEXT_HOP_PROTOCOL = "browser.resource_timing.next_hop_protocol";
|
|
122
|
+
/**
|
|
123
|
+
* Render blocking status (blocking, non-blocking)
|
|
124
|
+
*
|
|
125
|
+
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
|
|
126
|
+
*/
|
|
127
|
+
const ATTR_RESOURCE_RENDER_BLOCKING_STATUS = "browser.resource_timing.render_blocking_status";
|
|
128
|
+
//#endregion
|
|
129
|
+
export { ATTR_RESOURCE_CONNECT_END, ATTR_RESOURCE_CONNECT_START, ATTR_RESOURCE_DECODED_BODY_SIZE, ATTR_RESOURCE_DOMAIN_LOOKUP_END, ATTR_RESOURCE_DOMAIN_LOOKUP_START, ATTR_RESOURCE_DURATION, ATTR_RESOURCE_ENCODED_BODY_SIZE, ATTR_RESOURCE_FETCH_START, ATTR_RESOURCE_INITIATOR_TYPE, ATTR_RESOURCE_NEXT_HOP_PROTOCOL, ATTR_RESOURCE_REDIRECT_END, ATTR_RESOURCE_REDIRECT_START, ATTR_RESOURCE_RENDER_BLOCKING_STATUS, ATTR_RESOURCE_REQUEST_START, ATTR_RESOURCE_RESPONSE_END, ATTR_RESOURCE_RESPONSE_START, ATTR_RESOURCE_SECURE_CONNECTION_START, ATTR_RESOURCE_TRANSFER_SIZE, ATTR_RESOURCE_URL, ATTR_RESOURCE_WORKER_START, RESOURCE_TIMING_EVENT_NAME };
|
|
130
|
+
|
|
131
|
+
//# sourceMappingURL=semconv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semconv.js","names":[],"sources":["../../src/resource-timing/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 resource timing\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const RESOURCE_TIMING_EVENT_NAME = 'browser.resource_timing';\n\n// Resource timing attributes\n\n/**\n * The URL of the resource\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_URL = 'url.full';\n\n/**\n * The type of resource (script, stylesheet, img, xmlhttprequest, fetch, etc.)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_INITIATOR_TYPE =\n 'browser.resource_timing.initiator_type';\n\n/**\n * Total duration of the resource load (in milliseconds)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_DURATION = 'browser.resource_timing.duration';\n\n/**\n * Start time of the resource fetch (relative to navigation start)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_FETCH_START = 'browser.resource_timing.fetch_start';\n\n/**\n * Domain lookup start time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_DOMAIN_LOOKUP_START =\n 'browser.resource_timing.domain_lookup_start';\n\n/**\n * Domain lookup end time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_DOMAIN_LOOKUP_END =\n 'browser.resource_timing.domain_lookup_end';\n\n/**\n * Connection start time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_CONNECT_START =\n 'browser.resource_timing.connect_start';\n\n/**\n * Connection end time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_CONNECT_END = 'browser.resource_timing.connect_end';\n\n/**\n * Secure connection start time (HTTPS)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_SECURE_CONNECTION_START =\n 'browser.resource_timing.secure_connection_start';\n\n/**\n * Request start time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_REQUEST_START =\n 'browser.resource_timing.request_start';\n\n/**\n * Response start time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_RESPONSE_START =\n 'browser.resource_timing.response_start';\n\n/**\n * Response end time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_RESPONSE_END =\n 'browser.resource_timing.response_end';\n\n/**\n * Transfer size in bytes (including headers)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_TRANSFER_SIZE =\n 'browser.resource_timing.transfer_size';\n\n/**\n * Encoded body size in bytes (compressed)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_ENCODED_BODY_SIZE =\n 'browser.resource_timing.encoded_body_size';\n\n/**\n * Decoded body size in bytes (uncompressed)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_DECODED_BODY_SIZE =\n 'browser.resource_timing.decoded_body_size';\n\n/**\n * Redirect start time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_REDIRECT_START =\n 'browser.resource_timing.redirect_start';\n\n/**\n * Redirect end time\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_REDIRECT_END =\n 'browser.resource_timing.redirect_end';\n\n/**\n * Worker start time (for Service Worker interception)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_WORKER_START =\n 'browser.resource_timing.worker_start';\n\n/**\n * Next hop protocol (h2, h3, http/1.1, etc.)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_NEXT_HOP_PROTOCOL =\n 'browser.resource_timing.next_hop_protocol';\n\n/**\n * Render blocking status (blocking, non-blocking)\n *\n * @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.\n */\nexport const ATTR_RESOURCE_RENDER_BLOCKING_STATUS =\n 'browser.resource_timing.render_blocking_status';\n"],"mappings":";;;;;;AAgBA,MAAa,6BAA6B;;;;;;AAS1C,MAAa,oBAAoB;;;;;;AAOjC,MAAa,+BACX;;;;;;AAOF,MAAa,yBAAyB;;;;;;AAOtC,MAAa,4BAA4B;;;;;;AAOzC,MAAa,oCACX;;;;;;AAOF,MAAa,kCACX;;;;;;AAOF,MAAa,8BACX;;;;;;AAOF,MAAa,4BAA4B;;;;;;AAOzC,MAAa,wCACX;;;;;;AAOF,MAAa,8BACX;;;;;;AAOF,MAAa,+BACX;;;;;;AAOF,MAAa,6BACX;;;;;;AAOF,MAAa,8BACX;;;;;;AAOF,MAAa,kCACX;;;;;;AAOF,MAAa,kCACX;;;;;;AAOF,MAAa,+BACX;;;;;;AAOF,MAAa,6BACX;;;;;;AAOF,MAAa,6BACX;;;;;;AAOF,MAAa,kCACX;;;;;;AAOF,MAAa,uCACX"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { InstrumentationConfig } from "@opentelemetry/instrumentation";
|
|
2
|
+
|
|
3
|
+
//#region src/resource-timing/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* ResourceTimingInstrumentation Configuration
|
|
6
|
+
*/
|
|
7
|
+
interface ResourceTimingInstrumentationConfig extends InstrumentationConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Number of resources to process per batch.
|
|
10
|
+
* Default: 50
|
|
11
|
+
*/
|
|
12
|
+
batchSize?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Maximum time in milliseconds to wait for an idle callback before forcing processing.
|
|
15
|
+
* Default: 1000
|
|
16
|
+
*/
|
|
17
|
+
forceProcessingAfter?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum time in milliseconds to spend processing resources per idle callback.
|
|
20
|
+
* Default: 50
|
|
21
|
+
*/
|
|
22
|
+
maxProcessingTime?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Maximum number of resources to queue before forcing immediate flush.
|
|
25
|
+
* Default: 1000
|
|
26
|
+
*/
|
|
27
|
+
maxQueueSize?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Filter which resource types to capture by their initiator type
|
|
30
|
+
* (e.g. 'xmlhttprequest', 'fetch', 'script', 'link', 'img', 'css', etc.).
|
|
31
|
+
* When set, only entries whose initiatorType matches one of the listed values
|
|
32
|
+
* are captured. When unset, all resource entries are captured.
|
|
33
|
+
*/
|
|
34
|
+
initiatorTypes?: string[];
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { ResourceTimingInstrumentationConfig };
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getElementCSSSelector.js","names":[],"sources":["../../src/utils/getElementCSSSelector.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\ntype GetElementCSSSelectorOptions = {\n /**\n * If true, the function will attempt to use element ID to create condensed CSS selector.\n */\n useIdForTargetElement?: boolean;\n /**\n * If true, the function will attempt to use element ID for all ancestor elements to create condensed CSS selector.\n */\n useIdForAncestors?: boolean;\n};\n\n/**\n * Generates the CSS selector of a given element in the DOM tree.\n *\n * @example #main > div:nth-child(2) > button.submit\n * @example #unique-id\n */\nexport const getElementCSSSelector = (\n element: Node,\n {\n useIdForTargetElement = false,\n useIdForAncestors = false,\n }: GetElementCSSSelectorOptions = {},\n): string => {\n // Handle document node\n if (element.nodeType === Node.DOCUMENT_NODE) {\n return '';\n }\n\n const htmlElement = element as HTMLElement;\n const nodeValue = getNodeSelector(\n htmlElement,\n useIdForTargetElement || useIdForAncestors,\n );\n\n // If optimized and found an ID selector, stop recursion early\n if (nodeValue.startsWith('#')) {\n return nodeValue;\n }\n\n const parent = htmlElement.parentElement;\n const parentSelector = parent\n ? getElementCSSSelector(parent, {\n useIdForAncestors,\n useIdForTargetElement: false,\n })\n : '';\n\n return parentSelector ? `${parentSelector} > ${nodeValue}` : nodeValue;\n};\n\nconst getNodeSelector = (element: Node, useElementId = false): string => {\n if (element.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const htmlElement = element as HTMLElement;\n const id = htmlElement.getAttribute('id');\n\n // Use ID if requested and it's unique\n if (useElementId && id) {\n // Check if ID is unique in the document\n const elementsWithSameId = htmlElement.ownerDocument.querySelectorAll(\n `#${CSS.escape(id)}`,\n );\n\n if (elementsWithSameId.length === 1) {\n return `#${CSS.escape(id)}`;\n }\n }\n\n let selector = getFullClassSelector(htmlElement);\n // Add nth-child if there are siblings with the same tag and classes\n const index = getNthChild(htmlElement);\n\n if (index > 0) {\n selector += `:nth-child(${index})`;\n }\n\n return selector;\n};\n\nconst getNthChild = (element: HTMLElement): number => {\n // parentElement is needed to access children\n if (!element.parentElement) {\n return 0;\n }\n\n const selector = getFullClassSelector(element);\n\n // Get all siblings that match the same selector\n const siblings = Array.from(element.parentElement.children).filter(\n (sibling) => getFullClassSelector(sibling) === selector,\n );\n\n // Only add nth-child if there are multiple matching siblings\n if (siblings.length > 1) {\n return siblings.indexOf(element) + 1;\n }\n\n return 0;\n};\n\nconst getFullClassSelector = (element: Element): string =>\n element.localName +\n (element.classList.length > 0\n ? Array.from(element.classList)\n .map((cls) => `.${CSS.escape(cls)}`)\n .join('')\n : '');\n"],"mappings":";;;;;;;AAsBA,MAAa,yBACX,SACA,EACE,wBAAwB,OACxB,oBAAoB,UACY,EAAE,KACzB;AAEX,KAAI,QAAQ,aAAa,KAAK,cAC5B,QAAO;CAGT,MAAM,cAAc;CACpB,MAAM,YAAY,gBAChB,aACA,yBAAyB,kBAC1B;AAGD,KAAI,UAAU,WAAW,IAAI,CAC3B,QAAO;CAGT,MAAM,SAAS,YAAY;CAC3B,MAAM,iBAAiB,SACnB,sBAAsB,QAAQ;EAC5B;EACA,uBAAuB;EACxB,CAAC,GACF;AAEJ,QAAO,iBAAiB,GAAG,eAAe,KAAK,cAAc;;AAG/D,MAAM,mBAAmB,SAAe,eAAe,UAAkB;AACvE,KAAI,QAAQ,aAAa,KAAK,aAC5B,QAAO;CAGT,MAAM,cAAc;CACpB,MAAM,KAAK,YAAY,aAAa,KAAK;AAGzC,KAAI,gBAAgB;MAES,YAAY,cAAc,iBACnD,IAAI,IAAI,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"getElementCSSSelector.js","names":[],"sources":["../../src/utils/getElementCSSSelector.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\ntype GetElementCSSSelectorOptions = {\n /**\n * If true, the function will attempt to use element ID to create condensed CSS selector.\n */\n useIdForTargetElement?: boolean;\n /**\n * If true, the function will attempt to use element ID for all ancestor elements to create condensed CSS selector.\n */\n useIdForAncestors?: boolean;\n};\n\n/**\n * Generates the CSS selector of a given element in the DOM tree.\n *\n * @example #main > div:nth-child(2) > button.submit\n * @example #unique-id\n */\nexport const getElementCSSSelector = (\n element: Node,\n {\n useIdForTargetElement = false,\n useIdForAncestors = false,\n }: GetElementCSSSelectorOptions = {},\n): string => {\n // Handle document node\n if (element.nodeType === Node.DOCUMENT_NODE) {\n return '';\n }\n\n const htmlElement = element as HTMLElement;\n const nodeValue = getNodeSelector(\n htmlElement,\n useIdForTargetElement || useIdForAncestors,\n );\n\n // If optimized and found an ID selector, stop recursion early\n if (nodeValue.startsWith('#')) {\n return nodeValue;\n }\n\n const parent = htmlElement.parentElement;\n const parentSelector = parent\n ? getElementCSSSelector(parent, {\n useIdForAncestors,\n useIdForTargetElement: false,\n })\n : '';\n\n return parentSelector ? `${parentSelector} > ${nodeValue}` : nodeValue;\n};\n\nconst getNodeSelector = (element: Node, useElementId = false): string => {\n if (element.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const htmlElement = element as HTMLElement;\n const id = htmlElement.getAttribute('id');\n\n // Use ID if requested and it's unique\n if (useElementId && id) {\n // Check if ID is unique in the document\n const elementsWithSameId = htmlElement.ownerDocument.querySelectorAll(\n `#${CSS.escape(id)}`,\n );\n\n if (elementsWithSameId.length === 1) {\n return `#${CSS.escape(id)}`;\n }\n }\n\n let selector = getFullClassSelector(htmlElement);\n // Add nth-child if there are siblings with the same tag and classes\n const index = getNthChild(htmlElement);\n\n if (index > 0) {\n selector += `:nth-child(${index})`;\n }\n\n return selector;\n};\n\nconst getNthChild = (element: HTMLElement): number => {\n // parentElement is needed to access children\n if (!element.parentElement) {\n return 0;\n }\n\n const selector = getFullClassSelector(element);\n\n // Get all siblings that match the same selector\n const siblings = Array.from(element.parentElement.children).filter(\n (sibling) => getFullClassSelector(sibling) === selector,\n );\n\n // Only add nth-child if there are multiple matching siblings\n if (siblings.length > 1) {\n return siblings.indexOf(element) + 1;\n }\n\n return 0;\n};\n\nconst getFullClassSelector = (element: Element): string =>\n element.localName +\n (element.classList.length > 0\n ? Array.from(element.classList)\n .map((cls) => `.${CSS.escape(cls)}`)\n .join('')\n : '');\n"],"mappings":";;;;;;;AAsBA,MAAa,yBACX,SACA,EACE,wBAAwB,OACxB,oBAAoB,UACY,EAAE,KACzB;AAEX,KAAI,QAAQ,aAAa,KAAK,cAC5B,QAAO;CAGT,MAAM,cAAc;CACpB,MAAM,YAAY,gBAChB,aACA,yBAAyB,kBAC1B;AAGD,KAAI,UAAU,WAAW,IAAI,CAC3B,QAAO;CAGT,MAAM,SAAS,YAAY;CAC3B,MAAM,iBAAiB,SACnB,sBAAsB,QAAQ;EAC5B;EACA,uBAAuB;EACxB,CAAC,GACF;AAEJ,QAAO,iBAAiB,GAAG,eAAe,KAAK,cAAc;;AAG/D,MAAM,mBAAmB,SAAe,eAAe,UAAkB;AACvE,KAAI,QAAQ,aAAa,KAAK,aAC5B,QAAO;CAGT,MAAM,cAAc;CACpB,MAAM,KAAK,YAAY,aAAa,KAAK;AAGzC,KAAI,gBAAgB;MAES,YAAY,cAAc,iBACnD,IAAI,IAAI,OAAO,GAAG,GAGE,CAAC,WAAW,EAChC,QAAO,IAAI,IAAI,OAAO,GAAG;;CAI7B,IAAI,WAAW,qBAAqB,YAAY;CAEhD,MAAM,QAAQ,YAAY,YAAY;AAEtC,KAAI,QAAQ,EACV,aAAY,cAAc,MAAM;AAGlC,QAAO;;AAGT,MAAM,eAAe,YAAiC;AAEpD,KAAI,CAAC,QAAQ,cACX,QAAO;CAGT,MAAM,WAAW,qBAAqB,QAAQ;CAG9C,MAAM,WAAW,MAAM,KAAK,QAAQ,cAAc,SAAS,CAAC,QACzD,YAAY,qBAAqB,QAAQ,KAAK,SAChD;AAGD,KAAI,SAAS,SAAS,EACpB,QAAO,SAAS,QAAQ,QAAQ,GAAG;AAGrC,QAAO;;AAGT,MAAM,wBAAwB,YAC5B,QAAQ,aACP,QAAQ,UAAU,SAAS,IACxB,MAAM,KAAK,QAAQ,UAAU,CAC1B,KAAK,QAAQ,IAAI,IAAI,OAAO,IAAI,GAAG,CACnC,KAAK,GAAG,GACX"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentelemetry/browser-instrumentation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "OpenTelemetry browser instrumentations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opentelemetry",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"instrumentation",
|
|
10
10
|
"navigation-timing",
|
|
11
11
|
"user-action",
|
|
12
|
-
"web-vitals"
|
|
12
|
+
"web-vitals",
|
|
13
|
+
"resource-timing"
|
|
13
14
|
],
|
|
14
15
|
"homepage": "https://github.com/open-telemetry/opentelemetry-browser",
|
|
15
16
|
"bugs": "https://github.com/open-telemetry/opentelemetry-browser/issues",
|
|
@@ -28,7 +29,8 @@
|
|
|
28
29
|
"exports": {
|
|
29
30
|
"./experimental/navigation-timing": "./dist/navigation-timing/index.js",
|
|
30
31
|
"./experimental/user-action": "./dist/user-action/index.js",
|
|
31
|
-
"./experimental/web-vitals": "./dist/web-vitals/index.js"
|
|
32
|
+
"./experimental/web-vitals": "./dist/web-vitals/index.js",
|
|
33
|
+
"./experimental/resource-timing": "./dist/resource-timing/index.js"
|
|
32
34
|
},
|
|
33
35
|
"files": [
|
|
34
36
|
"dist"
|
|
@@ -42,15 +44,15 @@
|
|
|
42
44
|
"test:coverage": "vitest --coverage"
|
|
43
45
|
},
|
|
44
46
|
"dependencies": {
|
|
45
|
-
"@opentelemetry/api-logs": "^0.
|
|
46
|
-
"@opentelemetry/instrumentation": "^0.
|
|
47
|
-
"web-vitals": "^5.
|
|
47
|
+
"@opentelemetry/api-logs": "^0.215.0",
|
|
48
|
+
"@opentelemetry/instrumentation": "^0.215.0",
|
|
49
|
+
"web-vitals": "^5.2.0"
|
|
48
50
|
},
|
|
49
51
|
"peerDependencies": {
|
|
50
52
|
"@opentelemetry/api": "^1.9.0"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
|
-
"@opentelemetry/sdk-logs": "^0.
|
|
55
|
+
"@opentelemetry/sdk-logs": "^0.215.0"
|
|
54
56
|
},
|
|
55
57
|
"publishConfig": {
|
|
56
58
|
"access": "public"
|