@redthreadlabs/tracelog-client 1.5.0 → 1.6.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.
@@ -1,18 +1,18 @@
1
1
  import { EventBuilder } from './EventBuilder';
2
- import { JsonValue, LogClientOptions, TimerToken } from './types';
2
+ import { JsonValue, LogClientOptions, PerfToken } from './types';
3
3
  export declare class LogClient {
4
4
  private _opts;
5
5
  private _eventBuffer;
6
- private _timerBuffer;
7
- private _activeTimers;
8
- private _flushTimer;
9
- private _persistTimer;
6
+ private _perfBuffer;
7
+ private _activePerfs;
8
+ private _flushHandle;
9
+ private _persistHandle;
10
10
  private _disposed;
11
11
  private _flushing;
12
12
  constructor(opts: LogClientOptions);
13
13
  event(type?: string): EventBuilder;
14
- startTimer(name: string, parent?: TimerToken): TimerToken;
15
- endTimer(token: TimerToken, context?: Record<string, JsonValue>): void;
14
+ startPerf(name: string, parent?: PerfToken): PerfToken;
15
+ endPerf(token: PerfToken, context?: Record<string, JsonValue>): void;
16
16
  flush(): Promise<void>;
17
17
  dispose(): void;
18
18
  private _enqueueEvent;
package/dist/LogClient.js CHANGED
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LogClient = void 0;
4
4
  const EventBuilder_1 = require("./EventBuilder");
5
5
  const util_1 = require("./util");
6
- // Default constants (matching the original AppLogRecorder)
7
- const DEFAULT_FLUSH_INTERVAL_MS = 5000;
6
+ // Defaults (all overridable via LogClientOptions)
7
+ const DEFAULT_FLUSH_CADENCE_MS = 5000;
8
8
  const DEFAULT_MAX_BUFFER_SIZE = 100;
9
9
  const DEFAULT_MAX_CHUNK_SIZE = 50;
10
10
  const DEFAULT_MAX_CHUNK_BYTES = 512 * 1024;
@@ -15,26 +15,26 @@ const PERSIST_DEBOUNCE_MS = 100;
15
15
  class LogClient {
16
16
  constructor(opts) {
17
17
  this._eventBuffer = [];
18
- this._timerBuffer = [];
19
- this._activeTimers = new Map();
20
- this._flushTimer = null;
21
- this._persistTimer = null;
18
+ this._perfBuffer = [];
19
+ this._activePerfs = new Map();
20
+ this._flushHandle = null;
21
+ this._persistHandle = null;
22
22
  this._disposed = false;
23
23
  this._flushing = false;
24
24
  this._opts = opts;
25
25
  this._loadPersistedLogs();
26
- this._flushTimer = setInterval(() => this.flush(), opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS);
26
+ this._flushHandle = setInterval(() => this.flush(), opts.flushCadenceMs ?? DEFAULT_FLUSH_CADENCE_MS);
27
27
  }
28
28
  // ---- Fluent event builder ----
29
29
  event(type = 'client-log') {
30
30
  return new EventBuilder_1.EventBuilder((evt) => this._enqueueEvent(evt), type);
31
31
  }
32
32
  // ---- Perf timing ----
33
- startTimer(name, parent) {
33
+ startPerf(name, parent) {
34
34
  const id = randomHex(16);
35
35
  const trace_id = parent ? parent.trace_id : randomHex(32);
36
36
  const root_id = parent ? parent.root_id : id;
37
- const token = { id, trace_id, root_id, key: name };
37
+ const token = { id, trace_id, root_id, name };
38
38
  const active = {
39
39
  token,
40
40
  startTime: now(),
@@ -42,33 +42,33 @@ class LogClient {
42
42
  parentToken: parent,
43
43
  children: [],
44
44
  };
45
- this._activeTimers.set(id, active);
45
+ this._activePerfs.set(id, active);
46
46
  // Register as child of parent
47
47
  if (parent) {
48
- const parentActive = this._activeTimers.get(parent.id);
48
+ const parentActive = this._activePerfs.get(parent.id);
49
49
  if (parentActive) {
50
50
  parentActive.children.push(id);
51
51
  }
52
52
  }
53
53
  return token;
54
54
  }
55
- endTimer(token, context) {
56
- const active = this._activeTimers.get(token.id);
55
+ endPerf(token, context) {
56
+ const active = this._activePerfs.get(token.id);
57
57
  if (!active)
58
58
  return;
59
59
  const duration = now() - active.startTime;
60
60
  // Auto-close children that haven't been ended yet
61
61
  for (const childId of active.children) {
62
- const childActive = this._activeTimers.get(childId);
62
+ const childActive = this._activePerfs.get(childId);
63
63
  if (childActive) {
64
- this.endTimer(childActive.token);
64
+ this.endPerf(childActive.token);
65
65
  }
66
66
  }
67
- const timer = {
67
+ const perf = {
68
68
  id: token.id,
69
69
  trace_id: token.trace_id,
70
70
  root_id: token.root_id,
71
- name: token.key,
71
+ name: token.name,
72
72
  type: 'client-perf',
73
73
  timestamp: Math.round(active.startTime),
74
74
  duration: Math.round(duration),
@@ -76,16 +76,16 @@ class LogClient {
76
76
  tz_offset: active.tzOffset,
77
77
  };
78
78
  if (active.parentToken) {
79
- timer.parent_id = active.parentToken.id;
79
+ perf.parent_id = active.parentToken.id;
80
80
  }
81
81
  if (context && Object.keys(context).length > 0) {
82
- timer.context = { tags: context };
82
+ perf.context = { tags: context };
83
83
  }
84
- this._timerBuffer.push(timer);
85
- this._activeTimers.delete(token.id);
84
+ this._perfBuffer.push(perf);
85
+ this._activePerfs.delete(token.id);
86
86
  this._schedulePersist();
87
87
  // Force flush if buffer is getting large
88
- if (this._timerBuffer.length + this._eventBuffer.length >= (this._opts.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE)) {
88
+ if (this._perfBuffer.length + this._eventBuffer.length >= (this._opts.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE)) {
89
89
  this.flush();
90
90
  }
91
91
  }
@@ -93,13 +93,13 @@ class LogClient {
93
93
  async flush() {
94
94
  if (this._disposed || this._flushing)
95
95
  return;
96
- if (this._eventBuffer.length === 0 && this._timerBuffer.length === 0)
96
+ if (this._eventBuffer.length === 0 && this._perfBuffer.length === 0)
97
97
  return;
98
98
  this._flushing = true;
99
99
  try {
100
100
  const events = this._eventBuffer.splice(0);
101
- const timers = this._timerBuffer.splice(0);
102
- await this._sendInChunks(events, timers);
101
+ const perfs = this._perfBuffer.splice(0);
102
+ await this._sendInChunks(events, perfs);
103
103
  }
104
104
  finally {
105
105
  this._flushing = false;
@@ -110,13 +110,13 @@ class LogClient {
110
110
  if (this._disposed)
111
111
  return;
112
112
  this._disposed = true;
113
- if (this._flushTimer) {
114
- clearInterval(this._flushTimer);
115
- this._flushTimer = null;
113
+ if (this._flushHandle) {
114
+ clearInterval(this._flushHandle);
115
+ this._flushHandle = null;
116
116
  }
117
- if (this._persistTimer) {
118
- clearTimeout(this._persistTimer);
119
- this._persistTimer = null;
117
+ if (this._persistHandle) {
118
+ clearTimeout(this._persistHandle);
119
+ this._persistHandle = null;
120
120
  }
121
121
  // Persist anything remaining
122
122
  this._persistNow();
@@ -132,23 +132,23 @@ class LogClient {
132
132
  }
133
133
  }
134
134
  // ---- Internal: chunked sending ----
135
- async _sendInChunks(events, timers) {
135
+ async _sendInChunks(events, perfs) {
136
136
  const maxChunkSize = this._opts.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;
137
137
  const maxChunkBytes = this._opts.maxChunkBytes ?? DEFAULT_MAX_CHUNK_BYTES;
138
- // Combine events and timers into chunks that respect size limits
138
+ // Combine events and perfs into chunks that respect size limits
139
139
  let eventIdx = 0;
140
- let timerIdx = 0;
140
+ let perfIdx = 0;
141
141
  let isFirstChunk = true;
142
- while (eventIdx < events.length || timerIdx < timers.length) {
142
+ while (eventIdx < events.length || perfIdx < perfs.length) {
143
143
  if (!isFirstChunk) {
144
144
  await delay(INTER_CHUNK_DELAY_MS);
145
145
  }
146
146
  isFirstChunk = false;
147
147
  const chunkEvents = [];
148
- const chunkTimers = [];
148
+ const chunkPerfs = [];
149
149
  let estimatedBytes = 200; // base overhead for batch envelope
150
150
  // Fill chunk with events
151
- while (eventIdx < events.length && chunkEvents.length + chunkTimers.length < maxChunkSize) {
151
+ while (eventIdx < events.length && chunkEvents.length + chunkPerfs.length < maxChunkSize) {
152
152
  const itemBytes = estimateJsonSize(events[eventIdx]);
153
153
  if (estimatedBytes + itemBytes > maxChunkBytes && chunkEvents.length > 0)
154
154
  break;
@@ -156,24 +156,24 @@ class LogClient {
156
156
  estimatedBytes += itemBytes;
157
157
  eventIdx++;
158
158
  }
159
- // Fill chunk with timers
160
- while (timerIdx < timers.length && chunkEvents.length + chunkTimers.length < maxChunkSize) {
161
- const itemBytes = estimateJsonSize(timers[timerIdx]);
162
- if (estimatedBytes + itemBytes > maxChunkBytes && (chunkEvents.length + chunkTimers.length) > 0)
159
+ // Fill chunk with perfs
160
+ while (perfIdx < perfs.length && chunkEvents.length + chunkPerfs.length < maxChunkSize) {
161
+ const itemBytes = estimateJsonSize(perfs[perfIdx]);
162
+ if (estimatedBytes + itemBytes > maxChunkBytes && (chunkEvents.length + chunkPerfs.length) > 0)
163
163
  break;
164
- chunkTimers.push(timers[timerIdx]);
164
+ chunkPerfs.push(perfs[perfIdx]);
165
165
  estimatedBytes += itemBytes;
166
- timerIdx++;
166
+ perfIdx++;
167
167
  }
168
- if (chunkEvents.length === 0 && chunkTimers.length === 0)
168
+ if (chunkEvents.length === 0 && chunkPerfs.length === 0)
169
169
  break;
170
- await this._sendChunkWithRetry(chunkEvents, chunkTimers);
170
+ await this._sendChunkWithRetry(chunkEvents, chunkPerfs);
171
171
  }
172
172
  }
173
- async _sendChunkWithRetry(events, timers) {
173
+ async _sendChunkWithRetry(events, perfs) {
174
174
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
175
175
  try {
176
- await this._sendChunk(events, timers);
176
+ await this._sendChunk(events, perfs);
177
177
  return;
178
178
  }
179
179
  catch (err) {
@@ -183,17 +183,17 @@ class LogClient {
183
183
  else {
184
184
  // Max retries exceeded — put items back for persistence
185
185
  this._eventBuffer.push(...events);
186
- this._timerBuffer.push(...timers);
186
+ this._perfBuffer.push(...perfs);
187
187
  this._schedulePersist();
188
188
  }
189
189
  }
190
190
  }
191
191
  }
192
- async _sendChunk(events, timers) {
192
+ async _sendChunk(events, perfs) {
193
193
  const batch = {
194
194
  client: this._opts.client,
195
195
  events,
196
- timers,
196
+ perfs,
197
197
  };
198
198
  const userId = this._opts.getUserId?.();
199
199
  const sessionRef = this._opts.getSessionRef?.();
@@ -219,23 +219,23 @@ class LogClient {
219
219
  }
220
220
  // ---- Internal: persistence ----
221
221
  _schedulePersist() {
222
- if (this._persistTimer || !this._opts.persistLogs)
222
+ if (this._persistHandle || !this._opts.persistLogs)
223
223
  return;
224
- this._persistTimer = setTimeout(() => {
225
- this._persistTimer = null;
224
+ this._persistHandle = setTimeout(() => {
225
+ this._persistHandle = null;
226
226
  this._persistNow();
227
227
  }, PERSIST_DEBOUNCE_MS);
228
228
  }
229
229
  _persistNow() {
230
230
  if (!this._opts.persistLogs)
231
231
  return;
232
- if (this._eventBuffer.length === 0 && this._timerBuffer.length === 0) {
232
+ if (this._eventBuffer.length === 0 && this._perfBuffer.length === 0) {
233
233
  this._opts.persistLogs('').catch(() => { });
234
234
  return;
235
235
  }
236
236
  const data = JSON.stringify({
237
237
  events: this._eventBuffer,
238
- timers: this._timerBuffer,
238
+ perfs: this._perfBuffer,
239
239
  });
240
240
  this._opts.persistLogs(data).catch(() => { });
241
241
  }
@@ -250,8 +250,8 @@ class LogClient {
250
250
  if (Array.isArray(parsed.events)) {
251
251
  this._eventBuffer.push(...parsed.events);
252
252
  }
253
- if (Array.isArray(parsed.timers)) {
254
- this._timerBuffer.push(...parsed.timers);
253
+ if (Array.isArray(parsed.perfs)) {
254
+ this._perfBuffer.push(...parsed.perfs);
255
255
  }
256
256
  // Clear persisted data now that it's loaded
257
257
  this._opts.persistLogs?.('').catch(() => { });
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { LogClient } from './LogClient';
2
2
  export { EventBuilder } from './EventBuilder';
3
- export { LogBatch, LogEventItem, TimerItem, ClientInfo, TimerToken, LogClientOptions, LogLevel, JsonValue, } from './types';
3
+ export { LogBatch, LogEventItem, LogPerfItem, ClientInfo, PerfToken, LogClientOptions, LogLevel, JsonValue, } from './types';
package/dist/types.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import type { ClientInfo } from '@redthreadlabs/tracelog-schema';
2
- export type { JsonValue, LogLevel, LogBatch, LogEventItem, TimerItem, ClientInfo, } from '@redthreadlabs/tracelog-schema';
3
- export interface TimerToken {
4
- /** 16-char hex ID for this timer */
2
+ export type { JsonValue, LogLevel, LogBatch, LogEventItem, LogPerfItem, ClientInfo, } from '@redthreadlabs/tracelog-schema';
3
+ export interface PerfToken {
4
+ /** 16-char hex ID for this perf */
5
5
  id: string;
6
- /** 32-char hex trace ID (shared across the entire timer tree) */
6
+ /** 32-char hex trace ID (shared across the entire perf tree) */
7
7
  trace_id: string;
8
- /** ID of the root timer in this trace */
8
+ /** ID of the root perf in this trace */
9
9
  root_id: string;
10
- /** Key/name of the operation being timed */
11
- key: string;
10
+ /** Name of the operation being measured */
11
+ name: string;
12
12
  }
13
13
  export interface LogClientOptions {
14
14
  /** Server endpoint URL for log submission */
@@ -23,8 +23,8 @@ export interface LogClientOptions {
23
23
  getSessionRef?: () => string | undefined;
24
24
  /** Returns native device identifier */
25
25
  getDeviceId?: () => string | undefined;
26
- /** Flush interval in ms. Default: 5000 */
27
- flushIntervalMs?: number;
26
+ /** Flush cadence in ms. Default: 5000 */
27
+ flushCadenceMs?: number;
28
28
  /** Max events buffered before forced flush. Default: 100 */
29
29
  maxBufferSize?: number;
30
30
  /** Max events per HTTP request. Default: 50 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redthreadlabs/tracelog-client",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Lightweight logging client for tracelog — works in React Native and browsers",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -21,6 +21,6 @@
21
21
  "typescript": "latest"
22
22
  },
23
23
  "dependencies": {
24
- "@redthreadlabs/tracelog-schema": "^0.1.0"
24
+ "@redthreadlabs/tracelog-schema": "^0.3.0"
25
25
  }
26
26
  }