@squide/firefly 12.0.4 → 13.0.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 (33) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/honeycomb/activeSpan.d.ts +12 -0
  3. package/dist/honeycomb/activeSpan.js +105 -0
  4. package/dist/honeycomb/activeSpan.js.map +1 -0
  5. package/dist/honeycomb/canRegisterHoneycombInstrumentation.d.ts +1 -0
  6. package/dist/honeycomb/canRegisterHoneycombInstrumentation.js +11 -0
  7. package/dist/honeycomb/canRegisterHoneycombInstrumentation.js.map +1 -0
  8. package/dist/honeycomb/createTraceContextId.d.ts +1 -0
  9. package/dist/honeycomb/createTraceContextId.js +16 -0
  10. package/dist/honeycomb/createTraceContextId.js.map +1 -0
  11. package/dist/honeycomb/initializeHoneycomb.d.ts +2 -0
  12. package/dist/honeycomb/initializeHoneycomb.js +25 -0
  13. package/dist/honeycomb/initializeHoneycomb.js.map +1 -0
  14. package/dist/honeycomb/registerHoneycombInstrumentation.d.ts +3 -0
  15. package/dist/honeycomb/registerHoneycombInstrumentation.js +405 -0
  16. package/dist/honeycomb/registerHoneycombInstrumentation.js.map +1 -0
  17. package/dist/honeycomb/tracer.d.ts +1 -0
  18. package/dist/honeycomb/tracer.js +14 -0
  19. package/dist/honeycomb/tracer.js.map +1 -0
  20. package/dist/honeycomb/utils.d.ts +23 -0
  21. package/dist/honeycomb/utils.js +49 -0
  22. package/dist/honeycomb/utils.js.map +1 -0
  23. package/dist/initializeFirefly.js +12 -2
  24. package/dist/initializeFirefly.js.map +1 -1
  25. package/package.json +3 -1
  26. package/src/honeycomb/activeSpan.ts +131 -0
  27. package/src/honeycomb/canRegisterHoneycombInstrumentation.ts +5 -0
  28. package/src/honeycomb/createTraceContextId.ts +12 -0
  29. package/src/honeycomb/initializeHoneycomb.ts +22 -0
  30. package/src/honeycomb/registerHoneycombInstrumentation.ts +470 -0
  31. package/src/honeycomb/tracer.ts +6 -0
  32. package/src/honeycomb/utils.ts +64 -0
  33. package/src/initializeFirefly.ts +12 -2
