@redthreadlabs/tracelog-client 1.4.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.
- package/dist/EventBuilder.js +2 -0
- package/dist/LogClient.d.ts +7 -7
- package/dist/LogClient.js +60 -57
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +9 -89
- package/dist/types.js +0 -1
- package/dist/util.d.ts +8 -0
- package/dist/util.js +13 -0
- package/package.json +4 -1
package/dist/EventBuilder.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EventBuilder = void 0;
|
|
4
|
+
const util_1 = require("./util");
|
|
4
5
|
class EventBuilder {
|
|
5
6
|
constructor(enqueue, type) {
|
|
6
7
|
this._level = 'info';
|
|
@@ -82,6 +83,7 @@ class EventBuilder {
|
|
|
82
83
|
timestamp: Date.now(),
|
|
83
84
|
level: this._level,
|
|
84
85
|
message: this._message,
|
|
86
|
+
tz_offset: (0, util_1.tzOffsetMinutes)(),
|
|
85
87
|
};
|
|
86
88
|
if (this._duration !== undefined)
|
|
87
89
|
event.duration = this._duration;
|
package/dist/LogClient.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { EventBuilder } from './EventBuilder';
|
|
2
|
-
import { JsonValue, LogClientOptions,
|
|
2
|
+
import { JsonValue, LogClientOptions, PerfToken } from './types';
|
|
3
3
|
export declare class LogClient {
|
|
4
4
|
private _opts;
|
|
5
5
|
private _eventBuffer;
|
|
6
|
-
private
|
|
7
|
-
private
|
|
8
|
-
private
|
|
9
|
-
private
|
|
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
|
-
|
|
15
|
-
|
|
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
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LogClient = void 0;
|
|
4
4
|
const EventBuilder_1 = require("./EventBuilder");
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const util_1 = require("./util");
|
|
6
|
+
// Defaults (all overridable via LogClientOptions)
|
|
7
|
+
const DEFAULT_FLUSH_CADENCE_MS = 5000;
|
|
7
8
|
const DEFAULT_MAX_BUFFER_SIZE = 100;
|
|
8
9
|
const DEFAULT_MAX_CHUNK_SIZE = 50;
|
|
9
10
|
const DEFAULT_MAX_CHUNK_BYTES = 512 * 1024;
|
|
@@ -14,75 +15,77 @@ const PERSIST_DEBOUNCE_MS = 100;
|
|
|
14
15
|
class LogClient {
|
|
15
16
|
constructor(opts) {
|
|
16
17
|
this._eventBuffer = [];
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
18
|
+
this._perfBuffer = [];
|
|
19
|
+
this._activePerfs = new Map();
|
|
20
|
+
this._flushHandle = null;
|
|
21
|
+
this._persistHandle = null;
|
|
21
22
|
this._disposed = false;
|
|
22
23
|
this._flushing = false;
|
|
23
24
|
this._opts = opts;
|
|
24
25
|
this._loadPersistedLogs();
|
|
25
|
-
this.
|
|
26
|
+
this._flushHandle = setInterval(() => this.flush(), opts.flushCadenceMs ?? DEFAULT_FLUSH_CADENCE_MS);
|
|
26
27
|
}
|
|
27
28
|
// ---- Fluent event builder ----
|
|
28
29
|
event(type = 'client-log') {
|
|
29
30
|
return new EventBuilder_1.EventBuilder((evt) => this._enqueueEvent(evt), type);
|
|
30
31
|
}
|
|
31
32
|
// ---- Perf timing ----
|
|
32
|
-
|
|
33
|
+
startPerf(name, parent) {
|
|
33
34
|
const id = randomHex(16);
|
|
34
35
|
const trace_id = parent ? parent.trace_id : randomHex(32);
|
|
35
36
|
const root_id = parent ? parent.root_id : id;
|
|
36
|
-
const token = { id, trace_id, root_id,
|
|
37
|
+
const token = { id, trace_id, root_id, name };
|
|
37
38
|
const active = {
|
|
38
39
|
token,
|
|
39
40
|
startTime: now(),
|
|
41
|
+
tzOffset: (0, util_1.tzOffsetMinutes)(),
|
|
40
42
|
parentToken: parent,
|
|
41
43
|
children: [],
|
|
42
44
|
};
|
|
43
|
-
this.
|
|
45
|
+
this._activePerfs.set(id, active);
|
|
44
46
|
// Register as child of parent
|
|
45
47
|
if (parent) {
|
|
46
|
-
const parentActive = this.
|
|
48
|
+
const parentActive = this._activePerfs.get(parent.id);
|
|
47
49
|
if (parentActive) {
|
|
48
50
|
parentActive.children.push(id);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
return token;
|
|
52
54
|
}
|
|
53
|
-
|
|
54
|
-
const active = this.
|
|
55
|
+
endPerf(token, context) {
|
|
56
|
+
const active = this._activePerfs.get(token.id);
|
|
55
57
|
if (!active)
|
|
56
58
|
return;
|
|
57
59
|
const duration = now() - active.startTime;
|
|
58
60
|
// Auto-close children that haven't been ended yet
|
|
59
61
|
for (const childId of active.children) {
|
|
60
|
-
const childActive = this.
|
|
62
|
+
const childActive = this._activePerfs.get(childId);
|
|
61
63
|
if (childActive) {
|
|
62
|
-
this.
|
|
64
|
+
this.endPerf(childActive.token);
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
|
-
const
|
|
67
|
+
const perf = {
|
|
66
68
|
id: token.id,
|
|
67
69
|
trace_id: token.trace_id,
|
|
68
70
|
root_id: token.root_id,
|
|
69
|
-
name: token.
|
|
71
|
+
name: token.name,
|
|
70
72
|
type: 'client-perf',
|
|
71
73
|
timestamp: Math.round(active.startTime),
|
|
72
74
|
duration: Math.round(duration),
|
|
73
75
|
outcome: 'success',
|
|
76
|
+
tz_offset: active.tzOffset,
|
|
74
77
|
};
|
|
75
78
|
if (active.parentToken) {
|
|
76
|
-
|
|
79
|
+
perf.parent_id = active.parentToken.id;
|
|
77
80
|
}
|
|
78
81
|
if (context && Object.keys(context).length > 0) {
|
|
79
|
-
|
|
82
|
+
perf.context = { tags: context };
|
|
80
83
|
}
|
|
81
|
-
this.
|
|
82
|
-
this.
|
|
84
|
+
this._perfBuffer.push(perf);
|
|
85
|
+
this._activePerfs.delete(token.id);
|
|
83
86
|
this._schedulePersist();
|
|
84
87
|
// Force flush if buffer is getting large
|
|
85
|
-
if (this.
|
|
88
|
+
if (this._perfBuffer.length + this._eventBuffer.length >= (this._opts.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE)) {
|
|
86
89
|
this.flush();
|
|
87
90
|
}
|
|
88
91
|
}
|
|
@@ -90,13 +93,13 @@ class LogClient {
|
|
|
90
93
|
async flush() {
|
|
91
94
|
if (this._disposed || this._flushing)
|
|
92
95
|
return;
|
|
93
|
-
if (this._eventBuffer.length === 0 && this.
|
|
96
|
+
if (this._eventBuffer.length === 0 && this._perfBuffer.length === 0)
|
|
94
97
|
return;
|
|
95
98
|
this._flushing = true;
|
|
96
99
|
try {
|
|
97
100
|
const events = this._eventBuffer.splice(0);
|
|
98
|
-
const
|
|
99
|
-
await this._sendInChunks(events,
|
|
101
|
+
const perfs = this._perfBuffer.splice(0);
|
|
102
|
+
await this._sendInChunks(events, perfs);
|
|
100
103
|
}
|
|
101
104
|
finally {
|
|
102
105
|
this._flushing = false;
|
|
@@ -107,13 +110,13 @@ class LogClient {
|
|
|
107
110
|
if (this._disposed)
|
|
108
111
|
return;
|
|
109
112
|
this._disposed = true;
|
|
110
|
-
if (this.
|
|
111
|
-
clearInterval(this.
|
|
112
|
-
this.
|
|
113
|
+
if (this._flushHandle) {
|
|
114
|
+
clearInterval(this._flushHandle);
|
|
115
|
+
this._flushHandle = null;
|
|
113
116
|
}
|
|
114
|
-
if (this.
|
|
115
|
-
clearTimeout(this.
|
|
116
|
-
this.
|
|
117
|
+
if (this._persistHandle) {
|
|
118
|
+
clearTimeout(this._persistHandle);
|
|
119
|
+
this._persistHandle = null;
|
|
117
120
|
}
|
|
118
121
|
// Persist anything remaining
|
|
119
122
|
this._persistNow();
|
|
@@ -129,23 +132,23 @@ class LogClient {
|
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
// ---- Internal: chunked sending ----
|
|
132
|
-
async _sendInChunks(events,
|
|
135
|
+
async _sendInChunks(events, perfs) {
|
|
133
136
|
const maxChunkSize = this._opts.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;
|
|
134
137
|
const maxChunkBytes = this._opts.maxChunkBytes ?? DEFAULT_MAX_CHUNK_BYTES;
|
|
135
|
-
// Combine events and
|
|
138
|
+
// Combine events and perfs into chunks that respect size limits
|
|
136
139
|
let eventIdx = 0;
|
|
137
|
-
let
|
|
140
|
+
let perfIdx = 0;
|
|
138
141
|
let isFirstChunk = true;
|
|
139
|
-
while (eventIdx < events.length ||
|
|
142
|
+
while (eventIdx < events.length || perfIdx < perfs.length) {
|
|
140
143
|
if (!isFirstChunk) {
|
|
141
144
|
await delay(INTER_CHUNK_DELAY_MS);
|
|
142
145
|
}
|
|
143
146
|
isFirstChunk = false;
|
|
144
147
|
const chunkEvents = [];
|
|
145
|
-
const
|
|
148
|
+
const chunkPerfs = [];
|
|
146
149
|
let estimatedBytes = 200; // base overhead for batch envelope
|
|
147
150
|
// Fill chunk with events
|
|
148
|
-
while (eventIdx < events.length && chunkEvents.length +
|
|
151
|
+
while (eventIdx < events.length && chunkEvents.length + chunkPerfs.length < maxChunkSize) {
|
|
149
152
|
const itemBytes = estimateJsonSize(events[eventIdx]);
|
|
150
153
|
if (estimatedBytes + itemBytes > maxChunkBytes && chunkEvents.length > 0)
|
|
151
154
|
break;
|
|
@@ -153,24 +156,24 @@ class LogClient {
|
|
|
153
156
|
estimatedBytes += itemBytes;
|
|
154
157
|
eventIdx++;
|
|
155
158
|
}
|
|
156
|
-
// Fill chunk with
|
|
157
|
-
while (
|
|
158
|
-
const itemBytes = estimateJsonSize(
|
|
159
|
-
if (estimatedBytes + itemBytes > maxChunkBytes && (chunkEvents.length +
|
|
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)
|
|
160
163
|
break;
|
|
161
|
-
|
|
164
|
+
chunkPerfs.push(perfs[perfIdx]);
|
|
162
165
|
estimatedBytes += itemBytes;
|
|
163
|
-
|
|
166
|
+
perfIdx++;
|
|
164
167
|
}
|
|
165
|
-
if (chunkEvents.length === 0 &&
|
|
168
|
+
if (chunkEvents.length === 0 && chunkPerfs.length === 0)
|
|
166
169
|
break;
|
|
167
|
-
await this._sendChunkWithRetry(chunkEvents,
|
|
170
|
+
await this._sendChunkWithRetry(chunkEvents, chunkPerfs);
|
|
168
171
|
}
|
|
169
172
|
}
|
|
170
|
-
async _sendChunkWithRetry(events,
|
|
173
|
+
async _sendChunkWithRetry(events, perfs) {
|
|
171
174
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
172
175
|
try {
|
|
173
|
-
await this._sendChunk(events,
|
|
176
|
+
await this._sendChunk(events, perfs);
|
|
174
177
|
return;
|
|
175
178
|
}
|
|
176
179
|
catch (err) {
|
|
@@ -180,17 +183,17 @@ class LogClient {
|
|
|
180
183
|
else {
|
|
181
184
|
// Max retries exceeded — put items back for persistence
|
|
182
185
|
this._eventBuffer.push(...events);
|
|
183
|
-
this.
|
|
186
|
+
this._perfBuffer.push(...perfs);
|
|
184
187
|
this._schedulePersist();
|
|
185
188
|
}
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
|
-
async _sendChunk(events,
|
|
192
|
+
async _sendChunk(events, perfs) {
|
|
190
193
|
const batch = {
|
|
191
194
|
client: this._opts.client,
|
|
192
195
|
events,
|
|
193
|
-
|
|
196
|
+
perfs,
|
|
194
197
|
};
|
|
195
198
|
const userId = this._opts.getUserId?.();
|
|
196
199
|
const sessionRef = this._opts.getSessionRef?.();
|
|
@@ -216,23 +219,23 @@ class LogClient {
|
|
|
216
219
|
}
|
|
217
220
|
// ---- Internal: persistence ----
|
|
218
221
|
_schedulePersist() {
|
|
219
|
-
if (this.
|
|
222
|
+
if (this._persistHandle || !this._opts.persistLogs)
|
|
220
223
|
return;
|
|
221
|
-
this.
|
|
222
|
-
this.
|
|
224
|
+
this._persistHandle = setTimeout(() => {
|
|
225
|
+
this._persistHandle = null;
|
|
223
226
|
this._persistNow();
|
|
224
227
|
}, PERSIST_DEBOUNCE_MS);
|
|
225
228
|
}
|
|
226
229
|
_persistNow() {
|
|
227
230
|
if (!this._opts.persistLogs)
|
|
228
231
|
return;
|
|
229
|
-
if (this._eventBuffer.length === 0 && this.
|
|
232
|
+
if (this._eventBuffer.length === 0 && this._perfBuffer.length === 0) {
|
|
230
233
|
this._opts.persistLogs('').catch(() => { });
|
|
231
234
|
return;
|
|
232
235
|
}
|
|
233
236
|
const data = JSON.stringify({
|
|
234
237
|
events: this._eventBuffer,
|
|
235
|
-
|
|
238
|
+
perfs: this._perfBuffer,
|
|
236
239
|
});
|
|
237
240
|
this._opts.persistLogs(data).catch(() => { });
|
|
238
241
|
}
|
|
@@ -247,8 +250,8 @@ class LogClient {
|
|
|
247
250
|
if (Array.isArray(parsed.events)) {
|
|
248
251
|
this._eventBuffer.push(...parsed.events);
|
|
249
252
|
}
|
|
250
|
-
if (Array.isArray(parsed.
|
|
251
|
-
this.
|
|
253
|
+
if (Array.isArray(parsed.perfs)) {
|
|
254
|
+
this._perfBuffer.push(...parsed.perfs);
|
|
252
255
|
}
|
|
253
256
|
// Clear persisted data now that it's loaded
|
|
254
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,
|
|
3
|
+
export { LogBatch, LogEventItem, LogPerfItem, ClientInfo, PerfToken, LogClientOptions, LogLevel, JsonValue, } from './types';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,94 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface LogBatch {
|
|
6
|
-
client: ClientInfo;
|
|
7
|
-
user_id?: string;
|
|
8
|
-
session_ref?: string;
|
|
9
|
-
device_id?: string;
|
|
10
|
-
events: LogEventItem[];
|
|
11
|
-
timers: TimerItem[];
|
|
12
|
-
}
|
|
13
|
-
export interface LogEventItem {
|
|
14
|
-
/** Event category, e.g. 'auth', 'billing', 'startup'. Default: 'client-log' */
|
|
15
|
-
type: string;
|
|
16
|
-
/** Epoch milliseconds */
|
|
17
|
-
timestamp: number;
|
|
18
|
-
level: LogLevel;
|
|
19
|
-
message: string;
|
|
20
|
-
/** Duration in milliseconds (for timed events that aren't span-shaped) */
|
|
21
|
-
duration?: number;
|
|
22
|
-
/** Serialized error info. `code` is the structured error code (ShareDB,
|
|
23
|
-
* Node `err.code`, etc.) — facetable downstream, unlike a code folded
|
|
24
|
-
* into the message text. */
|
|
25
|
-
error?: {
|
|
26
|
-
message: string;
|
|
27
|
-
type?: string;
|
|
28
|
-
code?: string;
|
|
29
|
-
stack?: string;
|
|
30
|
-
};
|
|
31
|
-
/** Arbitrary key-value event data */
|
|
32
|
-
params?: Record<string, JsonValue>;
|
|
33
|
-
}
|
|
34
|
-
export interface TimerItem {
|
|
35
|
-
/** 16-char hex ID, generated client-side */
|
|
1
|
+
import type { ClientInfo } from '@redthreadlabs/tracelog-schema';
|
|
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 */
|
|
36
5
|
id: string;
|
|
37
|
-
/** 32-char hex trace ID
|
|
6
|
+
/** 32-char hex trace ID (shared across the entire perf tree) */
|
|
38
7
|
trace_id: string;
|
|
39
|
-
/** ID of the root
|
|
8
|
+
/** ID of the root perf in this trace */
|
|
40
9
|
root_id: string;
|
|
41
|
-
/**
|
|
42
|
-
parent_id?: string;
|
|
43
|
-
/** Operation name, e.g. 'content-store-startup' */
|
|
44
|
-
name: string;
|
|
45
|
-
/** Timer category. Default: 'client-perf' */
|
|
46
|
-
type: string;
|
|
47
|
-
/** Start time, epoch milliseconds */
|
|
48
|
-
timestamp: number;
|
|
49
|
-
/** Duration in milliseconds */
|
|
50
|
-
duration: number;
|
|
51
|
-
outcome: 'success' | 'failure' | 'unknown';
|
|
52
|
-
context?: {
|
|
53
|
-
tags?: Record<string, JsonValue>;
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
export interface ClientInfo {
|
|
57
|
-
/** Application name, e.g. 'duiduidui-app' */
|
|
10
|
+
/** Name of the operation being measured */
|
|
58
11
|
name: string;
|
|
59
|
-
/** Application version */
|
|
60
|
-
version: string;
|
|
61
|
-
os: {
|
|
62
|
-
name: string;
|
|
63
|
-
version: string;
|
|
64
|
-
};
|
|
65
|
-
device: {
|
|
66
|
-
model?: string;
|
|
67
|
-
brand?: string;
|
|
68
|
-
type: string;
|
|
69
|
-
};
|
|
70
|
-
runtime: {
|
|
71
|
-
name: string;
|
|
72
|
-
version: string;
|
|
73
|
-
};
|
|
74
|
-
screen?: {
|
|
75
|
-
width: number;
|
|
76
|
-
height: number;
|
|
77
|
-
pixel_ratio: number;
|
|
78
|
-
};
|
|
79
|
-
locale?: string;
|
|
80
|
-
timezone?: string;
|
|
81
|
-
device_year_class?: number;
|
|
82
|
-
}
|
|
83
|
-
export interface TimerToken {
|
|
84
|
-
/** 16-char hex ID for this timer */
|
|
85
|
-
id: string;
|
|
86
|
-
/** 32-char hex trace ID (shared across the entire timer tree) */
|
|
87
|
-
trace_id: string;
|
|
88
|
-
/** ID of the root timer in this trace */
|
|
89
|
-
root_id: string;
|
|
90
|
-
/** Key/name of the operation being timed */
|
|
91
|
-
key: string;
|
|
92
12
|
}
|
|
93
13
|
export interface LogClientOptions {
|
|
94
14
|
/** Server endpoint URL for log submission */
|
|
@@ -103,8 +23,8 @@ export interface LogClientOptions {
|
|
|
103
23
|
getSessionRef?: () => string | undefined;
|
|
104
24
|
/** Returns native device identifier */
|
|
105
25
|
getDeviceId?: () => string | undefined;
|
|
106
|
-
/** Flush
|
|
107
|
-
|
|
26
|
+
/** Flush cadence in ms. Default: 5000 */
|
|
27
|
+
flushCadenceMs?: number;
|
|
108
28
|
/** Max events buffered before forced flush. Default: 100 */
|
|
109
29
|
maxBufferSize?: number;
|
|
110
30
|
/** Max events per HTTP request. Default: 50 */
|
package/dist/types.js
CHANGED
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minutes east of UTC right now (ISO-8601 sign: localWallClock = UTC + offset).
|
|
3
|
+
* `Date.prototype.getTimezoneOffset()` returns minutes to ADD to local to get
|
|
4
|
+
* UTC (so it's inverted, e.g. +300 for EST); negating gives the conventional
|
|
5
|
+
* eastward offset (EST = -300, IST = +330). Captured at record time so a
|
|
6
|
+
* buffered event reflects where/when it actually happened.
|
|
7
|
+
*/
|
|
8
|
+
export declare function tzOffsetMinutes(): number;
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tzOffsetMinutes = tzOffsetMinutes;
|
|
4
|
+
/**
|
|
5
|
+
* Minutes east of UTC right now (ISO-8601 sign: localWallClock = UTC + offset).
|
|
6
|
+
* `Date.prototype.getTimezoneOffset()` returns minutes to ADD to local to get
|
|
7
|
+
* UTC (so it's inverted, e.g. +300 for EST); negating gives the conventional
|
|
8
|
+
* eastward offset (EST = -300, IST = +330). Captured at record time so a
|
|
9
|
+
* buffered event reflects where/when it actually happened.
|
|
10
|
+
*/
|
|
11
|
+
function tzOffsetMinutes() {
|
|
12
|
+
return -new Date().getTimezoneOffset();
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redthreadlabs/tracelog-client",
|
|
3
|
-
"version": "1.
|
|
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/",
|
|
@@ -19,5 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"typescript": "latest"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@redthreadlabs/tracelog-schema": "^0.3.0"
|
|
22
25
|
}
|
|
23
26
|
}
|