@dash0/sdk-web 0.10.1 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/dash0.iife.js +1 -1
  2. package/dist/dash0.iife.js.map +1 -1
  3. package/dist/dash0.js +1 -1
  4. package/dist/dash0.js.map +1 -1
  5. package/dist/dash0.umd.cjs +1 -1
  6. package/dist/dash0.umd.cjs.map +1 -1
  7. package/dist/modules/api/events.js +2 -2
  8. package/dist/modules/api/session.js +9 -4
  9. package/dist/modules/semantic-conventions.js +1 -1
  10. package/dist/modules/utils/id.js +1 -1
  11. package/dist/modules/utils/id_test.js +1 -1
  12. package/dist/modules/utils/otel/span.js +4 -2
  13. package/dist/modules/utils/otel/trace-context.js +3 -1
  14. package/dist/modules/utils/session-id.js +18 -0
  15. package/dist/modules/utils/session-id_test.js +26 -0
  16. package/dist/modules/utils/trace-id.js +18 -0
  17. package/dist/modules/utils/trace-id_test.js +32 -0
  18. package/dist/tsconfig.tsbuildinfo +1 -1
  19. package/dist/types/api/events.d.ts +1 -1
  20. package/dist/types/api/session.d.ts +3 -0
  21. package/dist/types/semantic-conventions.d.ts +1 -1
  22. package/dist/types/utils/id.d.ts +1 -1
  23. package/dist/types/utils/session-id.d.ts +1 -0
  24. package/dist/types/utils/session-id_test.d.ts +1 -0
  25. package/dist/types/utils/trace-id.d.ts +1 -0
  26. package/dist/types/utils/trace-id_test.d.ts +1 -0
  27. package/package.json +1 -1
  28. package/src/api/events.ts +3 -3
  29. package/src/api/session.ts +10 -5
  30. package/src/semantic-conventions.ts +1 -1
  31. package/src/utils/id.ts +1 -1
  32. package/src/utils/id_test.ts +1 -1
  33. package/src/utils/otel/span.ts +4 -2
  34. package/src/utils/otel/trace-context.ts +3 -1
  35. package/src/utils/session-id.ts +27 -0
  36. package/src/utils/session-id_test.ts +33 -0
  37. package/src/utils/trace-id.ts +27 -0
  38. package/src/utils/trace-id_test.ts +42 -0
@@ -1,13 +1,15 @@
1
1
  import { KeyValue, Span, SpanStatus } from "../../../types/otlp";
2
2
  import { nowNanos } from "../time";
3
- import { generateUniqueId, SPAN_ID_BYTES, TRACE_ID_BYTES } from "../id";
3
+ import { generateUniqueId, SPAN_ID_BYTES } from "../id";
4
4
  import { SPAN_KIND_CLIENT, SPAN_STATUS_UNSET } from "../../semantic-conventions";
5
+ import { sessionId } from "../../api/session";
6
+ import { generateTraceId } from "../trace-id";
5
7
 
6
8
  export type InProgressSpan = Omit<Span, "endTimeUnixNano">;
7
9
 
