@dash0/sdk-web 0.13.1 → 0.13.3
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 +15 -1
- package/dist/dash0.iife.js +1 -1
- package/dist/dash0.iife.js.map +1 -1
- package/dist/dash0.js +1 -1
- package/dist/dash0.js.map +1 -1
- package/dist/dash0.umd.cjs +1 -1
- package/dist/dash0.umd.cjs.map +1 -1
- package/dist/modules/api/log-level.js +1 -0
- package/dist/modules/entrypoint/npm-package.js +1 -0
- package/dist/modules/entrypoint/script.js +2 -0
- package/dist/modules/instrumentations/http/fetch.js +5 -2
- package/dist/modules/semantic-conventions.js +2 -0
- package/dist/modules/transport/fetch.js +2 -1
- package/dist/modules/utils/debug.js +20 -10
- package/dist/modules/utils/performance.js +43 -19
- package/dist/modules/vars.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/api/log-level.d.ts +2 -0
- package/dist/types/entrypoint/npm-package.d.ts +1 -0
- package/dist/types/semantic-conventions.d.ts +1 -0
- package/dist/types/utils/debug.d.ts +11 -1
- package/dist/types/vars.d.ts +1 -1
- package/package.json +1 -1
- package/src/api/log-level.ts +2 -0
- package/src/entrypoint/npm-package.ts +1 -0
- package/src/entrypoint/script.ts +2 -0
- package/src/instrumentations/http/fetch.ts +5 -1
- package/src/semantic-conventions.ts +3 -0
- package/src/transport/fetch.ts +3 -1
- package/src/utils/debug.ts +25 -10
- package/src/utils/performance.ts +55 -22
- package/src/vars.ts +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { setActiveLogLevel } from "../utils/debug";
|
|
@@ -4,6 +4,7 @@ export * from "../api/identify";
|
|
|
4
4
|
export * from "../api/debug";
|
|
5
5
|
export * from "../api/attributes";
|
|
6
6
|
export * from "../api/events";
|
|
7
|
+
export * from "../api/log-level";
|
|
7
8
|
export { terminateSession } from "../api/session";
|
|
8
9
|
export { reportError } from "../api/report-error";
|
|
9
10
|
export function init(opts) {
|
|
@@ -6,6 +6,7 @@ import { init as initApi } from "../api/init";
|
|
|
6
6
|
import { terminateSession } from "../api/session";
|
|
7
7
|
import { addSignalAttribute, removeSignalAttribute } from "../api/attributes";
|
|
8
8
|
import { sendEvent } from "../api/events";
|
|
9
|
+
import { setActiveLogLevel } from "../api/log-level";
|
|
9
10
|
/**
|
|
10
11
|
* All the APIs exposed through the script tag via `dash0('{{api name}}')`
|
|
11
12
|
*/
|
|
@@ -17,6 +18,7 @@ const scriptApis = {
|
|
|
17
18
|
reportError,
|
|
18
19
|
addSignalAttribute,
|
|
19
20
|
removeSignalAttribute,
|
|
21
|
+
setActiveLogLevel,
|
|
20
22
|
sendEvent,
|
|
21
23
|
};
|
|
22
24
|
init();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { debug, observeResourcePerformance, win } from "../../utils";
|
|
2
2
|
import { isUrlIgnored, matchesAny } from "../../utils/ignore-rules";
|
|
3
3
|
import { addAttribute, setSpanStatus, addTraceContextHttpHeaders, endSpan, errorToSpanStatus, recordException, startSpan, } from "../../utils/otel";
|
|
4
|
-
import { HTTP_REQUEST_METHOD, HTTP_REQUEST_METHOD_ORIGINAL, HTTP_RESPONSE_STATUS_CODE, SPAN_STATUS_ERROR, SPAN_STATUS_UNSET, } from "../../semantic-conventions";
|
|
4
|
+
import { ERROR_TYPE, HTTP_REQUEST_METHOD, HTTP_REQUEST_METHOD_ORIGINAL, HTTP_RESPONSE_STATUS_CODE, SPAN_STATUS_ERROR, SPAN_STATUS_UNSET, } from "../../semantic-conventions";
|
|
5
5
|
import { isSameOrigin, wrap, parseUrl } from "../../utils";
|
|
6
6
|
import { vars } from "../../vars";
|
|
7
7
|
import { httpRequestHeaderKey, httpResponseHeaderKey } from "../../utils/otel/http";
|
|
@@ -138,7 +138,10 @@ function tryCaptureHttpHeaders(headers, span, getAttributeKey) {
|
|
|
138
138
|
}
|
|
139
139
|
function addResponseData(span, response) {
|
|
140
140
|
const status = response.status;
|
|
141
|
-
setSpanStatus(span, status >= 200 && status < 400 ? SPAN_STATUS_UNSET : SPAN_STATUS_ERROR
|
|
141
|
+
setSpanStatus(span, status >= 200 && status < 400 ? SPAN_STATUS_UNSET : SPAN_STATUS_ERROR);
|
|
142
|
+
if (status === 0) {
|
|
143
|
+
addAttribute(span.attributes, ERROR_TYPE, response.type);
|
|
144
|
+
}
|
|
142
145
|
addAttribute(span.attributes, HTTP_RESPONSE_STATUS_CODE, String(status));
|
|
143
146
|
tryCaptureHttpHeaders(response.headers, span, (k) => httpResponseHeaderKey(k));
|
|
144
147
|
}
|
|
@@ -27,6 +27,8 @@ export const USER_ROLES = "user.roles";
|
|
|
27
27
|
export const EXCEPTION_MESSAGE = "exception.message";
|
|
28
28
|
export const EXCEPTION_TYPE = "exception.type";
|
|
29
29
|
export const EXCEPTION_STACKTRACE = "exception.stacktrace";
|
|
30
|
+
// Error Attribute Keys
|
|
31
|
+
export const ERROR_TYPE = "error.type";
|
|
30
32
|
// URL Attribute Keys
|
|
31
33
|
export const URL_DOMAIN = "url.domain";
|
|
32
34
|
export const URL_FRAGMENT = "url.fragment";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { vars } from "../vars";
|
|
2
|
-
import { noop, warn, fetch } from "../utils";
|
|
2
|
+
import { noop, warn, fetch, debug } from "../utils";
|
|
3
3
|
const BEACON_BODY_SIZE_LIMIT = 60000;
|
|
4
4
|
export async function send(path, body) {
|
|
5
|
+
debug("Transmitting telemetry to endpoints", body);
|
|
5
6
|
const jsonString = JSON.stringify(body);
|
|
6
7
|
let requestBody = jsonString;
|
|
7
8
|
let byteLength = jsonString.length;
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import { noop } from "./fn";
|
|
2
|
-
|
|
2
|
+
const logLevels = {
|
|
3
|
+
debug: 0,
|
|
4
|
+
info: 1,
|
|
5
|
+
warn: 2,
|
|
6
|
+
error: 3,
|
|
7
|
+
};
|
|
8
|
+
let activeLogLevel = logLevels.warn;
|
|
9
|
+
/**
|
|
10
|
+
* Changes the logging verbosity of Dash0's web SDK. By default, only warnings and errors are logged.
|
|
11
|
+
*/
|
|
12
|
+
export function setActiveLogLevel(level) {
|
|
13
|
+
activeLogLevel = logLevels[level] ?? logLevels.warn;
|
|
14
|
+
}
|
|
3
15
|
export const info = createLogger("info");
|
|
4
16
|
export const warn = createLogger("warn");
|
|
5
17
|
export const error = createLogger("error");
|
|
6
18
|
export const debug = createLogger("debug");
|
|
7
|
-
function createLogger(
|
|
8
|
-
if (typeof console
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
if (console[method] && typeof console[method].apply === "function") {
|
|
19
|
+
function createLogger(logLevel) {
|
|
20
|
+
if (typeof console !== "undefined" && console[logLevel] && typeof console[logLevel].apply === "function") {
|
|
21
|
+
const numericLogLevel = logLevels[logLevel];
|
|
12
22
|
return function () {
|
|
13
|
-
|
|
23
|
+
if (numericLogLevel >= activeLogLevel) {
|
|
24
|
+
console[logLevel].apply(console, arguments);
|
|
25
|
+
}
|
|
14
26
|
};
|
|
15
27
|
}
|
|
16
|
-
return
|
|
17
|
-
console.log.apply(console, arguments);
|
|
18
|
-
};
|
|
28
|
+
return noop;
|
|
19
29
|
}
|
|
@@ -5,6 +5,7 @@ import { setTimeout } from "./timers";
|
|
|
5
5
|
import { addEventListener, removeEventListener } from "./listeners";
|
|
6
6
|
const TEN_MINUTES_IN_MILLIS = 1000 * 60 * 10;
|
|
7
7
|
const ONE_DAY_IN_MILLIS = 1000 * 60 * 60 * 24;
|
|
8
|
+
const OBSERVER_WAIT_TIME_MS = 300;
|
|
8
9
|
export const isResourceTimingAvailable = !!(perf && perf.getEntriesByType);
|
|
9
10
|
export const isPerformanceObserverAvailable = perf && typeof win["PerformanceObserver"] === "function" && typeof perf["now"] === "function";
|
|
10
11
|
export const PerformanceTimingNames = Object.freeze({
|
|
@@ -32,13 +33,14 @@ export const PerformanceTimingNames = Object.freeze({
|
|
|
32
33
|
UNLOAD_EVENT_END: "unloadEventEnd",
|
|
33
34
|
UNLOAD_EVENT_START: "unloadEventStart",
|
|
34
35
|
});
|
|
36
|
+
const usedResources = new WeakSet();
|
|
35
37
|
export function observeResourcePerformance(opts) {
|
|
36
38
|
if (!isPerformanceObserverAvailable)
|
|
37
39
|
return observeWithoutPerformanceObserverSupport(opts.onEnd);
|
|
38
40
|
// Used to calculate the duration when no resource was found.
|
|
39
41
|
let startTime;
|
|
40
42
|
let endTime;
|
|
41
|
-
|
|
43
|
+
const resources = [];
|
|
42
44
|
// Global resources that will need to be disposed
|
|
43
45
|
let observer;
|
|
44
46
|
let fallbackNoResourceFoundTimerHandle;
|
|
@@ -70,40 +72,36 @@ export function observeResourcePerformance(opts) {
|
|
|
70
72
|
function onEnd() {
|
|
71
73
|
endTime = perf.now();
|
|
72
74
|
cancelFallbackEndNeverCalledTimer();
|
|
73
|
-
if (
|
|
74
|
-
end();
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
addEventListener(doc, "visibilitychange", onVisibilityChanged);
|
|
78
|
-
fallbackNoResourceFoundTimerHandle = setTimeout(end, opts.maxWaitForResourceMillis);
|
|
75
|
+
if (!isWaitingAcceptable()) {
|
|
76
|
+
return end();
|
|
79
77
|
}
|
|
78
|
+
setTimeout(() => end(), Math.min(OBSERVER_WAIT_TIME_MS, opts.maxWaitForResourceMillis));
|
|
79
|
+
addEventListener(doc, "visibilitychange", onVisibilityChanged);
|
|
80
|
+
fallbackNoResourceFoundTimerHandle = setTimeout(end, opts.maxWaitForResourceMillis);
|
|
80
81
|
}
|
|
81
82
|
function end() {
|
|
82
83
|
disposeGlobalResources();
|
|
84
|
+
const resource = findBestMatchingResource();
|
|
83
85
|
// In some old web browsers, e.g. Chrome 31, the value provided as the duration
|
|
84
86
|
// can be very wrong. We have seen cases where this value is measured in years.
|
|
85
87
|
// If this does seem be the case, then we will ignore the duration property and
|
|
86
88
|
// instead prefer our approximation.
|
|
87
89
|
if (resource?.duration && resource.duration < ONE_DAY_IN_MILLIS) {
|
|
88
|
-
opts.onEnd({ resource, duration:
|
|
90
|
+
opts.onEnd({ resource, duration: resource.duration });
|
|
89
91
|
}
|
|
90
92
|
else {
|
|
91
|
-
opts.onEnd({ resource, duration:
|
|
93
|
+
opts.onEnd({ resource, duration: endTime - startTime });
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
function onResourceFound(list) {
|
|
95
|
-
|
|
97
|
+
list
|
|
98
|
+
.getEntriesByType("resource")
|
|
99
|
+
.filter((e) => {
|
|
96
100
|
// This polymorphism is not properly represented in the api types. The cast is safe since we're only accessing the resource timings.
|
|
97
101
|
const entry = e;
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
});
|
|
102
|
-
if (!r)
|
|
103
|
-
return;
|
|
104
|
-
resource = r;
|
|
105
|
-
if (endTime)
|
|
106
|
-
end();
|
|
102
|
+
return entry.startTime >= startTime && opts.resourceMatcher(entry);
|
|
103
|
+
})
|
|
104
|
+
.forEach((entry) => resources.push(entry));
|
|
107
105
|
}
|
|
108
106
|
function onVisibilityChanged() {
|
|
109
107
|
if (!isWaitingAcceptable())
|
|
@@ -143,6 +141,32 @@ export function observeResourcePerformance(opts) {
|
|
|
143
141
|
return;
|
|
144
142
|
removeEventListener(doc, "visibilitychange", onVisibilityChanged);
|
|
145
143
|
}
|
|
144
|
+
function findBestMatchingResource() {
|
|
145
|
+
if (!resources.length)
|
|
146
|
+
return undefined;
|
|
147
|
+
let bestMatch;
|
|
148
|
+
const matchingResources = resources.filter((res) => res.responseEnd <= endTime + opts.maxToleranceForResourceTimingsMillis && !usedResources.has(res));
|
|
149
|
+
if (!matchingResources.length) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
if (matchingResources.length === 1) {
|
|
153
|
+
bestMatch = matchingResources[0];
|
|
154
|
+
}
|
|
155
|
+
let bestScore;
|
|
156
|
+
if (!bestMatch) {
|
|
157
|
+
for (const res of matchingResources) {
|
|
158
|
+
const score = Math.abs(endTime - startTime - res.duration) + Math.abs(res.responseEnd - endTime);
|
|
159
|
+
if (bestScore === undefined || score < bestScore) {
|
|
160
|
+
bestScore = score;
|
|
161
|
+
bestMatch = res;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (!bestMatch)
|
|
166
|
+
return;
|
|
167
|
+
usedResources.add(bestMatch);
|
|
168
|
+
return bestMatch;
|
|
169
|
+
}
|
|
146
170
|
}
|
|
147
171
|
// We may only wait for resource data to arrive as long as the document is visible or in the process
|
|
148
172
|
// of becoming visible. In all other cases we might lose data when waiting, e.g. when the document
|
package/dist/modules/vars.js
CHANGED
|
@@ -16,7 +16,7 @@ export const vars = {
|
|
|
16
16
|
wrapTimers: true,
|
|
17
17
|
propagateTraceHeadersCorsURLs: [],
|
|
18
18
|
maxWaitForResourceTimingsMillis: 10000,
|
|
19
|
-
maxToleranceForResourceTimingsMillis:
|
|
19
|
+
maxToleranceForResourceTimingsMillis: 50,
|
|
20
20
|
headersToCapture: [],
|
|
21
21
|
pageViewInstrumentation: {
|
|
22
22
|
trackVirtualPageViews: true,
|