@posthog/core 1.34.0 → 1.35.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.
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -18
- package/dist/index.mjs +3 -3
- package/dist/logs/index.d.ts +14 -15
- package/dist/logs/index.d.ts.map +1 -1
- package/dist/logs/index.js +46 -18
- package/dist/logs/index.mjs +47 -19
- package/dist/logs/logs-utils.d.ts +16 -1
- package/dist/logs/logs-utils.d.ts.map +1 -1
- package/dist/logs/logs-utils.js +17 -0
- package/dist/logs/logs-utils.mjs +15 -1
- package/dist/logs/types.d.ts +23 -38
- package/dist/logs/types.d.ts.map +1 -1
- package/dist/posthog-core.d.ts +3 -0
- package/dist/posthog-core.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +2 -1
- package/src/logs/index.spec.ts +259 -0
- package/src/logs/index.ts +108 -49
- package/src/logs/logs-utils.ts +30 -1
- package/src/logs/types.ts +32 -37
- package/src/posthog-core.ts +3 -0
package/src/logs/index.ts
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import type { LogAttributeValue } from '@posthog/types'
|
|
2
|
-
import { buildOtlpLogRecord, buildOtlpLogsPayload } from './logs-utils'
|
|
2
|
+
import { buildOtlpLogRecord, buildOtlpLogsPayload, buildResourceAttributes } from './logs-utils'
|
|
3
3
|
import { Logger, PostHogPersistedProperty } from '../types'
|
|
4
|
-
import type { PostHogCoreStateless } from '../posthog-core-stateless'
|
|
5
4
|
import { isArray, safeSetTimeout } from '../utils'
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
LogSdkContext,
|
|
11
|
-
ResolvedPostHogLogsConfig,
|
|
12
|
-
} from './types'
|
|
5
|
+
import type { BufferedLogEntry, CaptureLogOptions, LogSdkContext, LogsHost, ResolvedPostHogLogsConfig } from './types'
|
|
6
|
+
|
|
7
|
+
// Caps the retry backoff at 2^6 = 64× the flush interval.
|
|
8
|
+
const MAX_FLUSH_BACKOFF_EXPONENT = 6
|
|
13
9
|
|
|
14
10
|
export class PostHogLogs {
|
|
15
11
|
private _maxBufferSize: number
|
|
12
|
+
// Eviction cap; `_maxBufferSize` only triggers a flush. Collapses to
|
|
13
|
+
// `_maxBufferSize` when the host sets no separate value.
|
|
14
|
+
private _maxQueueSize: number
|
|
16
15
|
private _flushIntervalMs: number
|
|
17
16
|
// Mutable — halved on 413 to shrink the next POST, and ramped back up by
|
|
18
17
|
// one record after each successful send so a one-off oversized payload
|
|
@@ -22,6 +21,12 @@ export class PostHogLogs {
|
|
|
22
21
|
// Serializes concurrent flushes — the second caller awaits the first rather
|
|
23
22
|
// than racing it and double-sending the same head-of-queue records.
|
|
24
23
|
private _flushPromise: Promise<void> | null = null
|
|
24
|
+
// Head records evicted (FIFO) while a batch is in flight; the queue-advance
|
|
25
|
+
// subtracts these so it drops the sent records, not ones captured mid-send.
|
|
26
|
+
private _evictedSinceAdvance = 0
|
|
27
|
+
// Consecutive failed flushes; drives exponential backoff on the retry timer.
|
|
28
|
+
// A successful flush resets it to 0.
|
|
29
|
+
private _consecutiveFlushFailures = 0
|
|
25
30
|
|
|
26
31
|
// Fixed-window rate cap. Tumbling (not sliding) for cheap arithmetic on the
|
|
27
32
|
// hot path. Window rolls the first time `captureLog` fires after the window
|
|
@@ -34,7 +39,7 @@ export class PostHogLogs {
|
|
|
34
39
|
private _droppedWarned = false
|
|
35
40
|
|
|
36
41
|
constructor(
|
|
37
|
-
private readonly _instance:
|
|
42
|
+
private readonly _instance: LogsHost,
|
|
38
43
|
private readonly _config: ResolvedPostHogLogsConfig,
|
|
39
44
|
private readonly _logger: Logger,
|
|
40
45
|
private readonly _getContext: () => LogSdkContext,
|
|
@@ -47,12 +52,38 @@ export class PostHogLogs {
|
|
|
47
52
|
private readonly _waitForStoragePersist: () => Promise<void> = () => Promise.resolve()
|
|
48
53
|
) {
|
|
49
54
|
this._maxBufferSize = _config.maxBufferSize
|
|
55
|
+
// Never below the flush trigger: a smaller eviction cap would stop the
|
|
56
|
+
// size-based flush from ever firing. Collapses to `maxBufferSize` when unset.
|
|
57
|
+
this._maxQueueSize = Math.max(_config.maxQueueSize ?? _config.maxBufferSize, _config.maxBufferSize)
|
|
50
58
|
this._flushIntervalMs = _config.flushIntervalMs
|
|
51
59
|
this._maxBatchRecordsPerPost = _config.maxBatchRecordsPerPost
|
|
52
60
|
this._rateCapWindowMs = _config.rateCapWindowMs
|
|
53
61
|
this._maxLogsPerInterval = _config.maxLogsPerInterval
|
|
54
62
|
}
|
|
55
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Clears the flush timer and rate-cap state. The host owns the record queue
|
|
66
|
+
* and clears it separately (the browser empties its in-memory store).
|
|
67
|
+
*/
|
|
68
|
+
reset(): void {
|
|
69
|
+
this._clearFlushTimer()
|
|
70
|
+
this._flushPromise = null
|
|
71
|
+
this._intervalWindowStart = 0
|
|
72
|
+
this._intervalLogCount = 0
|
|
73
|
+
this._droppedWarned = false
|
|
74
|
+
this._evictedSinceAdvance = 0
|
|
75
|
+
this._consecutiveFlushFailures = 0
|
|
76
|
+
this._maxBatchRecordsPerPost = this._config.maxBatchRecordsPerPost
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Call when connectivity is restored: clear the failure backoff and flush now,
|
|
80
|
+
// so records don't wait out a (possibly minutes-long) backoff delay after the
|
|
81
|
+
// network returns. The host owns connectivity detection (web: `online` event).
|
|
82
|
+
onReconnect(): void {
|
|
83
|
+
this._consecutiveFlushFailures = 0
|
|
84
|
+
this._flushInBackground()
|
|
85
|
+
}
|
|
86
|
+
|
|
56
87
|
captureLog(options: CaptureLogOptions): void {
|
|
57
88
|
if (this._instance.isDisabled) {
|
|
58
89
|
return
|
|
@@ -70,8 +101,10 @@ export class PostHogLogs {
|
|
|
70
101
|
if (filtered === null) {
|
|
71
102
|
return
|
|
72
103
|
}
|
|
73
|
-
// beforeSend could return a record with empty body —
|
|
104
|
+
// beforeSend could return a record with empty body — drop it, mirroring the
|
|
105
|
+
// null-return path so both beforeSend drops surface the same diagnostic.
|
|
74
106
|
if (!filtered.body) {
|
|
107
|
+
this._logger.info(`Log was rejected in beforeSend function`)
|
|
75
108
|
return
|
|
76
109
|
}
|
|
77
110
|
|
|
@@ -196,6 +229,12 @@ export class PostHogLogs {
|
|
|
196
229
|
let sentCount = 0
|
|
197
230
|
|
|
198
231
|
while (queue.length > 0 && sentCount < originalQueueLength) {
|
|
232
|
+
// Reset per batch so the advance below counts only evictions during THIS
|
|
233
|
+
// batch's send. Evictions during the persist await or between iterations
|
|
234
|
+
// are already reflected in the next iteration's queue read, so they must
|
|
235
|
+
// not carry into the next batch's drop math.
|
|
236
|
+
this._evictedSinceAdvance = 0
|
|
237
|
+
|
|
199
238
|
const batchSize = Math.min(queue.length, this._maxBatchRecordsPerPost)
|
|
200
239
|
const batch = queue.slice(0, batchSize)
|
|
201
240
|
const records = batch.map((e) => e.record)
|
|
@@ -250,36 +289,19 @@ export class PostHogLogs {
|
|
|
250
289
|
}
|
|
251
290
|
|
|
252
291
|
private async _persistQueueAdvance(consumed: number): Promise<void> {
|
|
253
|
-
// Re-read
|
|
292
|
+
// Re-read in case captures landed mid-flush. Subtract head records the FIFO cap
|
|
293
|
+
// evicted during the send (already-sent records that left the queue), so we drop
|
|
294
|
+
// only the still-present sent records, not ones captured during the send.
|
|
295
|
+
const evicted = this._evictedSinceAdvance
|
|
296
|
+
const drop = Math.max(0, consumed - evicted)
|
|
254
297
|
const refreshed = this._instance.getPersistedProperty<BufferedLogEntry[]>(PostHogPersistedProperty.LogsQueue) ?? []
|
|
255
|
-
this._instance.setPersistedProperty(PostHogPersistedProperty.LogsQueue, refreshed.slice(
|
|
256
|
-
//
|
|
257
|
-
// events' `flushStorage()` contract. Prevents duplicates if the app crashes
|
|
258
|
-
// after the HTTP success but before the queue-advance persists.
|
|
298
|
+
this._instance.setPersistedProperty(PostHogPersistedProperty.LogsQueue, refreshed.slice(drop))
|
|
299
|
+
// Persist before the next batch sends so a crash after HTTP success can't dupe.
|
|
259
300
|
await this._waitForStoragePersist()
|
|
260
301
|
}
|
|
261
302
|
|
|
262
|
-
/**
|
|
263
|
-
* OTLP resource attributes for every batch.
|
|
264
|
-
*
|
|
265
|
-
* Layout: user `resourceAttributes` spread first, then SDK-controlled
|
|
266
|
-
* keys layered on top so users cannot accidentally clobber them. Most logs
|
|
267
|
-
* backends index on `service.name` and `telemetry.sdk.*` for routing,
|
|
268
|
-
* SDK-version dashboards, and bug-correlation; letting a stray user key
|
|
269
|
-
* overwrite them silently breaks ingestion attribution. The dedicated
|
|
270
|
-
* `serviceName` / `environment` / `serviceVersion` config fields are the
|
|
271
|
-
* supported way to override `service.name` / `deployment.environment` /
|
|
272
|
-
* `service.version`.
|
|
273
|
-
*/
|
|
274
303
|
private _buildResourceAttributes(): Record<string, LogAttributeValue> {
|
|
275
|
-
return
|
|
276
|
-
...this._config.resourceAttributes,
|
|
277
|
-
'service.name': this._config.serviceName || 'unknown_service',
|
|
278
|
-
...(this._config.environment && { 'deployment.environment': this._config.environment }),
|
|
279
|
-
...(this._config.serviceVersion && { 'service.version': this._config.serviceVersion }),
|
|
280
|
-
'telemetry.sdk.name': this._instance.getLibraryId(),
|
|
281
|
-
'telemetry.sdk.version': this._instance.getLibraryVersion(),
|
|
282
|
-
}
|
|
304
|
+
return buildResourceAttributes(this._config, this._instance.getLibraryId(), this._instance.getLibraryVersion())
|
|
283
305
|
}
|
|
284
306
|
|
|
285
307
|
private _enqueue(entry: BufferedLogEntry): void {
|
|
@@ -290,28 +312,50 @@ export class PostHogLogs {
|
|
|
290
312
|
}
|
|
291
313
|
|
|
292
314
|
const queue = this._instance.getPersistedProperty<BufferedLogEntry[]>(PostHogPersistedProperty.LogsQueue) ?? []
|
|
293
|
-
|
|
315
|
+
// Drop the oldest only above the eviction cap, not at the flush trigger, so a
|
|
316
|
+
// burst is held while the async flush drains.
|
|
317
|
+
if (queue.length >= this._maxQueueSize) {
|
|
294
318
|
queue.shift()
|
|
319
|
+
this._evictedSinceAdvance++
|
|
295
320
|
this._logger.info('Logs queue is full, dropping oldest record.')
|
|
296
321
|
}
|
|
297
322
|
queue.push(entry)
|
|
298
323
|
this._instance.setPersistedProperty(PostHogPersistedProperty.LogsQueue, queue)
|
|
299
324
|
|
|
300
|
-
//
|
|
301
|
-
//
|
|
325
|
+
// Flush trigger: drain now rather than waiting for the timer. The queue may
|
|
326
|
+
// grow past this up to the eviction cap while the flush is in flight.
|
|
302
327
|
if (queue.length >= this._maxBufferSize) {
|
|
303
328
|
this._flushInBackground()
|
|
304
329
|
return
|
|
305
330
|
}
|
|
306
331
|
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
332
|
+
// Arm one timer at a time; re-arming within the window would push the flush out.
|
|
333
|
+
this._armFlushTimer()
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Arms the flush timer if none is pending. One-shot: the callback clears the
|
|
337
|
+
// handle so the next enqueue (or a flush that left records) schedules again.
|
|
338
|
+
private _armFlushTimer(delayMs: number = this._flushIntervalMs): void {
|
|
339
|
+
if (this._flushTimer) {
|
|
340
|
+
return
|
|
314
341
|
}
|
|
342
|
+
this._flushTimer = safeSetTimeout(() => {
|
|
343
|
+
this._flushTimer = undefined
|
|
344
|
+
this._flushInBackground()
|
|
345
|
+
}, delayMs)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Retry delay after a flush that left records: the first retry is at the base
|
|
349
|
+
// interval, then exponential backoff (capped) so a sustained outage isn't
|
|
350
|
+
// retried every interval.
|
|
351
|
+
private _nextFlushDelay(): number {
|
|
352
|
+
const exponent = Math.min(Math.max(0, this._consecutiveFlushFailures - 1), MAX_FLUSH_BACKOFF_EXPONENT)
|
|
353
|
+
return this._flushIntervalMs * 2 ** exponent
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private _hasQueuedRecords(): boolean {
|
|
357
|
+
const queue = this._instance.getPersistedProperty<BufferedLogEntry[]>(PostHogPersistedProperty.LogsQueue)
|
|
358
|
+
return !!queue && queue.length > 0
|
|
315
359
|
}
|
|
316
360
|
|
|
317
361
|
/**
|
|
@@ -371,9 +415,24 @@ export class PostHogLogs {
|
|
|
371
415
|
}
|
|
372
416
|
|
|
373
417
|
private _flushInBackground(): void {
|
|
374
|
-
void this.flush()
|
|
375
|
-
|
|
376
|
-
|
|
418
|
+
void this.flush()
|
|
419
|
+
.then(
|
|
420
|
+
() => {
|
|
421
|
+
this._consecutiveFlushFailures = 0
|
|
422
|
+
},
|
|
423
|
+
(err) => {
|
|
424
|
+
this._consecutiveFlushFailures++
|
|
425
|
+
this._logger.error('PostHog logs flush failed:', err)
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
.finally(() => {
|
|
429
|
+
// Records remaining (transient failure or mid-flush captures) would otherwise
|
|
430
|
+
// sit undelivered on a quiet page; re-arm so the timer retries them, backing
|
|
431
|
+
// off on consecutive failures.
|
|
432
|
+
if (!this._instance.isDisabled && this._hasQueuedRecords()) {
|
|
433
|
+
this._armFlushTimer(this._nextFlushDelay())
|
|
434
|
+
}
|
|
435
|
+
})
|
|
377
436
|
}
|
|
378
437
|
|
|
379
438
|
private _clearFlushTimer(): void {
|
package/src/logs/logs-utils.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
OtlpSeverityEntry,
|
|
10
10
|
OtlpSeverityText,
|
|
11
11
|
} from '@posthog/types'
|
|
12
|
-
import type { LogSdkContext } from './types'
|
|
12
|
+
import type { LogSdkContext, ResolvedPostHogLogsConfig } from './types'
|
|
13
13
|
import { isArray, isBoolean, isNull, isUndefined } from '../utils'
|
|
14
14
|
|
|
15
15
|
// ============================================================================
|
|
@@ -168,6 +168,35 @@ export function buildOtlpLogRecord(options: CaptureLogOptions, sdkContext: LogSd
|
|
|
168
168
|
// OTLP envelope construction
|
|
169
169
|
// ============================================================================
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* OTLP resource attributes for every batch, shared by the core flush path and
|
|
173
|
+
* SDK-specific paths that bypass it (e.g. the browser's synchronous sendBeacon
|
|
174
|
+
* drain). Having one builder keeps those paths from drifting.
|
|
175
|
+
*
|
|
176
|
+
* Layout: user `resourceAttributes` spread first, then SDK-controlled keys
|
|
177
|
+
* (`service.name`, `deployment.environment`, `service.version`,
|
|
178
|
+
* `telemetry.sdk.*`) layered on top so a stray user key can't clobber the
|
|
179
|
+
* ingestion-attribution keys. The dedicated `serviceName` / `environment` /
|
|
180
|
+
* `serviceVersion` config fields are the supported way to override the first
|
|
181
|
+
* three; each SDK resolves its own `service.name` default before this point, so
|
|
182
|
+
* the `unknown_service` fallback here only fires if a config slips through with
|
|
183
|
+
* an empty `serviceName`.
|
|
184
|
+
*/
|
|
185
|
+
export function buildResourceAttributes(
|
|
186
|
+
config: ResolvedPostHogLogsConfig,
|
|
187
|
+
scopeName: string,
|
|
188
|
+
scopeVersion: string
|
|
189
|
+
): Record<string, LogAttributeValue> {
|
|
190
|
+
return {
|
|
191
|
+
...config.resourceAttributes,
|
|
192
|
+
'service.name': config.serviceName || 'unknown_service',
|
|
193
|
+
...(config.environment && { 'deployment.environment': config.environment }),
|
|
194
|
+
...(config.serviceVersion && { 'service.version': config.serviceVersion }),
|
|
195
|
+
'telemetry.sdk.name': scopeName,
|
|
196
|
+
'telemetry.sdk.version': scopeVersion,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
171
200
|
/**
|
|
172
201
|
* Wraps a list of records in the OTLP `resourceLogs` envelope.
|
|
173
202
|
*
|
package/src/logs/types.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type {
|
|
|
11
11
|
OtlpKeyValue,
|
|
12
12
|
OtlpLogRecord,
|
|
13
13
|
OtlpLogsPayload,
|
|
14
|
+
BeforeSendLogFn,
|
|
14
15
|
} from '@posthog/types'
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -39,44 +40,34 @@ export interface LogSdkContext {
|
|
|
39
40
|
import type { Logger as CaptureLoggerType } from '@posthog/types'
|
|
40
41
|
export type CaptureLogger = CaptureLoggerType
|
|
41
42
|
|
|
42
|
-
import type {
|
|
43
|
+
import type {
|
|
44
|
+
LogAttributeValue,
|
|
45
|
+
CaptureLogOptions,
|
|
46
|
+
OtlpLogRecord,
|
|
47
|
+
OtlpLogsPayload,
|
|
48
|
+
BeforeSendLogFn,
|
|
49
|
+
} from '@posthog/types'
|
|
50
|
+
import type { PostHogPersistedProperty } from '../types'
|
|
51
|
+
import type { SendLogsBatchOutcome } from '../posthog-core-stateless'
|
|
43
52
|
|
|
44
53
|
export interface BufferedLogEntry {
|
|
45
54
|
record: OtlpLogRecord
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* Configure as a single fn or an array. Arrays form a left-to-right chain:
|
|
54
|
-
* each fn receives the previous fn's return value. A `null` from any link
|
|
55
|
-
* short-circuits the chain and drops the record.
|
|
56
|
-
*
|
|
57
|
-
* Runs *before* the rate cap so dropped records don't consume the
|
|
58
|
-
* per-interval budget. Throwing fns are logged and skipped — the chain
|
|
59
|
-
* continues with the previous return value, so a buggy filter degrades to a
|
|
60
|
-
* no-op rather than crashing `captureLog()`.
|
|
61
|
-
*
|
|
62
|
-
* @example Redact secrets from log bodies
|
|
63
|
-
* ```ts
|
|
64
|
-
* logs: {
|
|
65
|
-
* beforeSend: (record) => ({
|
|
66
|
-
* ...record,
|
|
67
|
-
* body: record.body.replace(/api_key=\S+/g, 'api_key=[REDACTED]'),
|
|
68
|
-
* }),
|
|
69
|
-
* }
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* @example Drop noisy debug logs in production
|
|
73
|
-
* ```ts
|
|
74
|
-
* logs: {
|
|
75
|
-
* beforeSend: (record) => (record.level === 'debug' ? null : record),
|
|
76
|
-
* }
|
|
77
|
-
* ```
|
|
58
|
+
* The minimal host surface `PostHogLogs` depends on. `PostHogCoreStateless`
|
|
59
|
+
* satisfies it structurally (mobile/node); the browser supplies an adapter
|
|
60
|
+
* backed by its own persistence and request layer.
|
|
78
61
|
*/
|
|
79
|
-
export
|
|
62
|
+
export interface LogsHost {
|
|
63
|
+
readonly isDisabled: boolean
|
|
64
|
+
readonly optedOut: boolean
|
|
65
|
+
getPersistedProperty<T>(key: PostHogPersistedProperty): T | undefined
|
|
66
|
+
setPersistedProperty<T>(key: PostHogPersistedProperty, value: T | null): void
|
|
67
|
+
_sendLogsBatch(payload: OtlpLogsPayload): Promise<SendLogsBatchOutcome>
|
|
68
|
+
getLibraryId(): string
|
|
69
|
+
getLibraryVersion(): string
|
|
70
|
+
}
|
|
80
71
|
|
|
81
72
|
/**
|
|
82
73
|
* Configuration for the logs feature on `new PostHog(key, { logs: ... })`.
|
|
@@ -87,7 +78,7 @@ export interface PostHogLogsConfig {
|
|
|
87
78
|
/**
|
|
88
79
|
* Service name attached to every record as the OTLP `service.name`
|
|
89
80
|
* resource attribute. Used by the Logs UI for filtering / grouping.
|
|
90
|
-
*
|
|
81
|
+
* Defaults to `'unknown_service'` when unset.
|
|
91
82
|
*/
|
|
92
83
|
serviceName?: string
|
|
93
84
|
|
|
@@ -121,11 +112,11 @@ export interface PostHogLogsConfig {
|
|
|
121
112
|
flushIntervalMs?: number
|
|
122
113
|
|
|
123
114
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
115
|
+
* Number of buffered records that triggers an immediate flush. Records also
|
|
116
|
+
* flush on the periodic interval and on `shutdown()`. The queue can grow past
|
|
117
|
+
* this while an async flush is in flight (e.g. during a synchronous burst); a
|
|
118
|
+
* separate, larger memory backstop evicts the oldest only once the queue
|
|
119
|
+
* exceeds the per-interval rate cap. Default: 100.
|
|
129
120
|
*/
|
|
130
121
|
maxBufferSize?: number
|
|
131
122
|
|
|
@@ -182,6 +173,10 @@ export interface PostHogLogsConfig {
|
|
|
182
173
|
// Flat names internally — public API uses `rateCap: { maxLogs, windowMs }`.
|
|
183
174
|
export interface ResolvedPostHogLogsConfig extends Omit<PostHogLogsConfig, 'rateCap'> {
|
|
184
175
|
maxBufferSize: number
|
|
176
|
+
// Eviction cap: the queue drops the oldest record once it exceeds this. Separate
|
|
177
|
+
// from `maxBufferSize` (the flush trigger) so a burst is held, not evicted, while
|
|
178
|
+
// the async flush drains. Defaults to `maxBufferSize` when unset.
|
|
179
|
+
maxQueueSize?: number
|
|
185
180
|
flushIntervalMs: number
|
|
186
181
|
maxBatchRecordsPerPost: number
|
|
187
182
|
rateCapWindowMs: number
|
package/src/posthog-core.ts
CHANGED
|
@@ -1052,6 +1052,9 @@ export abstract class PostHogCore extends PostHogCoreStateless {
|
|
|
1052
1052
|
return result?.variant ?? result?.enabled
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
|
+
/**
|
|
1056
|
+
* @deprecated Use `getFeatureFlagResult()` instead, which returns the flag value and payload from a single evaluation.
|
|
1057
|
+
*/
|
|
1055
1058
|
getFeatureFlagPayload(key: string): JsonType | undefined {
|
|
1056
1059
|
const result = this._getFeatureFlagResult(key, { missingFlagBehavior: 'getFeatureFlagPayload', sendEvent: false })
|
|
1057
1060
|
return result?.payload
|