@zuplo/cli 7.7.7 → 7.7.9

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 (146) hide show
  1. package/node_modules/@posthog/core/dist/error-tracking/index.d.ts +1 -1
  2. package/node_modules/@posthog/core/dist/error-tracking/index.d.ts.map +1 -1
  3. package/node_modules/@posthog/core/dist/error-tracking/parsers/base.d.ts.map +1 -1
  4. package/node_modules/@posthog/core/dist/error-tracking/parsers/base.js +19 -2
  5. package/node_modules/@posthog/core/dist/error-tracking/parsers/base.mjs +19 -2
  6. package/node_modules/@posthog/core/dist/index.d.ts +7 -0
  7. package/node_modules/@posthog/core/dist/index.d.ts.map +1 -1
  8. package/node_modules/@posthog/core/dist/index.js +82 -21
  9. package/node_modules/@posthog/core/dist/index.mjs +4 -0
  10. package/node_modules/@posthog/core/dist/logs/index.d.ts +3 -2
  11. package/node_modules/@posthog/core/dist/logs/index.d.ts.map +1 -1
  12. package/node_modules/@posthog/core/dist/logs/index.js +28 -22
  13. package/node_modules/@posthog/core/dist/logs/index.mjs +29 -23
  14. package/node_modules/@posthog/core/dist/logs/logs-utils.js +1 -1
  15. package/node_modules/@posthog/core/dist/logs/logs-utils.mjs +2 -2
  16. package/node_modules/@posthog/core/dist/logs/types.d.ts +2 -2
  17. package/node_modules/@posthog/core/dist/metrics/index.d.ts +5 -2
  18. package/node_modules/@posthog/core/dist/metrics/index.d.ts.map +1 -1
  19. package/node_modules/@posthog/core/dist/metrics/index.js +28 -14
  20. package/node_modules/@posthog/core/dist/metrics/index.mjs +29 -15
  21. package/node_modules/@posthog/core/dist/metrics/metrics-utils.d.ts.map +1 -1
  22. package/node_modules/@posthog/core/dist/metrics/metrics-utils.js +1 -2
  23. package/node_modules/@posthog/core/dist/metrics/metrics-utils.mjs +2 -3
  24. package/node_modules/@posthog/core/dist/metrics/types.d.ts +7 -0
  25. package/node_modules/@posthog/core/dist/metrics/types.d.ts.map +1 -1
  26. package/node_modules/@posthog/core/dist/posthog-core-stateless.d.ts +32 -4
  27. package/node_modules/@posthog/core/dist/posthog-core-stateless.d.ts.map +1 -1
  28. package/node_modules/@posthog/core/dist/posthog-core-stateless.js +68 -20
  29. package/node_modules/@posthog/core/dist/posthog-core-stateless.mjs +68 -20
  30. package/node_modules/@posthog/core/dist/traces/config.d.ts +13 -0
  31. package/node_modules/@posthog/core/dist/traces/config.d.ts.map +1 -0
  32. package/node_modules/@posthog/core/dist/traces/config.js +101 -0
  33. package/node_modules/@posthog/core/dist/traces/config.mjs +63 -0
  34. package/node_modules/@posthog/core/dist/traces/context.d.ts +18 -0
  35. package/node_modules/@posthog/core/dist/traces/context.d.ts.map +1 -0
  36. package/node_modules/@posthog/core/dist/traces/context.js +53 -0
  37. package/node_modules/@posthog/core/dist/traces/context.mjs +15 -0
  38. package/node_modules/@posthog/core/dist/traces/ids.d.ts +12 -0
  39. package/node_modules/@posthog/core/dist/traces/ids.d.ts.map +1 -0
  40. package/node_modules/@posthog/core/dist/traces/ids.js +92 -0
  41. package/node_modules/@posthog/core/dist/traces/ids.mjs +42 -0
  42. package/node_modules/@posthog/core/dist/traces/index.d.ts +150 -0
  43. package/node_modules/@posthog/core/dist/traces/index.d.ts.map +1 -0
  44. package/node_modules/@posthog/core/dist/traces/index.js +551 -0
  45. package/node_modules/@posthog/core/dist/traces/index.mjs +513 -0
  46. package/node_modules/@posthog/core/dist/traces/otlp.d.ts +24 -0
  47. package/node_modules/@posthog/core/dist/traces/otlp.d.ts.map +1 -0
  48. package/node_modules/@posthog/core/dist/traces/otlp.js +158 -0
  49. package/node_modules/@posthog/core/dist/traces/otlp.mjs +108 -0
  50. package/node_modules/@posthog/core/dist/traces/sanitize.d.ts +32 -0
  51. package/node_modules/@posthog/core/dist/traces/sanitize.d.ts.map +1 -0
  52. package/node_modules/@posthog/core/dist/traces/sanitize.js +93 -0
  53. package/node_modules/@posthog/core/dist/traces/sanitize.mjs +43 -0
  54. package/node_modules/@posthog/core/dist/traces/span.d.ts +189 -0
  55. package/node_modules/@posthog/core/dist/traces/span.d.ts.map +1 -0
  56. package/node_modules/@posthog/core/dist/traces/span.js +533 -0
  57. package/node_modules/@posthog/core/dist/traces/span.mjs +462 -0
  58. package/node_modules/@posthog/core/dist/traces/traceparent.d.ts +51 -0
  59. package/node_modules/@posthog/core/dist/traces/traceparent.d.ts.map +1 -0
  60. package/node_modules/@posthog/core/dist/traces/traceparent.js +116 -0
  61. package/node_modules/@posthog/core/dist/traces/traceparent.mjs +63 -0
  62. package/node_modules/@posthog/core/dist/traces/types.d.ts +114 -0
  63. package/node_modules/@posthog/core/dist/traces/types.d.ts.map +1 -0
  64. package/node_modules/@posthog/core/dist/traces/types.js +18 -0
  65. package/node_modules/@posthog/core/dist/traces/types.mjs +1 -0
  66. package/node_modules/@posthog/core/dist/utils/backoff.d.ts +23 -0
  67. package/node_modules/@posthog/core/dist/utils/backoff.d.ts.map +1 -0
  68. package/node_modules/@posthog/core/dist/utils/backoff.js +65 -0
  69. package/node_modules/@posthog/core/dist/utils/backoff.mjs +14 -0
  70. package/node_modules/@posthog/core/dist/utils/flush-timer.d.ts +26 -0
  71. package/node_modules/@posthog/core/dist/utils/flush-timer.d.ts.map +1 -0
  72. package/node_modules/@posthog/core/dist/utils/flush-timer.js +67 -0
  73. package/node_modules/@posthog/core/dist/utils/flush-timer.mjs +29 -0
  74. package/node_modules/@posthog/core/dist/utils/json-utils.d.ts +7 -0
  75. package/node_modules/@posthog/core/dist/utils/json-utils.d.ts.map +1 -1
  76. package/node_modules/@posthog/core/dist/utils/json-utils.js +27 -0
  77. package/node_modules/@posthog/core/dist/utils/json-utils.mjs +25 -1
  78. package/node_modules/@posthog/core/dist/utils/otlp-resource.d.ts +13 -2
  79. package/node_modules/@posthog/core/dist/utils/otlp-resource.d.ts.map +1 -1
  80. package/node_modules/@posthog/core/dist/utils/otlp-resource.js +34 -7
  81. package/node_modules/@posthog/core/dist/utils/otlp-resource.mjs +26 -2
  82. package/node_modules/@posthog/core/dist/utils/retry-after.d.ts +55 -0
  83. package/node_modules/@posthog/core/dist/utils/retry-after.d.ts.map +1 -0
  84. package/node_modules/@posthog/core/dist/utils/retry-after.js +95 -0
  85. package/node_modules/@posthog/core/dist/utils/retry-after.mjs +50 -0
  86. package/node_modules/@posthog/core/package.json +3 -3
  87. package/node_modules/@posthog/core/src/error-tracking/index.ts +24 -1
  88. package/node_modules/@posthog/core/src/error-tracking/parsers/base.spec.ts +77 -7
  89. package/node_modules/@posthog/core/src/error-tracking/parsers/base.ts +42 -19
  90. package/node_modules/@posthog/core/src/index.ts +18 -0
  91. package/node_modules/@posthog/core/src/logs/index.spec.ts +490 -2
  92. package/node_modules/@posthog/core/src/logs/index.ts +63 -31
  93. package/node_modules/@posthog/core/src/logs/logs-utils.ts +2 -2
  94. package/node_modules/@posthog/core/src/logs/types.ts +2 -2
  95. package/node_modules/@posthog/core/src/metrics/index.spec.ts +304 -0
  96. package/node_modules/@posthog/core/src/metrics/index.ts +53 -16
  97. package/node_modules/@posthog/core/src/metrics/metrics-utils.ts +2 -3
  98. package/node_modules/@posthog/core/src/metrics/types.ts +10 -2
  99. package/node_modules/@posthog/core/src/posthog-core-stateless.ts +157 -38
  100. package/node_modules/@posthog/core/src/traces/config.spec.ts +271 -0
  101. package/node_modules/@posthog/core/src/traces/config.ts +142 -0
  102. package/node_modules/@posthog/core/src/traces/context.ts +30 -0
  103. package/node_modules/@posthog/core/src/traces/ids.spec.ts +115 -0
  104. package/node_modules/@posthog/core/src/traces/ids.ts +75 -0
  105. package/node_modules/@posthog/core/src/traces/index.spec.ts +3187 -0
  106. package/node_modules/@posthog/core/src/traces/index.ts +1060 -0
  107. package/node_modules/@posthog/core/src/traces/live-spans.spec.ts +69 -0
  108. package/node_modules/@posthog/core/src/traces/otlp.spec.ts +368 -0
  109. package/node_modules/@posthog/core/src/traces/otlp.ts +191 -0
  110. package/node_modules/@posthog/core/src/traces/sanitize.ts +116 -0
  111. package/node_modules/@posthog/core/src/traces/span.spec.ts +1122 -0
  112. package/node_modules/@posthog/core/src/traces/span.ts +822 -0
  113. package/node_modules/@posthog/core/src/traces/traceparent.spec.ts +184 -0
  114. package/node_modules/@posthog/core/src/traces/traceparent.ts +172 -0
  115. package/node_modules/@posthog/core/src/traces/types.ts +140 -0
  116. package/node_modules/@posthog/core/src/utils/backoff.ts +44 -0
  117. package/node_modules/@posthog/core/src/utils/flush-timer.ts +50 -0
  118. package/node_modules/@posthog/core/src/utils/json-utils.ts +33 -0
  119. package/node_modules/@posthog/core/src/utils/otlp-resource.spec.ts +55 -9
  120. package/node_modules/@posthog/core/src/utils/otlp-resource.ts +45 -4
  121. package/node_modules/@posthog/core/src/utils/retry-after.ts +135 -0
  122. package/node_modules/@posthog/types/dist/index.d.ts +1 -0
  123. package/node_modules/@posthog/types/dist/index.d.ts.map +1 -1
  124. package/node_modules/@posthog/types/dist/posthog-config.d.ts +10 -5
  125. package/node_modules/@posthog/types/dist/posthog-config.d.ts.map +1 -1
  126. package/node_modules/@posthog/types/dist/traces.d.ts +387 -0
  127. package/node_modules/@posthog/types/dist/traces.d.ts.map +1 -0
  128. package/node_modules/@posthog/types/dist/traces.js +18 -0
  129. package/node_modules/@posthog/types/dist/traces.mjs +1 -0
  130. package/node_modules/@posthog/types/package.json +1 -1
  131. package/node_modules/@posthog/types/src/index.ts +19 -0
  132. package/node_modules/@posthog/types/src/posthog-config.ts +10 -5
  133. package/node_modules/@posthog/types/src/traces.ts +429 -0
  134. package/node_modules/@zuplo/core/package.json +1 -1
  135. package/node_modules/@zuplo/graphql/package.json +1 -1
  136. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  137. package/node_modules/@zuplo/otel/package.json +1 -1
  138. package/node_modules/@zuplo/runtime/out/esm/{chunk-FEB2VFS7.js → chunk-KNAYKBEE.js} +96 -96
  139. package/node_modules/@zuplo/runtime/out/esm/chunk-KNAYKBEE.js.map +1 -0
  140. package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
  141. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
  142. package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
  143. package/node_modules/@zuplo/runtime/package.json +1 -1
  144. package/package.json +11 -11
  145. package/node_modules/@zuplo/runtime/out/esm/chunk-FEB2VFS7.js.map +0 -1
  146. /package/node_modules/@zuplo/runtime/out/esm/{chunk-FEB2VFS7.js.LEGAL.txt → chunk-KNAYKBEE.js.LEGAL.txt} +0 -0
