@obsrviq/tracker 0.6.0 → 0.7.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/dist/index.js +81 -0
- package/dist/index.js.map +1 -1
- package/dist/obsrviq.global.js +41 -41
- package/dist/obsrviq.global.js.map +1 -1
- package/package.json +2 -2
- package/src/context.ts +4 -0
- package/src/index.ts +2 -0
- package/src/network.ts +32 -0
- package/src/trace.ts +100 -0
package/dist/index.js
CHANGED
|
@@ -792,6 +792,63 @@ function tokenBucket(rate2, burst) {
|
|
|
792
792
|
};
|
|
793
793
|
}
|
|
794
794
|
|
|
795
|
+
// src/trace.ts
|
|
796
|
+
function randomHex(bytes) {
|
|
797
|
+
const arr = new Uint8Array(bytes);
|
|
798
|
+
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
799
|
+
crypto.getRandomValues(arr);
|
|
800
|
+
} else {
|
|
801
|
+
for (let i = 0; i < bytes; i++) arr[i] = Math.random() * 256 | 0;
|
|
802
|
+
}
|
|
803
|
+
let s = "";
|
|
804
|
+
for (let i = 0; i < bytes; i++) s += arr[i].toString(16).padStart(2, "0");
|
|
805
|
+
return s;
|
|
806
|
+
}
|
|
807
|
+
function newTrace() {
|
|
808
|
+
const traceId = randomHex(16);
|
|
809
|
+
const spanId = randomHex(8);
|
|
810
|
+
return { traceId, spanId, header: `00-${traceId}-${spanId}-01` };
|
|
811
|
+
}
|
|
812
|
+
function traceTarget(rawUrl, cfg) {
|
|
813
|
+
if (!cfg.tracePropagation) return false;
|
|
814
|
+
let u;
|
|
815
|
+
try {
|
|
816
|
+
u = new URL(rawUrl, typeof location !== "undefined" ? location.href : void 0);
|
|
817
|
+
} catch {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") return false;
|
|
821
|
+
if (typeof location !== "undefined" && u.origin === location.origin) return true;
|
|
822
|
+
return hostAllowed(u.hostname, cfg.traceHosts);
|
|
823
|
+
}
|
|
824
|
+
function hostAllowed(hostname, hosts) {
|
|
825
|
+
const h = hostname.toLowerCase();
|
|
826
|
+
for (const raw of hosts) {
|
|
827
|
+
let entry = String(raw).trim().toLowerCase();
|
|
828
|
+
if (!entry) continue;
|
|
829
|
+
if (entry.includes("://")) {
|
|
830
|
+
try {
|
|
831
|
+
entry = new URL(entry).hostname;
|
|
832
|
+
} catch {
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
entry = entry.replace(/^\*?\./, "");
|
|
836
|
+
if (h === entry || h.endsWith("." + entry)) return true;
|
|
837
|
+
}
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
function injectFetchTrace(input, init, header) {
|
|
841
|
+
const hasInitHeaders = !!init && "headers" in init && init.headers != null;
|
|
842
|
+
if (input instanceof Request && !hasInitHeaders) {
|
|
843
|
+
const h2 = new Headers(input.headers);
|
|
844
|
+
if (!h2.has("traceparent")) h2.set("traceparent", header);
|
|
845
|
+
return { input: new Request(input, { headers: h2 }), init };
|
|
846
|
+
}
|
|
847
|
+
const h = new Headers(init?.headers ?? void 0);
|
|
848
|
+
if (!h.has("traceparent")) h.set("traceparent", header);
|
|
849
|
+
return { input, init: { ...init || {}, headers: h } };
|
|
850
|
+
}
|
|
851
|
+
|
|
795
852
|
// src/network.ts
|
|
796
853
|
var BODY_CAP = 4 * 1024;
|
|
797
854
|
var NET_RATE = 50;
|
|
@@ -807,6 +864,7 @@ var HEADER_ALLOW = /* @__PURE__ */ new Set([
|
|
|
807
864
|
"content-encoding",
|
|
808
865
|
"x-request-id",
|
|
809
866
|
"x-correlation-id",
|
|
867
|
+
"traceparent",
|
|
810
868
|
"server",
|
|
811
869
|
"vary"
|
|
812
870
|
]);
|
|
@@ -1041,6 +1099,17 @@ function wrapFetch(ctx, tr, emitNet) {
|
|
|
1041
1099
|
const perfStart = perfNow();
|
|
1042
1100
|
const method = (init?.method || (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
1043
1101
|
const url = redactUrl(rawUrl);
|
|
1102
|
+
let traceId;
|
|
1103
|
+
if (traceTarget(rawUrl, ctx.config)) {
|
|
1104
|
+
try {
|
|
1105
|
+
const tr2 = newTrace();
|
|
1106
|
+
const inj = injectFetchTrace(input, init, tr2.header);
|
|
1107
|
+
input = inj.input;
|
|
1108
|
+
init = inj.init;
|
|
1109
|
+
traceId = tr2.traceId;
|
|
1110
|
+
} catch {
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1044
1113
|
const reqHeaders = pickHeaders(
|
|
1045
1114
|
ctx.config.redactHeaders,
|
|
1046
1115
|
headerEntries(init?.headers ?? (input instanceof Request ? input.headers : void 0))
|
|
@@ -1063,6 +1132,7 @@ function wrapFetch(ctx, tr, emitNet) {
|
|
|
1063
1132
|
ok: false,
|
|
1064
1133
|
resourceType: "fetch",
|
|
1065
1134
|
requestHeaders: reqHeaders,
|
|
1135
|
+
traceId,
|
|
1066
1136
|
timing,
|
|
1067
1137
|
...partial
|
|
1068
1138
|
};
|
|
@@ -1144,6 +1214,14 @@ function wrapXhr(ctx, tr, emitNet) {
|
|
|
1144
1214
|
meta.startT = ctx.clock.now();
|
|
1145
1215
|
meta.perfStart = perfNow();
|
|
1146
1216
|
if (ctx.config.captureNetworkBodies) meta.body = stringifyBody(body);
|
|
1217
|
+
if (traceTarget(meta.rawUrl, ctx.config)) {
|
|
1218
|
+
try {
|
|
1219
|
+
const tr2 = newTrace();
|
|
1220
|
+
this.setRequestHeader("traceparent", tr2.header);
|
|
1221
|
+
meta.traceId = tr2.traceId;
|
|
1222
|
+
} catch {
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1147
1225
|
const finish = (error) => {
|
|
1148
1226
|
const endT = ctx.clock.now();
|
|
1149
1227
|
const base = {
|
|
@@ -1178,6 +1256,7 @@ function wrapXhr(ctx, tr, emitNet) {
|
|
|
1178
1256
|
ok: status >= 200 && status < 400,
|
|
1179
1257
|
resourceType: "xhr",
|
|
1180
1258
|
requestHeaders: meta.reqHeaders,
|
|
1259
|
+
traceId: meta.traceId,
|
|
1181
1260
|
responseHeaders: respHeaders,
|
|
1182
1261
|
responseSize,
|
|
1183
1262
|
requestBody: ctx.config.captureNetworkBodies ? bodyPreview(meta.body, void 0) : void 0,
|
|
@@ -2179,6 +2258,8 @@ var DEFAULTS = {
|
|
|
2179
2258
|
noPrivacy: false,
|
|
2180
2259
|
captureNetworkBodies: false,
|
|
2181
2260
|
redactHeaders: ["authorization", "cookie", "set-cookie"],
|
|
2261
|
+
tracePropagation: false,
|
|
2262
|
+
traceHosts: [],
|
|
2182
2263
|
sampleRate: 1,
|
|
2183
2264
|
recordCanvas: false,
|
|
2184
2265
|
endpoint: "https://in.lumera.app",
|