@redthreadlabs/tracelog-schema 0.3.0 → 0.5.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/keys.d.ts CHANGED
@@ -15,7 +15,7 @@
15
15
  * for the live snapshot. `buildKey` and `parseKey` are exact inverses so the
16
16
  * agent and viewer never drift on this layout.
17
17
  */
18
- export interface KeyVars {
18
+ export interface ObjectKeyVars {
19
19
  channel: string;
20
20
  interval: string;
21
21
  host: string;
@@ -24,7 +24,7 @@ export interface KeyVars {
24
24
  /** the live, still-being-written snapshot */
25
25
  current?: boolean;
26
26
  }
27
- export interface ParsedKey {
27
+ export interface ParsedObjectKey {
28
28
  key: string;
29
29
  channel: string;
30
30
  interval: string;
@@ -37,12 +37,12 @@ export interface ParsedKey {
37
37
  etag?: string;
38
38
  }
39
39
  /** Build a log object's key. Pass `gzip` to append the `.gz` suffix. */
40
- export declare function buildKey(vars: KeyVars, gzip?: boolean): string;
40
+ export declare function buildKey(vars: ObjectKeyVars, gzip?: boolean): string;
41
41
  /**
42
42
  * Parse a log object's key back into its parts, or null if it is not a log
43
43
  * file in the known grammar (e.g. a sidecar `.meta.json`, or anything else).
44
44
  */
45
- export declare function parseKey(key: string, size?: number, lastModified?: Date, etag?: string): ParsedKey | null;
45
+ export declare function parseKey(key: string, size?: number, lastModified?: Date, etag?: string): ParsedObjectKey | null;
46
46
  /**
47
47
  * The UTC time span an interval label covers: daily `YYYY-MM-DD` → 24 h,
48
48
  * hourly `YYYY-MM-DDTHH` → 1 h. Unknown grammar → null (callers should be
@@ -50,14 +50,14 @@ export declare function parseKey(key: string, size?: number, lastModified?: Date
50
50
  */
51
51
  export declare function intervalSpan(interval: string): [number, number] | null;
52
52
  /** Whether a file's interval overlaps [startMs, endMs]. Unknown layout → kept. */
53
- export declare function overlapsRange(file: Pick<ParsedKey, 'interval'>, startMs: number, endMs: number): boolean;
53
+ export declare function overlapsRange(file: Pick<ParsedObjectKey, 'interval'>, startMs: number, endMs: number): boolean;
54
54
  /**
55
55
  * Drop `_current` snapshots shadowed by their finalized file: if the finalized
56
56
  * key exists, ignore the (briefly surviving) `_current`. A `_current` with no
57
57
  * finalized sibling is kept — it is either live (today) or a dead host's only
58
58
  * copy.
59
59
  */
60
- export declare function dedupeCurrents<T extends Pick<ParsedKey, 'channel' | 'interval' | 'host' | 'seq' | 'current'>>(files: T[]): T[];
60
+ export declare function dedupeCurrents<T extends Pick<ParsedObjectKey, 'channel' | 'interval' | 'host' | 'seq' | 'current'>>(files: T[]): T[];
61
61
  /**
62
62
  * Normalize a hostname into the host label used in keys. EC2 internal
63
63
  * hostnames (`ip-A-B-C-D[.…]`) become the dotted IP — which avoids embedding
package/dist/kinds.d.ts CHANGED
@@ -1,9 +1,17 @@
1
1
  /**
2
- * The record kinds that appear as the single top-level key of every NDJSON
3
- * line tracelog writes: `{ "<kind>": { ...fields... } }`. `metadata` is the
4
- * once-per-file header line, not a data record, so it is not a RecordKind.
2
+ * The DATA record kinds the single top-level key of a data NDJSON line:
3
+ * `{ "<kind>": { ...fields... } }`. These are what the sidecar histogram counts.
4
+ * `metadata` is deliberately NOT here: it's a dimension/context record, not data
5
+ * (see {@link METADATA_KIND}).
5
6
  */
6
7
  export type RecordKind = 'transaction' | 'span' | 'error' | 'event' | 'metricset';
7
8
  export declare const RECORD_KINDS: readonly RecordKind[];
8
- /** The header line's kind. Every file's first line is `{ "metadata": {...} }`. */
9
+ /**
10
+ * The `metadata` line's kind: `{ "metadata": <RecordOrigin> }` — it carries a
11
+ * RecordOrigin (service + environment), not data. It appears in two scopes:
12
+ * - the per-file header (file-scoped — the writer's origin), and
13
+ * - in-stream (lifetime-scoped — a client's per-launch origin, keyed by
14
+ * `lifetime_id`), which records join to.
15
+ * Excluded from RECORD_KINDS and the sidecar histogram (it isn't a data record).
16
+ */
9
17
  export declare const METADATA_KIND = "metadata";
package/dist/kinds.js CHANGED
@@ -12,5 +12,12 @@ exports.RECORD_KINDS = [
12
12
  'event',
13
13
  'metricset',
14
14
  ];
15
- /** The header line's kind. Every file's first line is `{ "metadata": {...} }`. */
15
+ /**
16
+ * The `metadata` line's kind: `{ "metadata": <RecordOrigin> }` — it carries a
17
+ * RecordOrigin (service + environment), not data. It appears in two scopes:
18
+ * - the per-file header (file-scoped — the writer's origin), and
19
+ * - in-stream (lifetime-scoped — a client's per-launch origin, keyed by
20
+ * `lifetime_id`), which records join to.
21
+ * Excluded from RECORD_KINDS and the sidecar histogram (it isn't a data record).
22
+ */
16
23
  exports.METADATA_KIND = 'metadata';
package/dist/wire.d.ts CHANGED
@@ -1,30 +1,63 @@
1
1
  /**
2
2
  * The wire format for the `POST /logs` ingest endpoint: what a remote client
3
- * (browser, React Native) sends and what the server parses. The server maps
4
- * these into the on-disk record kinds (see kinds.ts). Defined here so the
5
- * client SDK, the server, and the viewer all share one definition.
3
+ * (browser, React Native) sends. Defined here so the client SDK, the server, and
4
+ * the viewer all share one definition.
5
+ *
6
+ * The wire records ARE (modulo a few server-stamped fields) the on-disk records,
7
+ * in the same units — timestamps are epoch MICROSECONDS, durations are
8
+ * MILLISECONDS — so the ingest endpoint forwards them as-is rather than
9
+ * unwrapping and re-wrapping each one. The server's only per-record job is to
10
+ * stamp batch-level facts it owns (lifetime_id, context.user from the JWT, the
11
+ * source IP) and write to the channel.
6
12
  */
7
13
  export type JsonValue = string | number | boolean | null | JsonValue[] | {
8
14
  [key: string]: JsonValue;
9
15
  };
10
16
  export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
11
- export interface LogBatch {
12
- client: ClientInfo;
17
+ export interface RecordBatch {
13
18
  user_id?: string;
14
- session_ref?: string;
15
- device_id?: string;
16
- events: LogEventItem[];
17
- perfs: LogPerfItem[];
19
+ /**
20
+ * Id for this SDK lifetime (one app launch / process run), generated by the
21
+ * SDK. The join key between records and the once-per-lifetime `metadata`
22
+ * record that carries this launch's RecordOrigin.
23
+ */
24
+ lifetime_id?: string;
25
+ /**
26
+ * This lifetime's RecordOrigin (service + environment). Sent on the first
27
+ * batch of a launch and again when it changes; the server writes it as an
28
+ * in-stream `metadata` record keyed by `lifetime_id`.
29
+ */
30
+ origin?: RecordOrigin;
31
+ events: EventRecord[];
32
+ transactions: TransactionRecord[];
33
+ spans: SpanRecord[];
34
+ }
35
+ /**
36
+ * Per-record context, shared by every record kind. `labels` is the arbitrary
37
+ * key-value attribute bag; `user` is the identity the record is attributed to.
38
+ * Mirrors the agent's native `context.labels` / `context.user`.
39
+ */
40
+ export interface RecordContext {
41
+ /** Arbitrary key-value attributes. */
42
+ labels?: Record<string, JsonValue>;
43
+ /** The user this record is attributed to. */
44
+ user?: {
45
+ id?: string;
46
+ };
18
47
  }
19
- export interface LogEventItem {
48
+ /**
49
+ * A discrete log entry — something that happened at an instant: a log line or a
50
+ * behavioral event, carrying a level, message, and context labels. Events are
51
+ * NOT timed: a timed operation is a transaction/span, never an event with a
52
+ * duration.
53
+ */
54
+ export interface EventRecord {
20
55
  /** Event category, e.g. 'auth', 'billing', 'startup'. Default: 'client-log' */
21
56
  type: string;
22
- /** Epoch milliseconds */
57
+ /** Epoch microseconds */
23
58
  timestamp: number;
24
59
  level: LogLevel;
25
60
  message: string;
26
- /** Duration in milliseconds (for timed events that aren't span-shaped) */
27
- duration?: number;
28
61
  /** Serialized error info. `code` is the structured error code. */
29
62
  error?: {
30
63
  message: string;
@@ -32,8 +65,10 @@ export interface LogEventItem {
32
65
  code?: string;
33
66
  stack?: string;
34
67
  };
35
- /** Arbitrary key-value event data */
36
- params?: Record<string, JsonValue>;
68
+ /** UI locale at record time, e.g. 'en-US'. Can change mid-launch, so per-event. */
69
+ locale?: string;
70
+ /** Labels + user (see RecordContext). */
71
+ context?: RecordContext;
37
72
  /**
38
73
  * Minutes east of UTC at the moment the event was recorded (ISO-8601 sign:
39
74
  * `localWallClock = UTC + tz_offset`). Captured per-event because buffered
@@ -42,55 +77,106 @@ export interface LogEventItem {
42
77
  */
43
78
  tz_offset?: number;
44
79
  }
45
- export interface LogPerfItem {
46
- /** 16-char hex ID, generated client-side */
80
+ /**
81
+ * A root timed operation — the top of a trace (a request, a job, an agent run).
82
+ * Recorded as a `transaction`. Child work hangs off it as {@link SpanRecord}s.
83
+ */
84
+ export interface TransactionRecord {
85
+ /** 16-char hex ID, generated client-side. Also the trace's root id. */
47
86
  id: string;
48
- /** 32-char hex trace ID, shared by parent + children */
87
+ /** 32-char hex trace ID, shared by the whole trace */
49
88
  trace_id: string;
50
- /** ID of the root perf in this trace */
51
- root_id: string;
52
- /** 16-char hex ID of parent perf (absent for root perfs) */
53
- parent_id?: string;
54
- /** Operation name, e.g. 'content-store-startup' */
89
+ /** Operation name, e.g. 'parallel-search' */
55
90
  name: string;
56
- /** Perf category. Default: 'client-perf' */
91
+ /** Transaction type, e.g. 'request', 'agent', 'app'. Default: 'app' */
57
92
  type: string;
58
- /** Start time, epoch milliseconds */
93
+ /** Start time, epoch microseconds */
59
94
  timestamp: number;
60
95
  /** Duration in milliseconds */
61
96
  duration: number;
62
97
  outcome: 'success' | 'failure' | 'unknown';
63
- context?: {
64
- tags?: Record<string, JsonValue>;
65
- };
66
- /** Minutes east of UTC at record time (see LogEventItem.tz_offset). */
98
+ /** Labels + user (see RecordContext). */
99
+ context?: RecordContext;
100
+ /** Minutes east of UTC at record time (see EventRecord.tz_offset). */
67
101
  tz_offset?: number;
68
102
  }
69
- export interface ClientInfo {
70
- /** Application name, e.g. 'duiduidui-app' */
103
+ /**
104
+ * A timed sub-operation within a transaction — recorded as a `span`. Always has
105
+ * a parent (its transaction, or another span) and belongs to one transaction.
106
+ */
107
+ export interface SpanRecord {
108
+ /** 16-char hex ID, generated client-side */
109
+ id: string;
110
+ /** 32-char hex trace ID, shared by the whole trace */
111
+ trace_id: string;
112
+ /** ID of the transaction (trace root) this span belongs to */
113
+ transaction_id: string;
114
+ /** 16-char hex ID of the immediate parent (the transaction or another span) */
115
+ parent_id: string;
116
+ /** Operation name, e.g. 'search:hanzi' */
71
117
  name: string;
72
- /** Application version */
73
- version: string;
74
- os: {
118
+ /** Span type, e.g. 'db', 'external', 'app'. Default: 'app' */
119
+ type: string;
120
+ /** Start time, epoch microseconds */
121
+ timestamp: number;
122
+ /** Duration in milliseconds */
123
+ duration: number;
124
+ outcome: 'success' | 'failure' | 'unknown';
125
+ /** Labels + user (see RecordContext). */
126
+ context?: RecordContext;
127
+ /** Minutes east of UTC at record time (see EventRecord.tz_offset). */
128
+ tz_offset?: number;
129
+ }
130
+ /**
131
+ * Describes who/what produced records — a service and its environment. Carried
132
+ * by a `metadata` record in two scopes: the per-file header (the writer's
133
+ * origin, file-scoped) and, for a client, in-stream once per launch keyed by
134
+ * `lifetime_id`. Records don't carry the origin; they carry `lifetime_id` (or,
135
+ * server-side, sit in the file) and join to it.
136
+ *
137
+ * `service` + `runtime` are the common core; `host` is server-flavored; `device`
138
+ * is client-flavored. (locale/timezone are NOT here — they can change mid-launch,
139
+ * so they live per-record: `EventRecord.locale` and `tz_offset`.)
140
+ */
141
+ export interface RecordOrigin {
142
+ /** The SDK lifetime (app launch / process run) this RecordOrigin describes. Join key. */
143
+ lifetime_id?: string;
144
+ /** Application / service name + version. */
145
+ service: {
75
146
  name: string;
76
147
  version: string;
77
148
  };
78
- device: {
79
- model?: string;
80
- brand?: string;
81
- type: string;
82
- };
149
+ /** Runtime, e.g. 'react-native', 'node', 'browser'. */
83
150
  runtime: {
84
151
  name: string;
85
152
  version: string;
86
153
  };
87
- screen?: {
88
- width: number;
89
- height: number;
90
- pixel_ratio: number;
154
+ os?: {
155
+ name: string;
156
+ version: string;
157
+ };
158
+ /** Server-flavored: the host the service runs on. */
159
+ host?: {
160
+ name?: string;
161
+ };
162
+ /** Client-flavored: the device the app runs on. */
163
+ device?: {
164
+ /**
165
+ * Opaque, consumer-defined identifier for the device or installation — an
166
+ * app's own id, a hardware id, whatever the consumer chooses. The framework
167
+ * treats it as an opaque string and never interprets it. Stable across this
168
+ * device's launches, so records join to it through the origin (lifetime_id).
169
+ */
170
+ id?: string;
171
+ model?: string;
172
+ brand?: string;
173
+ type?: string;
174
+ /** Device performance tier. */
175
+ year_class?: number;
176
+ screen?: {
177
+ width: number;
178
+ height: number;
179
+ pixel_ratio: number;
180
+ };
91
181
  };
92
- locale?: string;
93
- /** IANA timezone name for the session, e.g. 'America/New_York'. */
94
- timezone?: string;
95
- device_year_class?: number;
96
182
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redthreadlabs/tracelog-schema",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Shared contract for the tracelog suite: record kinds, S3 key layout, metadata sidecar, and the /logs wire format",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",