8
10
  export function startSpan(name: string): InProgressSpan {
9
11
  return {
10
- traceId: generateUniqueId(TRACE_ID_BYTES),
12
+ traceId: generateTraceId(sessionId),
11
13
  spanId: generateUniqueId(SPAN_ID_BYTES),
12
14
  name,
13
15
  // Always CLIENT for now https://github.com/open-telemetry/opentelemetry-proto/blob/ac3242b03157295e4ee9e616af53b81517b06559/opentelemetry/proto/trace/v1/trace.proto#L143-L169
@@ -75,10 +75,12 @@ export function addTraceContextHttpHeaders(
75
75
  * Random Trace ID: 00000010 - IF set the component guarantees that the seven right most bytes of the trace-id
76
76
  * are randomly generated. Downstream processors are then able to rely on this for technical things like shard keys.
77
77
  *
78
+ * NOTE: For now we just send the "sampled" flag because not all components support the random trace ID flag.
79
+ *
78
80
  * References:
79
81
  * https://www.w3.org/TR/trace-context-2/#traceparent-header
80
82
  * https://www.w3.org/TR/trace-context-2/#trace-flags
81
83
  * https://www.w3.org/TR/trace-context-2/#random-trace-id-flag
82
84
  */
83
- fn.call(ctx, "traceparent", `00-${span.traceId}-${span.spanId}-03`);
85
+ fn.call(ctx, "traceparent", `00-${span.traceId}-${span.spanId}-01`);
84
86
  }
@@ -0,0 +1,27 @@
1
+ import * as localStorage from "./local-storage";
2
+ import { generateUniqueId, SESSION_ID_BYTES } from "./id";
3
+
4
+ type SessionFlags = {
5
+ ephemeralSession: boolean;
6
+ };
7
+
8
+ const SESSION_FLAGS = {
9
+ EPHEMERAL_SESSION: 0x01, // 00000001 - if the browser does NOT support local storage we count the session as ephemeral because we cannot persist it
10
+ } as const;
11
+
12
+ function encodeSessionFlags(flags: SessionFlags): string {
13
+ let byte = 0;
14
+ if (flags.ephemeralSession) {
15
+ byte |= SESSION_FLAGS.EPHEMERAL_SESSION;
16
+ }
17
+
18
+ return byte.toString(16).padStart(2, "0");
19
+ }
20
+
21
+ export function generateSessionId(): string {
22
+ const sessionFlags = {
23
+ ephemeralSession: !localStorage.isSupported,
24
+ };
25
+
26
+ return `${encodeSessionFlags(sessionFlags)}${generateUniqueId(SESSION_ID_BYTES - 1)}`;
27
+ }
@@ -0,0 +1,33 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { generateSessionId } from "./session-id";
3
+ import * as localStorage from "./local-storage";
4
+
5
+ describe("generateSessionId", () => {
6
+ it("returns a session ID of the expected length", () => {
7
+ const sessionId = generateSessionId();
8
+ expect(sessionId).toHaveLength(16);
9
+ });
10
+
11
+ it("returns a session ID with proper flags when storage is supported", () => {
12
+ vi.spyOn(localStorage, "isSupported", "get").mockReturnValue(true);
13
+
14
+ const sessionId = generateSessionId();
15
+ console.log(sessionId);
16
+ expect(sessionId.startsWith("00")).toBe(true);
17
+ });
18
+
19
+ it("returns a session ID with proper flags when storage is NOT supported", () => {
20
+ vi.spyOn(localStorage, "isSupported", "get").mockReturnValue(false);
21
+
22
+ const sessionId = generateSessionId();
23
+ console.log(sessionId);
24
+ expect(sessionId.startsWith("01")).toBe(true);
25
+ });
26
+
27
+ it("returns a unique session ID on each call", () => {
28
+ const sessionId1 = generateSessionId();
29
+ const sessionId2 = generateSessionId();
30
+
31
+ expect(sessionId1).not.toBe(sessionId2);
32
+ });
33
+ });
@@ -0,0 +1,27 @@
1
+ import { generateUniqueId, SESSION_ID_BYTES, TRACE_ID_BYTES } from "./id";
2
+
3
+ type TraceFlags = {
4
+ withoutSession: boolean;
5
+ };
6
+
7
+ const TRACE_ID_PREFIX = "d042";
8
+
9
+ const TRACE_FLAGS = {
10
+ WITHOUT_SESSION: 0x01, // 00000001 - in some edge cases we do not have a session ID, so we need to mark the trace as such
11
+ } as const;
12
+
13
+ function encodeTraceFlags(flags: TraceFlags): string {
14
+ let byte = 0;
15
+ if (flags.withoutSession) {
16
+ byte |= TRACE_FLAGS.WITHOUT_SESSION;
17
+ }
18
+
19
+ return byte.toString(16).padStart(2, "0");
20
+ }
21
+
22
+ export function generateTraceId(sessionId: string | null): string {
23
+ if (!sessionId) {
24
+ return `${TRACE_ID_PREFIX}${encodeTraceFlags({ withoutSession: true })}${generateUniqueId(TRACE_ID_BYTES - 3)}`;
25
+ }
26
+ return `${TRACE_ID_PREFIX}${encodeTraceFlags({ withoutSession: false })}${sessionId}${generateUniqueId(TRACE_ID_BYTES - SESSION_ID_BYTES - 3)}`;
27
+ }
@@ -0,0 +1,42 @@
1
+ import { expect, describe, it } from "vitest";
2
+ import { generateTraceId } from "./trace-id";
3
+
4
+ describe("generateTraceId", () => {
5
+ it("returns a trace ID of the expected length", () => {
6
+ const traceId = generateTraceId(null);
7
+
8
+ expect(traceId).toHaveLength(32);
9
+ });
10
+
11
+ it("returns a trace ID with correct prefix when a session id is set", () => {
12
+ const traceId = generateTraceId("abcdef1234567890");
13
+
14
+ expect(traceId.substring(0, 6)).toEqual("d04200");
15
+ });
16
+
17
+ it("returns a trace ID with correct prefix when NOT session is set", () => {
18
+ const traceId = generateTraceId(null);
19
+
20
+ expect(traceId.substring(0, 6)).toEqual("d04201");
21
+ });
22
+
23
+ it("returns a unique trace ID on each call", () => {
24
+ const sessiondId = "abcdef1234567890";
25
+ const traceId1 = generateTraceId("abcdef1234567890");
26
+ const traceId2 = generateTraceId("abcdef1234567890");
27
+
28
+ expect(traceId1).not.toBe(traceId2);
29
+ expect(traceId1.substring(6, 22)).toBe(sessiondId);
30
+ expect(traceId2.substring(6, 22)).toBe(sessiondId);
31
+ });
32
+
33
+ it("returns a unique trace ID when session id is not set", () => {
34
+ const traceId1 = generateTraceId(null);
35
+ const sessionId1 = traceId1.substring(6, 22);
36
+ const traceId2 = generateTraceId(null);
37
+ const sessionId2 = traceId2.substring(6, 22);
38
+
39
+ expect(traceId1).not.toBe(traceId2);
40
+ expect(sessionId1).not.toBe(sessionId2);
41
+ });
42
+ });