@@ -0,0 +1,470 @@
1
+ import type { Span } from "@opentelemetry/api";
2
+ import {
3
+ LocalModuleDeferredRegistrationFailedEvent,
4
+ LocalModuleDeferredRegistrationUpdateFailedEvent,
5
+ LocalModuleRegistrationFailedEvent,
6
+ LocalModulesDeferredRegistrationCompletedEvent,
7
+ type LocalModulesDeferredRegistrationCompletedEventPayload,
8
+ LocalModulesDeferredRegistrationStartedEvent,
9
+ type LocalModulesDeferredRegistrationStartedEventPayload,
10
+ LocalModulesDeferredRegistrationsUpdateCompletedEvent,
11
+ type LocalModulesDeferredRegistrationsUpdateCompletedEventPayload,
12
+ LocalModulesDeferredRegistrationsUpdateStartedEvent,
13
+ type LocalModulesDeferredRegistrationsUpdateStartedEventPayload,
14
+ LocalModulesRegistrationCompletedEvent,
15
+ type LocalModulesRegistrationCompletedEventPayload,
16
+ LocalModulesRegistrationStartedEvent,
17
+ type LocalModulesRegistrationStartedEventPayload,
18
+ type ModuleRegistrationError
19
+ } from "@squide/core";
20
+ import {
21
+ DeferredRegistrationsUpdateCompletedEvent,
22
+ DeferredRegistrationsUpdateStartedEvent,
23
+ RemoteModuleDeferredRegistrationFailedEvent,
24
+ RemoteModuleDeferredRegistrationUpdateFailedEvent,
25
+ type RemoteModuleRegistrationError,
26
+ RemoteModuleRegistrationFailedEvent,
27
+ RemoteModulesDeferredRegistrationCompletedEvent,
28
+ type RemoteModulesDeferredRegistrationCompletedEventPayload,
29
+ RemoteModulesDeferredRegistrationStartedEvent,
30
+ type RemoteModulesDeferredRegistrationStartedEventPayload,
31
+ RemoteModulesDeferredRegistrationsUpdateCompletedEvent,
32
+ type RemoteModulesDeferredRegistrationsUpdateCompletedEventPayload,
33
+ RemoteModulesDeferredRegistrationsUpdateStartedEvent,
34
+ type RemoteModulesDeferredRegistrationsUpdateStartedEventPayload,
35
+ RemoteModulesRegistrationCompletedEvent,
36
+ type RemoteModulesRegistrationCompletedEventPayload,
37
+ RemoteModulesRegistrationStartedEvent,
38
+ type RemoteModulesRegistrationStartedEventPayload
39
+ } from "@squide/module-federation";
40
+ import { ApplicationBoostrappedEvent, ModulesReadyEvent, ModulesRegisteredEvent, MswReadyEvent, ProtectedDataReadyEvent, PublicDataReadyEvent } from "../AppRouterReducer.ts";
41
+ import type { FireflyRuntime } from "../FireflyRuntime.tsx";
42
+ import { ApplicationBootstrappingStartedEvent } from "../initializeFirefly.ts";
43
+ import { ProtectedDataFetchStartedEvent } from "../useProtectedDataQueries.ts";
44
+ import { PublicDataFetchStartedEvent } from "../usePublicDataQueries.ts";
45
+ import { type ActiveSpan, createOverrideFetchRequestSpanWithActiveSpanContext, registerActiveSpanStack } from "./activeSpan.ts";
46
+ import { getTracer } from "./tracer.ts";
47
+ import { endActiveSpan, startActiveChildSpan, startChildSpan, startSpan, traceError } from "./utils.ts";
48
+
49
+ // TIPS:
50
+ // To query those traces in Honeycomb, use the following query filter: "root.name = squide-bootstrapping".
51
+
52
+ type DataFetchState = "none" | "fetching-data" | "public-data-ready" | "protected-data-ready" | "data-ready";
53
+
54
+ export function reduceDataFetchEvents(
55
+ runtime: FireflyRuntime,
56
+ onDataFetchingStarted: () => void,
57
+ onDataReady: () => void,
58
+ onPublicDataFetchStarted: () => void,
59
+ onPublicDataReady: () => void,
60
+ onProtectedDataFetchStarted: () => void,
61
+ onProtectedDataReady: () => void
62
+ ) {
63
+ let dataFetchState: DataFetchState = "none";
64
+
65
+ // TODO: Validate if this handler should use { once: true }.
66
+ runtime.eventBus.addListener(PublicDataFetchStartedEvent, () => {
67
+ if (dataFetchState === "none") {
68
+ dataFetchState = "fetching-data";
69
+ onDataFetchingStarted();
70
+ }
71
+
72
+ onPublicDataFetchStarted();
73
+ });
74
+
75
+ // TODO: Validate if this handler should use { once: true }.
76
+ runtime.eventBus.addListener(PublicDataReadyEvent, () => {
77
+ onPublicDataReady();
78
+
79
+ if (dataFetchState === "fetching-data") {
80
+ dataFetchState = "public-data-ready";
81
+ } else if (dataFetchState === "protected-data-ready") {
82
+ dataFetchState = "data-ready";
83
+ onDataReady();
84
+ }
85
+ });
86
+
87
+ // TODO: Validate if this handler should use { once: true }.
88
+ runtime.eventBus.addListener(ProtectedDataFetchStartedEvent, () => {
89
+ if (dataFetchState === "none") {
90
+ dataFetchState = "fetching-data";
91
+ onDataFetchingStarted();
92
+ }
93
+
94
+ onProtectedDataFetchStarted();
95
+ });
96
+
97
+ // TODO: Validate if this handler should use { once: true }.
98
+ runtime.eventBus.addListener(ProtectedDataReadyEvent, () => {
99
+ onProtectedDataReady();
100
+
101
+ if (dataFetchState === "fetching-data") {
102
+ dataFetchState = "protected-data-ready";
103
+ } else if (dataFetchState === "public-data-ready") {
104
+ dataFetchState = "data-ready";
105
+ onDataReady();
106
+ }
107
+ });
108
+ }
109
+
110
+ function registerTrackingListeners(runtime: FireflyRuntime) {
111
+ let bootstrappingSpan: Span;
112
+ let localModuleRegistrationSpan: Span;
113
+ let localModuleDeferredRegistrationSpan: Span;
114
+ let remoteModuleRegistrationSpan: Span;
115
+ let remoteModuleDeferredRegistrationSpan: Span;
116
+ let dataFetchSpan: ActiveSpan;
117
+ let deferredRegistrationsUpdateSpan: Span;
118
+ let localModuleDeferredRegistrationsUpdateSpan: ActiveSpan;
119
+ let remoteModuleDeferredRegistrationsUpdateSpan: ActiveSpan;
120
+
121
+ runtime.eventBus.addListener(ApplicationBootstrappingStartedEvent, () => {
122
+ bootstrappingSpan = startSpan((options, context) => getTracer().startSpan("squide-bootstrapping", options, context));
123
+ }, { once: true });
124
+
125
+ runtime.eventBus.addListener(ApplicationBoostrappedEvent, () => {
126
+ if (bootstrappingSpan) {
127
+ bootstrappingSpan.end();
128
+ }
129
+ }, { once: true });
130
+
131
+ runtime.eventBus.addListener(MswReadyEvent, () => {
132
+ if (bootstrappingSpan) {
133
+ bootstrappingSpan.addEvent("msw-ready");
134
+ }
135
+ }, { once: true });
136
+
137
+ runtime.eventBus.addListener(LocalModulesRegistrationStartedEvent, (payload: unknown) => {
138
+ const attributes = {
139
+ "app.squide.module_count": (payload as LocalModulesRegistrationStartedEventPayload).moduleCount
140
+ };
141
+
142
+ if (bootstrappingSpan) {
143
+ bootstrappingSpan.addEvent("local-module-registration-started", attributes);
144
+ }
145
+
146
+ localModuleRegistrationSpan = startChildSpan(bootstrappingSpan, (options, context) => {
147
+ return getTracer().startSpan("local-module-registration", { ...options, attributes }, context);
148
+ });
149
+ }, { once: true });
150
+
151
+ runtime.eventBus.addListener(LocalModulesRegistrationCompletedEvent, (payload: unknown) => {
152
+ if (bootstrappingSpan) {
153
+ bootstrappingSpan.addEvent("local-module-registration-completed", {
154
+ "app.squide.module_count": (payload as LocalModulesRegistrationCompletedEventPayload).moduleCount
155
+ });
156
+ }
157
+
158
+ if (localModuleRegistrationSpan) {
159
+ localModuleRegistrationSpan.end();
160
+ }
161
+ }, { once: true });
162
+
163
+ // Can occur multiple times.
164
+ runtime.eventBus.addListener(LocalModuleRegistrationFailedEvent, (payload: unknown) => {
165
+ const registrationError = payload as ModuleRegistrationError;
166
+
167
+ if (localModuleRegistrationSpan) {
168
+ traceError(localModuleRegistrationSpan, registrationError);
169
+ }
170
+ });
171
+
172
+ runtime.eventBus.addListener(LocalModulesDeferredRegistrationStartedEvent, (payload: unknown) => {
173
+ const attributes = {
174
+ "app.squide.registration_count": (payload as LocalModulesDeferredRegistrationStartedEventPayload).registrationCount
175
+ };
176
+
177
+ if (bootstrappingSpan) {
178
+ bootstrappingSpan.addEvent("local-module-deferred-registration-started", attributes);
179
+ }
180
+
181
+ localModuleDeferredRegistrationSpan = startChildSpan(bootstrappingSpan, (options, context) => {
182
+ return getTracer().startSpan("local-module-deferred-registration", { ...options, attributes }, context);
183
+ });
184
+ }, { once: true });
185
+
186
+ runtime.eventBus.addListener(LocalModulesDeferredRegistrationCompletedEvent, (payload: unknown) => {
187
+ if (bootstrappingSpan) {
188
+ bootstrappingSpan.addEvent("local-module-deferred-registration-completed", {
189
+ "app.squide.registration_count": (payload as LocalModulesDeferredRegistrationCompletedEventPayload).registrationCount
190
+ });
191
+ }
192
+
193
+ if (localModuleDeferredRegistrationSpan) {
194
+ localModuleDeferredRegistrationSpan.end();
195
+ }
196
+ }, { once: true });
197
+
198
+ // Can occur multiple times.
199
+ runtime.eventBus.addListener(LocalModuleDeferredRegistrationFailedEvent, (payload: unknown) => {
200
+ const registrationError = payload as ModuleRegistrationError;
201
+
202
+ if (localModuleDeferredRegistrationSpan) {
203
+ traceError(localModuleRegistrationSpan, registrationError);
204
+ }
205
+ });
206
+
207
+ runtime.eventBus.addListener(RemoteModulesRegistrationStartedEvent, (payload: unknown) => {
208
+ const attributes = {
209
+ "app.squide.remote_count": (payload as RemoteModulesRegistrationStartedEventPayload).remoteCount
210
+ };
211
+
212
+ if (bootstrappingSpan) {
213
+ bootstrappingSpan.addEvent("remote-module-registration-started", attributes);
214
+ }
215
+
216
+ remoteModuleRegistrationSpan = startChildSpan(bootstrappingSpan, (options, context) => {
217
+ return getTracer().startSpan("remote-module-registration", { ...options, attributes }, context);
218
+ });
219
+ }, { once: true });
220
+
221
+ runtime.eventBus.addListener(RemoteModulesRegistrationCompletedEvent, (payload: unknown) => {
222
+ if (bootstrappingSpan) {
223
+ bootstrappingSpan.addEvent("remote-module-registration-completed", {
224
+ "app.squide.remote_count": (payload as RemoteModulesRegistrationCompletedEventPayload).remoteCount
225
+ });
226
+ }
227
+
228
+ if (remoteModuleRegistrationSpan) {
229
+ remoteModuleRegistrationSpan.end();
230
+ }
231
+ }, { once: true });
232
+
233
+ // Can occur multiple times.
234
+ runtime.eventBus.addListener(RemoteModuleRegistrationFailedEvent, (payload: unknown) => {
235
+ const registrationError = payload as RemoteModuleRegistrationError;
236
+
237
+ if (remoteModuleRegistrationSpan) {
238
+ traceError(remoteModuleRegistrationSpan, registrationError);
239
+ }
240
+ });
241
+
242
+ runtime.eventBus.addListener(RemoteModulesDeferredRegistrationStartedEvent, (payload: unknown) => {
243
+ const attributes = {
244
+ "app.squide.registration_count": (payload as RemoteModulesDeferredRegistrationStartedEventPayload).registrationCount
245
+ };
246
+
247
+ if (bootstrappingSpan) {
248
+ bootstrappingSpan.addEvent("remote-module-deferred-registration-started", attributes);
249
+ }
250
+
251
+ remoteModuleDeferredRegistrationSpan = startChildSpan(bootstrappingSpan, (options, context) => {
252
+ return getTracer().startSpan("remote-module-deferred-registration", { ...options, attributes }, context);
253
+ });
254
+ }, { once: true });
255
+
256
+ runtime.eventBus.addListener(RemoteModulesDeferredRegistrationCompletedEvent, (payload: unknown) => {
257
+ if (bootstrappingSpan) {
258
+ bootstrappingSpan.addEvent("remote-module-deferred-registration-completed", {
259
+ "app.squide.registration_count": (payload as RemoteModulesDeferredRegistrationCompletedEventPayload).registrationCount
260
+ });
261
+ }
262
+
263
+ if (remoteModuleDeferredRegistrationSpan) {
264
+ remoteModuleDeferredRegistrationSpan.end();
265
+ }
266
+ }, { once: true });
267
+
268
+ // Can occur multiple times.
269
+ runtime.eventBus.addListener(RemoteModuleDeferredRegistrationFailedEvent, (payload: unknown) => {
270
+ const registrationError = payload as RemoteModuleRegistrationError;
271
+
272
+ if (remoteModuleDeferredRegistrationSpan) {
273
+ traceError(remoteModuleDeferredRegistrationSpan, registrationError);
274
+ }
275
+ });
276
+
277
+ const handleFetchDataStarted = () => {
278
+ dataFetchSpan = startActiveChildSpan(bootstrappingSpan, (options, context) => {
279
+ const name = "data-fetch";
280
+ const span = getTracer().startSpan(name, options, context);
281
+
282
+ return {
283
+ name,
284
+ span
285
+ };
286
+ });
287
+ };
288
+
289
+ const handleDataReady = () => {
290
+ if (dataFetchSpan) {
291
+ endActiveSpan(dataFetchSpan);
292
+ }
293
+ };
294
+
295
+ const handlePublicDataFetchStarted = () => {
296
+ if (dataFetchSpan) {
297
+ dataFetchSpan.instance.addEvent("public-data-fetch-started");
298
+ }
299
+ };
300
+
301
+ const handlePublicDataReady = () => {
302
+ if (dataFetchSpan) {
303
+ dataFetchSpan.instance.addEvent("public-data-ready");
304
+ }
305
+ };
306
+
307
+ const handleProtectedDataFetchStarted = () => {
308
+ if (dataFetchSpan) {
309
+ dataFetchSpan.instance.addEvent("protected-data-fetch-started");
310
+ }
311
+ };
312
+
313
+ const handleProtectedDataReady = () => {
314
+ if (dataFetchSpan) {
315
+ dataFetchSpan.instance.addEvent("protected-data-ready");
316
+ }
317
+ };
318
+
319
+ reduceDataFetchEvents(
320
+ runtime,
321
+ handleFetchDataStarted,
322
+ handleDataReady,
323
+ handlePublicDataFetchStarted,
324
+ handlePublicDataReady,
325
+ handleProtectedDataFetchStarted,
326
+ handleProtectedDataReady
327
+ );
328
+
329
+ runtime.eventBus.addListener(ModulesRegisteredEvent, () => {
330
+ if (bootstrappingSpan) {
331
+ bootstrappingSpan.addEvent("modules-registered");
332
+ }
333
+ }, { once: true });
334
+
335
+ runtime.eventBus.addListener(ModulesReadyEvent, () => {
336
+ if (bootstrappingSpan) {
337
+ bootstrappingSpan.addEvent("modules-ready");
338
+ }
339
+ }, { once: true });
340
+
341
+ // Can occur multiple times.
342
+ runtime.eventBus.addListener(DeferredRegistrationsUpdateStartedEvent, () => {
343
+ deferredRegistrationsUpdateSpan = startSpan((options, context) => getTracer().startSpan("squide-deferred-registrations-update", options, context));
344
+ });
345
+
346
+ // Can occur multiple times.
347
+ runtime.eventBus.addListener(DeferredRegistrationsUpdateCompletedEvent, () => {
348
+ if (deferredRegistrationsUpdateSpan) {
349
+ deferredRegistrationsUpdateSpan.end();
350
+ }
351
+ });
352
+
353
+ // Can occur multiple times.
354
+ runtime.eventBus.addListener(LocalModulesDeferredRegistrationsUpdateStartedEvent, (payload: unknown) => {
355
+ const attributes = {
356
+ "app.squide.registration_count": (payload as LocalModulesDeferredRegistrationsUpdateStartedEventPayload).registrationCount
357
+ };
358
+
359
+ if (deferredRegistrationsUpdateSpan) {
360
+ deferredRegistrationsUpdateSpan.addEvent("local-module-deferred-registrations-update-started", attributes);
361
+ }
362
+
363
+ localModuleDeferredRegistrationsUpdateSpan = startActiveChildSpan(deferredRegistrationsUpdateSpan, (options, context) => {
364
+ const name = "local-module-deferred-registrations-update";
365
+
366
+ const span = getTracer().startSpan(name, {
367
+ attributes,
368
+ ...options
369
+ }, context);
370
+
371
+ return {
372
+ name,
373
+ span
374
+ };
375
+ });
376
+ });
377
+
378
+ // Can occur multiple times.
379
+ runtime.eventBus.addListener(LocalModulesDeferredRegistrationsUpdateCompletedEvent, (payload: unknown) => {
380
+ if (deferredRegistrationsUpdateSpan) {
381
+ deferredRegistrationsUpdateSpan.addEvent("local-module-deferred-registrations-update-completed", {
382
+ "app.squide.registration_count": (payload as LocalModulesDeferredRegistrationsUpdateCompletedEventPayload).registrationCount
383
+ });
384
+ }
385
+
386
+ if (localModuleDeferredRegistrationsUpdateSpan) {
387
+ endActiveSpan(localModuleDeferredRegistrationsUpdateSpan);
388
+ }
389
+ });
390
+
391
+ // Can occur multiple times.
392
+ runtime.eventBus.addListener(LocalModuleDeferredRegistrationUpdateFailedEvent, (payload: unknown) => {
393
+ const registrationError = payload as ModuleRegistrationError;
394
+
395
+ if (localModuleDeferredRegistrationsUpdateSpan) {
396
+ traceError(localModuleDeferredRegistrationsUpdateSpan.instance, registrationError);
397
+ }
398
+ });
399
+
400
+ // Can occur multiple times.
401
+ runtime.eventBus.addListener(RemoteModulesDeferredRegistrationsUpdateStartedEvent, (payload: unknown) => {
402
+ const attributes = {
403
+ "app.squide.registration_count": (payload as RemoteModulesDeferredRegistrationsUpdateStartedEventPayload).registrationCount
404
+ };
405
+
406
+ if (deferredRegistrationsUpdateSpan) {
407
+ deferredRegistrationsUpdateSpan.addEvent("remote-module-deferred-registrations-update-started", attributes);
408
+ }
409
+
410
+ remoteModuleDeferredRegistrationsUpdateSpan = startActiveChildSpan(deferredRegistrationsUpdateSpan, (options, context) => {
411
+ const name = "remote-module-deferred-registrations-update";
412
+
413
+ const span = getTracer().startSpan(name, {
414
+ attributes,
415
+ ...options
416
+ }, context);
417
+
418
+ return {
419
+ name,
420
+ span
421
+ };
422
+ });
423
+ });
424
+
425
+ // Can occur multiple times.
426
+ runtime.eventBus.addListener(RemoteModulesDeferredRegistrationsUpdateCompletedEvent, (payload: unknown) => {
427
+ if (deferredRegistrationsUpdateSpan) {
428
+ deferredRegistrationsUpdateSpan.addEvent("remote-module-deferred-registrations-update-completed", {
429
+ "app.squide.registration_count": (payload as RemoteModulesDeferredRegistrationsUpdateCompletedEventPayload).registrationCount
430
+ });
431
+ }
432
+
433
+ if (remoteModuleDeferredRegistrationsUpdateSpan) {
434
+ endActiveSpan(remoteModuleDeferredRegistrationsUpdateSpan);
435
+ }
436
+ });
437
+
438
+ // Can occur multiple times.
439
+ runtime.eventBus.addListener(RemoteModuleDeferredRegistrationUpdateFailedEvent, (payload: unknown) => {
440
+ const registrationError = payload as RemoteModuleRegistrationError;
441
+
442
+ if (remoteModuleDeferredRegistrationsUpdateSpan) {
443
+ traceError(remoteModuleDeferredRegistrationsUpdateSpan.instance, registrationError);
444
+ }
445
+ });
446
+ }
447
+
448
+ function getRegisterFetchRequestHookFunction() {
449
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
450
+ // @ts-ignore
451
+ return globalThis.__WLP_HONEYCOMB_REGISTER_DYNAMIC_FETCH_REQUEST_HOOK;
452
+ }
453
+
454
+ export function registerHoneycombInstrumentation(runtime: FireflyRuntime) {
455
+ const registerFetchRequestHookFunction = getRegisterFetchRequestHookFunction();
456
+
457
+ if (registerFetchRequestHookFunction) {
458
+ registerActiveSpanStack();
459
+
460
+ const activeSpanOverrideFunction = createOverrideFetchRequestSpanWithActiveSpanContext(runtime.logger);
461
+
462
+ // Dynamically registering this request hook function to nest the HTTP requests
463
+ // of squide bootstrapping under the appropriate Honeycomb span.
464
+ registerFetchRequestHookFunction(activeSpanOverrideFunction);
465
+ } else {
466
+ runtime.logger.warning("[squide] Cannot register Honeycomb fetch request hook because \"globalThis.__WLP_HONEYCOMB_REGISTER_DYNAMIC_FETCH_REQUEST_HOOK\" is not available. Honeycomb instrumentation is still functional but in degraded mode.");
467
+ }
468
+
469
+ registerTrackingListeners(runtime);
470
+ }
@@ -0,0 +1,6 @@
1
+ import { trace } from "@opentelemetry/api";
2
+
3
+ export function getTracer() {
4
+ // The tracer name is used as the "library.name" attribute.
5
+ return trace.getTracer("@squide/honeycomb");
6
+ }
@@ -0,0 +1,64 @@
1
+ import { type Context, type Exception, context as otelContext, trace as otelTrace, type Span, SpanKind, type SpanOptions, SpanStatusCode, type TimeInput } from "@opentelemetry/api";
2
+ import { type ActiveSpan, popActiveSpan, setActiveSpan } from "./activeSpan.ts";
3
+
4
+ export type StartSpanFactory = (options?: SpanOptions, context?: Context) => Span;
5
+
6
+ export function startSpan(factory: StartSpanFactory) {
7
+ return factory({ kind: SpanKind.CLIENT });
8
+ }
9
+
10
+ export type StartChildSpanFactory = (options?: SpanOptions, context?: Context) => Span;
11
+
12
+ export function startChildSpan(parent: Span, factory: StartChildSpanFactory) {
13
+ const context = otelTrace.setSpan(otelContext.active(), parent);
14
+
15
+ return factory({ kind: SpanKind.CLIENT }, context);
16
+ }
17
+
18
+ export interface StartActiveSpanFactoryReturn {
19
+ name: string;
20
+ span: Span;
21
+ }
22
+
23
+ export type StartActiveSpanFactory = (options?: SpanOptions, context?: Context) => StartActiveSpanFactoryReturn;
24
+
25
+ export function startActiveSpan(factory: StartActiveSpanFactory) {
26
+ const { name, span } = factory({ kind: SpanKind.CLIENT });
27
+
28
+ return setActiveSpan(name, span);
29
+ }
30
+
31
+ export interface StartActiveChildSpanFactoryReturn {
32
+ name: string;
33
+ span: Span;
34
+ }
35
+
36
+ export type StartActiveChildSpanFactory = (options?: SpanOptions, context?: Context) => StartActiveChildSpanFactoryReturn;
37
+
38
+ export function startActiveChildSpan(parent: Span, factory: StartActiveChildSpanFactory) {
39
+ const context = otelTrace.setSpan(otelContext.active(), parent);
40
+
41
+ const { name, span } = factory({ kind: SpanKind.CLIENT }, context);
42
+
43
+ return setActiveSpan(name, span);
44
+ }
45
+
46
+ export function endActiveSpan(span: ActiveSpan) {
47
+ span.instance.end();
48
+
49
+ popActiveSpan(span);
50
+ }
51
+
52
+ export interface TraceErrorOptions {
53
+ time?: TimeInput;
54
+ }
55
+
56
+ export function traceError(span: Span, error: Exception, options: TraceErrorOptions = {}) {
57
+ const { time } = options;
58
+
59
+ span.recordException(error, time);
60
+
61
+ span.setStatus({
62
+ code: SpanStatusCode.ERROR
63
+ });
64
+ }
@@ -2,6 +2,7 @@ import { isFunction, registerLocalModules, type ModuleRegisterFunction, type Reg
2
2
  import { registerRemoteModules, type RemoteDefinition } from "@squide/module-federation";
3
3
  import { setMswAsReady } from "@squide/msw";
4
4
  import { FireflyRuntime, type FireflyRuntimeOptions } from "./FireflyRuntime.tsx";
5
+ import { initializeHoneycomb } from "./honeycomb/initializeHoneycomb.ts";
5
6
 
6
7
  export const ApplicationBootstrappingStartedEvent = "squide-app-bootstrapping-started";
7
8
 
@@ -69,7 +70,8 @@ export function initializeFirefly<TContext = unknown, TData = unknown>(options:
69
70
  mode,
70
71
  useMsw,
71
72
  loggers,
72
- plugins
73
+ plugins,
74
+ onError
73
75
  } = options;
74
76
 
75
77
  if (hasExecuted) {
@@ -85,7 +87,15 @@ export function initializeFirefly<TContext = unknown, TData = unknown>(options:
85
87
  plugins
86
88
  });
87
89
 
88
- bootstrap(runtime, options);
90
+ initializeHoneycomb(runtime)
91
+ .catch((error: unknown) => {
92
+ if (onError) {
93
+ onError(error);
94
+ }
95
+ })
96
+ .finally(() => {
97
+ bootstrap(runtime, options);
98
+ });
89
99
 
90
100
  return runtime;
91
101
  }