@@ -0,0 +1,513 @@
1
+ import { PassThroughSpan, PostHogSpan, applySpanLimits, describeError, inertSpan, monotonicNow, runWithActiveSpan, truncateAttributes } from "./span.mjs";
2
+ import { newSpanId, newTraceId } from "./ids.mjs";
3
+ import { parseTraceparent, sanitizeTracestate, traceparentHeader } from "./traceparent.mjs";
4
+ import { clampEndTime, resolveStartTime, resolveSuppliedTime, sanitizeName, toEpochMs } from "./sanitize.mjs";
5
+ import { assignUserAttributes } from "../utils/json-utils.mjs";
6
+ import { buildOtlpSpan, buildOtlpTracesPayload, buildTracesResourceAttributes } from "./otlp.mjs";
7
+ import { isPromise } from "../utils/index.mjs";
8
+ import { FlushTimer } from "../utils/flush-timer.mjs";
9
+ import { RetryAfterWindow } from "../utils/retry-after.mjs";
10
+ import { MAX_FLUSH_BACKOFF_MS, NO_JITTER, backoffDelayMs, drawJitter } from "../utils/backoff.mjs";
11
+ const MAX_RETRIES_PER_BATCH = 8;
12
+ function clockNow() {
13
+ return monotonicNow() ?? Date.now();
14
+ }
15
+ function isOwnSpan(value) {
16
+ try {
17
+ return value instanceof PostHogSpan;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ function remoteContext(header, tracestate) {
23
+ const remote = parseTraceparent(header);
24
+ if (!remote) return;
25
+ return {
26
+ traceId: remote.traceId,
27
+ parentSpanId: remote.spanId,
28
+ traceState: sanitizeTracestate(tracestate),
29
+ traceFlags: remote.flags,
30
+ isRemote: true
31
+ };
32
+ }
33
+ function looksLikeSpan(value) {
34
+ try {
35
+ return 'function' == typeof value.traceparent;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+ function isSpanRecordShape(record) {
41
+ return !!record.attributes && 'object' == typeof record.attributes && !Array.isArray(record.attributes) && Array.isArray(record.events) && void 0 !== record.name && void 0 !== record.kind && void 0 !== record.startTime && void 0 !== record.endTime;
42
+ }
43
+ function restoreField(record, field, value) {
44
+ if (record[field] !== value) record[field] = value;
45
+ }
46
+ function withRestoredIdentity(hooked, original) {
47
+ try {
48
+ const descriptors = Object.getOwnPropertyDescriptors(hooked);
49
+ for (const field of [
50
+ 'traceId',
51
+ 'spanId',
52
+ 'parentSpanId',
53
+ 'traceState'
54
+ ])descriptors[field] = {
55
+ value: original[field],
56
+ enumerable: true,
57
+ writable: true,
58
+ configurable: true
59
+ };
60
+ return Object.create(Object.getPrototypeOf(hooked), descriptors);
61
+ } catch {
62
+ return hooked;
63
+ }
64
+ }
65
+ class PostHogTraces {
66
+ constructor(_instance, _config, _logger, _getContext, _contextManager, _onSpanQueued){
67
+ this._instance = _instance;
68
+ this._config = _config;
69
+ this._logger = _logger;
70
+ this._getContext = _getContext;
71
+ this._contextManager = _contextManager;
72
+ this._onSpanQueued = _onSpanQueued;
73
+ this._queue = [];
74
+ this._flushTimer = new FlushTimer(()=>this._flushInBackground());
75
+ this._flushPromise = null;
76
+ this._droppedSinceWarning = 0;
77
+ this._lastDropWarningAt = 0;
78
+ this._dropReasons = new Set();
79
+ this._consecutiveFlushFailures = 0;
80
+ this._flushJitter = NO_JITTER;
81
+ this._retryAfter = new RetryAfterWindow();
82
+ this._headBatchFailures = 0;
83
+ this._headBatchSize = 0;
84
+ this._headBatchChargeableAt = 0;
85
+ this._generation = 0;
86
+ this._liveSpans = new Map();
87
+ this._maxExportBatchSize = _config.maxExportBatchSize;
88
+ }
89
+ startSpan(name, options) {
90
+ if (this._instance.isDisabled || this._instance.optedOut) return inertSpan(options, this._contextManager.active());
91
+ const explicitParent = traceparentHeader(options?.parent);
92
+ if (explicitParent && 'string' != typeof explicitParent && !isOwnSpan(explicitParent)) {
93
+ if (looksLikeSpan(explicitParent)) {
94
+ this._logger.debug('Span parent is not a span from this SDK; returning an inert span');
95
+ return inertSpan(options, this._contextManager.active());
96
+ }
97
+ this._logger.debug('Ignoring an unusable span parent');
98
+ }
99
+ const parent = this._resolveParent(explicitParent, options);
100
+ this._evictAgedSpans();
101
+ if (this._liveSpans.size >= this._config.maxLiveSpans) {
102
+ this._recordDrop(1, `the live-span limit (${this._config.maxLiveSpans}) was reached — spans are being started and never ended`);
103
+ return inertSpan(options, this._contextManager.active());
104
+ }
105
+ const now = Date.now();
106
+ const startTime = resolveStartTime(options?.startTime, now, this._logger);
107
+ const spanId = newSpanId();
108
+ this._liveSpans.set(spanId, clockNow());
109
+ const autoAttributes = this._autoContextAttributes();
110
+ return new PostHogSpan({
111
+ traceId: parent?.traceId ?? newTraceId(),
112
+ spanId,
113
+ parentSpanId: parent?.parentSpanId,
114
+ traceState: parent?.traceState,
115
+ traceFlags: parent?.traceFlags,
116
+ parentIsRemote: parent?.isRemote,
117
+ name: sanitizeName(name, 'Span name', this._config.maxAttributeValueLength, this._logger),
118
+ kind: options?.kind ?? 'internal',
119
+ attributes: assignUserAttributes({
120
+ ...autoAttributes
121
+ }, options?.attributes),
122
+ autoAttributeKeys: Object.keys(autoAttributes),
123
+ maxAttributes: this._config.maxAttributesPerSpan,
124
+ maxEvents: this._config.maxEventsPerSpan,
125
+ maxAttributesPerEvent: this._config.maxAttributesPerEvent,
126
+ maxAttributeValueLength: this._config.maxAttributeValueLength,
127
+ startTime,
128
+ backdated: startTime !== now
129
+ }, (record, autoKeys)=>this._onSpanEnd(record, autoKeys), this._logger);
130
+ }
131
+ withSpan(name, optionsOrFn, maybeFn) {
132
+ const options = 'function' == typeof optionsOrFn ? void 0 : optionsOrFn;
133
+ const fn = 'function' == typeof optionsOrFn ? optionsOrFn : maybeFn;
134
+ const span = this.startSpan(name, options);
135
+ try {
136
+ const result = runWithActiveSpan(this._contextManager, span, fn);
137
+ if (isPromise(result)) return result.then((value)=>{
138
+ span.end();
139
+ return value;
140
+ }, (error)=>{
141
+ this._recordCallbackError(span, error);
142
+ span.end();
143
+ throw error;
144
+ });
145
+ span.end();
146
+ return result;
147
+ } catch (error) {
148
+ this._recordCallbackError(span, error);
149
+ span.end();
150
+ throw error;
151
+ }
152
+ }
153
+ getActiveSpan() {
154
+ return this._contextManager.active() ?? null;
155
+ }
156
+ get throttled() {
157
+ return this._retryAfter.isOpen();
158
+ }
159
+ async flush() {
160
+ for(;;){
161
+ if (!this._queue.length) return;
162
+ const inFlight = this._flushPromise;
163
+ const removed = await (inFlight ?? this._startFlush());
164
+ if (!removed) return;
165
+ }
166
+ }
167
+ _startFlush() {
168
+ this._flushTimer.clear();
169
+ const startedAtGeneration = this._generation;
170
+ const promise = Promise.resolve().then(()=>startedAtGeneration === this._generation ? this._flushInner() : 0).finally(()=>{
171
+ if (this._flushPromise === promise) this._flushPromise = null;
172
+ this._armFlushTimerIfQueuedNoEarlierThan();
173
+ });
174
+ this._flushPromise = promise;
175
+ return promise;
176
+ }
177
+ reset() {
178
+ this._flushTimer.clear();
179
+ if (this._queue.length) this._logger.critical(`Discarding ${this._queue.length} span(s) that were still queued when tracing was shut down. Raise the shutdown timeout or flush earlier if they matter.`);
180
+ this._queue = [];
181
+ this._liveSpans.clear();
182
+ this._flushPromise = null;
183
+ this._generation++;
184
+ this._maxExportBatchSize = this._config.maxExportBatchSize;
185
+ this._droppedSinceWarning = 0;
186
+ this._dropReasons.clear();
187
+ this._lastDropWarningAt = 0;
188
+ this._consecutiveFlushFailures = 0;
189
+ this._flushJitter = NO_JITTER;
190
+ this._retryAfter.reset();
191
+ this._resetHeadBatchBudget();
192
+ }
193
+ _resetHeadBatchBudget() {
194
+ this._headBatchFailures = 0;
195
+ this._headBatchChargeableAt = 0;
196
+ }
197
+ _resolveParent(explicit, options) {
198
+ if ('string' == typeof explicit) {
199
+ const remote = remoteContext(explicit, options?.tracestate);
200
+ if (!remote) this._logger.debug('Ignoring malformed traceparent; starting a new trace');
201
+ return remote;
202
+ }
203
+ if (isOwnSpan(explicit)) return explicit.childContext();
204
+ const active = this._contextManager.active();
205
+ if (isOwnSpan(active)) return active.childContext();
206
+ if (active instanceof PassThroughSpan) return remoteContext(active.traceparent(), active.tracestate() ?? void 0);
207
+ }
208
+ _autoContextAttributes() {
209
+ let context;
210
+ try {
211
+ context = this._getContext();
212
+ } catch (error) {
213
+ this._logger.debug('Failed to read tracing context; span will carry no PostHog attributes', error);
214
+ return {};
215
+ }
216
+ const attributes = {};
217
+ if (context.distinctId) attributes.posthogDistinctId = context.distinctId;
218
+ if (context.sessionId) attributes.sessionId = context.sessionId;
219
+ if (context.currentUrl) attributes['url.full'] = context.currentUrl;
220
+ if (context.screenName) attributes['screen.name'] = context.screenName;
221
+ if (context.appState) attributes['app.state'] = context.appState;
222
+ return attributes;
223
+ }
224
+ _recordCallbackError(span, error) {
225
+ if (!(span instanceof PostHogSpan)) return;
226
+ const { type, message, stack } = describeError(error);
227
+ span.addEvent('exception', {
228
+ 'exception.type': type,
229
+ 'exception.message': message,
230
+ ...stack && {
231
+ 'exception.stacktrace': stack
232
+ }
233
+ });
234
+ if (!span.statusIsExplicitlyOk) span.setStatus('error', message);
235
+ }
236
+ _evictAgedSpans() {
237
+ const cutoff = clockNow() - this._config.maxSpanAgeMs;
238
+ let evicted = 0;
239
+ for (const [spanId, startedAt] of this._liveSpans){
240
+ if (startedAt > cutoff) break;
241
+ this._liveSpans.delete(spanId);
242
+ evicted++;
243
+ }
244
+ if (evicted) this._recordDrop(evicted, `they were still live after ${this._config.maxSpanAgeMs}ms`);
245
+ }
246
+ _onSpanEnd(incoming, autoKeys) {
247
+ if (!this._liveSpans.delete(incoming.spanId)) return;
248
+ if (this._instance.isDisabled || this._instance.optedOut) return void this._recordDrop(1, 'the user has opted out');
249
+ const record = this._runBeforeSpanSend(incoming, autoKeys);
250
+ if (!record) return;
251
+ this._reportLimitDrops(record);
252
+ if (this._queue.length >= this._config.maxQueueSize) return void this._recordDrop(1, `the queue is full (${this._config.maxQueueSize}) — raise the flush frequency or reduce span volume`);
253
+ this._queue.push(record);
254
+ try {
255
+ this._onSpanQueued?.();
256
+ } catch (error) {
257
+ this._logger.debug('Span queue notification failed', error);
258
+ }
259
+ if (!(this._queue.length >= this._maxExportBatchSize) || this._consecutiveFlushFailures || this._retryAfter.isOpen()) this._armFlushTimerIfQueued();
260
+ else this._flushInBackground();
261
+ }
262
+ _reportLimitDrops(record) {
263
+ const attributes = record.droppedAttributesCount ?? 0;
264
+ const events = record.droppedEventsCount ?? 0;
265
+ let eventAttributes = 0;
266
+ for (const event of record.events)eventAttributes += event.droppedAttributesCount ?? 0;
267
+ if (attributes || events || eventAttributes) this._logger.debug(`Span limits discarded data from "${record.name}": ${attributes} attributes, ${events} events, ${eventAttributes} event attributes`);
268
+ }
269
+ _runBeforeSpanSend(record, autoKeys) {
270
+ if (!this._config.beforeSpanSend.length) return record;
271
+ const identity = {
272
+ traceId: record.traceId,
273
+ spanId: record.spanId,
274
+ parentSpanId: record.parentSpanId,
275
+ traceState: record.traceState
276
+ };
277
+ const originalTimes = {
278
+ startTime: record.startTime,
279
+ endTime: record.endTime
280
+ };
281
+ const originalDropped = {
282
+ attributes: record.droppedAttributesCount,
283
+ events: record.droppedEventsCount
284
+ };
285
+ const keysBeforeHook = Object.keys(record.attributes);
286
+ const originalPropagation = {
287
+ traceFlags: record.traceFlags,
288
+ parentIsRemote: record.parentIsRemote
289
+ };
290
+ const originalStatus = record.status && {
291
+ ...record.status
292
+ };
293
+ let hooked = record;
294
+ let current = record;
295
+ try {
296
+ for (const hook of this._config.beforeSpanSend){
297
+ const result = hook(hooked);
298
+ if (!result) {
299
+ this._recordDrop(1, 'beforeSpanSend dropped it');
300
+ return null;
301
+ }
302
+ hooked = this._keepSpanIdentity(result, identity);
303
+ }
304
+ const rebuilt = {
305
+ traceId: identity.traceId,
306
+ spanId: identity.spanId,
307
+ parentSpanId: identity.parentSpanId,
308
+ traceState: identity.traceState,
309
+ name: hooked.name,
310
+ kind: hooked.kind,
311
+ status: hooked.status,
312
+ attributes: hooked.attributes,
313
+ events: hooked.events,
314
+ startTime: hooked.startTime,
315
+ endTime: hooked.endTime,
316
+ traceFlags: originalPropagation.traceFlags,
317
+ parentIsRemote: originalPropagation.parentIsRemote,
318
+ droppedAttributesCount: originalDropped.attributes,
319
+ droppedEventsCount: originalDropped.events
320
+ };
321
+ current = rebuilt;
322
+ if (!isSpanRecordShape(current)) {
323
+ this._logger.debug('beforeSpanSend did not return a span record; dropping the span');
324
+ this._recordDrop(1, 'beforeSpanSend returned an unusable record');
325
+ return null;
326
+ }
327
+ current.name = sanitizeName(current.name, 'Span name', this._config.maxAttributeValueLength, this._logger);
328
+ if (current.status && 'ok' !== current.status.code && 'error' !== current.status.code) {
329
+ this._logger.debug('beforeSpanSend set an unknown span status; keeping the original');
330
+ current.status = originalStatus;
331
+ }
332
+ current.startTime = toEpochMs(current.startTime) ?? originalTimes.startTime;
333
+ current.endTime = clampEndTime(toEpochMs(current.endTime) ?? originalTimes.endTime, current.startTime);
334
+ const sanitizedEvents = [];
335
+ for (const event of current.events)try {
336
+ sanitizedEvents.push({
337
+ ...event,
338
+ name: sanitizeName(event.name, 'Span event name', this._config.maxAttributeValueLength, this._logger),
339
+ timestamp: resolveSuppliedTime(event.timestamp, current.startTime, 'event timestamp', this._logger)
340
+ });
341
+ } catch {
342
+ this._logger.debug('beforeSpanSend left an unreadable span event; dropping it');
343
+ }
344
+ current.events = sanitizedEvents;
345
+ applySpanLimits(current, autoKeys, this._config.maxAttributesPerSpan, this._config.maxEventsPerSpan, this._config.maxAttributesPerEvent, this._config.maxAttributeValueLength, keysBeforeHook);
346
+ return current;
347
+ } catch (error) {
348
+ this._logger.debug('beforeSpanSend failed; dropping the span rather than exporting it unscrubbed', error);
349
+ this._recordDrop(1, 'beforeSpanSend failed');
350
+ return null;
351
+ }
352
+ }
353
+ _keepSpanIdentity(hooked, original) {
354
+ if (hooked.traceId !== original.traceId || hooked.spanId !== original.spanId || hooked.parentSpanId !== original.parentSpanId) this._logger.debug('beforeSpanSend changed a span identity field; keeping the original ids');
355
+ try {
356
+ restoreField(hooked, 'traceId', original.traceId);
357
+ restoreField(hooked, 'spanId', original.spanId);
358
+ restoreField(hooked, 'parentSpanId', original.parentSpanId);
359
+ restoreField(hooked, 'traceState', original.traceState);
360
+ } catch {
361
+ return withRestoredIdentity(hooked, original);
362
+ }
363
+ return hooked;
364
+ }
365
+ _recordDrop(count, reason) {
366
+ this._droppedSinceWarning += count;
367
+ this._dropReasons.add(reason);
368
+ if (Date.now() - this._lastDropWarningAt >= this._config.flushIntervalMs) this._warnAboutDrops();
369
+ }
370
+ _warnAboutDrops() {
371
+ if (!this._droppedSinceWarning) return;
372
+ this._lastDropWarningAt = Date.now();
373
+ this._logger.warn(`Dropping ${this._droppedSinceWarning} span(s): ${[
374
+ ...this._dropReasons
375
+ ].join('; ')}`);
376
+ this._droppedSinceWarning = 0;
377
+ this._dropReasons.clear();
378
+ }
379
+ _encodeBatch(batch) {
380
+ const encoded = [];
381
+ for (const record of batch)try {
382
+ encoded.push(buildOtlpSpan(record, this._logger));
383
+ } catch (error) {
384
+ this._logger.debug('Failed to encode a span; dropping it', error);
385
+ this._recordDrop(1, 'its attributes could not be encoded');
386
+ }
387
+ return encoded;
388
+ }
389
+ _discardQueueIfConsentWithdrawn() {
390
+ if (!this._instance.isDisabled && !this._instance.optedOut) return 0;
391
+ const discarded = this._queue.length;
392
+ this._queue = [];
393
+ this._resetHeadBatchBudget();
394
+ this._recordDrop(discarded, 'the user has opted out');
395
+ this._warnAboutDrops();
396
+ return discarded;
397
+ }
398
+ async _flushInner() {
399
+ if (!this._queue.length) return 0;
400
+ const discardedBeforeDrain = this._discardQueueIfConsentWithdrawn();
401
+ if (discardedBeforeDrain) return discardedBeforeDrain;
402
+ const resourceAttributes = truncateAttributes(buildTracesResourceAttributes(this._config, this._instance.getLibraryId(), this._instance.getLibraryVersion()), this._config.maxAttributeValueLength);
403
+ const scopeName = this._instance.getLibraryId();
404
+ const scopeVersion = this._instance.getLibraryVersion();
405
+ let remaining = this._queue.length;
406
+ let removed = 0;
407
+ let localCap = 1 / 0;
408
+ const generation = this._generation;
409
+ try {
410
+ while(remaining > 0 && this._queue.length > 0){
411
+ const discardedMidDrain = this._discardQueueIfConsentWithdrawn();
412
+ if (discardedMidDrain) return removed + discardedMidDrain;
413
+ const cap = this._headBatchFailures > 0 ? Math.min(this._maxExportBatchSize, this._headBatchSize) : this._maxExportBatchSize;
414
+ const size = Math.max(1, Math.min(cap, localCap, remaining, this._queue.length));
415
+ const batch = this._queue.slice(0, size);
416
+ const spans = this._encodeBatch(batch);
417
+ if (!spans.length) {
418
+ this._queue.splice(0, size);
419
+ remaining -= size;
420
+ removed += size;
421
+ this._resetHeadBatchBudget();
422
+ continue;
423
+ }
424
+ const chargeable = clockNow() >= this._headBatchChargeableAt && !this._retryAfter.isOpen();
425
+ const outcome = await this._instance._sendTracesBatch(buildOtlpTracesPayload(spans, resourceAttributes, scopeName, scopeVersion, this._logger));
426
+ if (generation !== this._generation) break;
427
+ this._retryAfter.record(outcome);
428
+ if ('ok' === outcome.kind) {
429
+ this._consecutiveFlushFailures = 0;
430
+ this._flushJitter = NO_JITTER;
431
+ this._resetHeadBatchBudget();
432
+ this._queue.splice(0, size);
433
+ remaining -= size;
434
+ removed += size;
435
+ if (this._maxExportBatchSize < this._config.maxExportBatchSize) this._maxExportBatchSize++;
436
+ continue;
437
+ }
438
+ if ('too-large' === outcome.kind) {
439
+ if (1 === size) {
440
+ this._queue.splice(0, 1);
441
+ remaining -= 1;
442
+ removed += 1;
443
+ this._recordDrop(1, 'it is too large for the ingestion endpoint');
444
+ this._consecutiveFlushFailures = 0;
445
+ this._flushJitter = NO_JITTER;
446
+ this._resetHeadBatchBudget();
447
+ continue;
448
+ }
449
+ const halved = Math.max(1, Math.floor(size / 2));
450
+ if (outcome.measuredLocally) localCap = halved;
451
+ else this._maxExportBatchSize = halved;
452
+ this._resetHeadBatchBudget();
453
+ this._logger.debug(`Batch too large; retrying the same spans in batches of ${halved}`);
454
+ continue;
455
+ }
456
+ if ('retry-later' === outcome.kind) {
457
+ this._consecutiveFlushFailures++;
458
+ this._flushJitter = drawJitter();
459
+ this._headBatchSize = size;
460
+ if (chargeable) {
461
+ this._headBatchFailures++;
462
+ this._headBatchChargeableAt = clockNow() + this._nextFlushDelay();
463
+ }
464
+ if (this._headBatchFailures < MAX_RETRIES_PER_BATCH) {
465
+ this._logger.debug('Span export failed; retrying on the next flush', outcome.error);
466
+ return removed;
467
+ }
468
+ this._queue.splice(0, size);
469
+ remaining -= size;
470
+ removed += size;
471
+ this._consecutiveFlushFailures = 0;
472
+ this._flushJitter = NO_JITTER;
473
+ this._resetHeadBatchBudget();
474
+ this._recordDrop(size, `the ingestion endpoint failed ${MAX_RETRIES_PER_BATCH} times in a row`);
475
+ if (this._retryAfter.isOpen()) return removed;
476
+ continue;
477
+ }
478
+ this._logger.debug('Dropping a span batch the ingestion endpoint rejected', outcome.error);
479
+ this._queue.splice(0, size);
480
+ remaining -= size;
481
+ removed += size;
482
+ this._consecutiveFlushFailures = 0;
483
+ this._flushJitter = NO_JITTER;
484
+ this._resetHeadBatchBudget();
485
+ this._recordDrop(size, 'the ingestion endpoint rejected the batch');
486
+ }
487
+ return removed;
488
+ } finally{
489
+ this._warnAboutDrops();
490
+ }
491
+ }
492
+ _flushInBackground() {
493
+ if (this._backgroundFlush) return;
494
+ this._backgroundFlush = this.flush().catch((error)=>{
495
+ this._logger.debug('Background span flush failed', error);
496
+ }).finally(()=>{
497
+ this._backgroundFlush = void 0;
498
+ this._armFlushTimerIfQueuedNoEarlierThan();
499
+ });
500
+ }
501
+ _armFlushTimerIfQueued() {
502
+ if (this._flushTimer.pending || !this._queue.length) return;
503
+ this._flushTimer.arm(this._nextFlushDelay());
504
+ }
505
+ _armFlushTimerIfQueuedNoEarlierThan() {
506
+ if (!this._queue.length) return;
507
+ this._flushTimer.armNoEarlierThan(this._nextFlushDelay());
508
+ }
509
+ _nextFlushDelay() {
510
+ return Math.max(backoffDelayMs(this._config.flushIntervalMs, this._consecutiveFlushFailures, this._flushJitter, MAX_FLUSH_BACKOFF_MS), this._retryAfter.remainingMs());
511
+ }
512
+ }
513
+ export { PostHogTraces };
@@ -0,0 +1,24 @@
1
+ import type { OtlpSpan, OtlpTracesPayload, SpanAttributes, SpanKind } from '@posthog/types';
2
+ import type { Logger } from '../types';
3
+ import type { ResolvedTracesConfig, SpanRecord } from './types';
4
+ export declare function spanKindToOtlp(kind: SpanKind | undefined): number;
5
+ /**
6
+ * Converts a millisecond epoch to the unix-nanosecond string OTLP expects.
7
+ * Concatenation rather than multiplication: `Date.now() * 1e6` exceeds
8
+ * `Number.MAX_SAFE_INTEGER`.
9
+ */
10
+ export declare function msToUnixNanoString(ms: number): string;
11
+ export declare function buildOtlpSpan(record: SpanRecord, logger?: Logger): OtlpSpan;
12
+ /**
13
+ * OTLP resource attributes for every batch. User `resourceAttributes` are spread
14
+ * first, then SDK-controlled identity keys on top so a stray key can't clobber
15
+ * them. `service.name` is always emitted: the server reads `service_name` only
16
+ * from that attribute, and spans are unattributable without it.
17
+ */
18
+ export declare function buildTracesResourceAttributes(config: ResolvedTracesConfig, sdkName: string, sdkVersion: string): SpanAttributes;
19
+ /**
20
+ * Wraps spans in the OTLP `resourceSpans` envelope: one resource, one scope, N
21
+ * spans per batch. The server flattens the scope to `{name}@{version}`.
22
+ */
23
+ export declare function buildOtlpTracesPayload(spans: OtlpSpan[], resourceAttributes: SpanAttributes, scopeName: string, scopeVersion: string, logger?: Logger): OtlpTracesPayload;
24
+ //# sourceMappingURL=otlp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otlp.d.ts","sourceRoot":"","sources":["../../src/traces/otlp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAGR,iBAAiB,EACjB,cAAc,EACd,QAAQ,EAET,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAsD/D,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAOjE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAYrD;AAoBD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAwC3E;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,cAAc,CAEhB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,QAAQ,EAAE,EACjB,kBAAkB,EAAE,cAAc,EAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,iBAAiB,CAcnB"}