@redthreadlabs/tracelog-schema 0.3.0 → 0.4.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,69 @@
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;
19
+ /**
20
+ * Opaque, consumer-defined identifier for the device or installation — an
21
+ * app's own id, a hardware id, whatever the consumer chooses. The framework
22
+ * treats it as an opaque string and never interprets it.
23
+ */
15
24
  device_id?: string;
16
- events: LogEventItem[];
17
- perfs: LogPerfItem[];
25
+ /**
26
+ * Id for this SDK lifetime (one app launch / process run), generated by the
27
+ * SDK. The join key between records and the once-per-lifetime `metadata`
28
+ * record that carries this launch's RecordOrigin.
29
+ */
30
+ lifetime_id?: string;
31
+ /**
32
+ * This lifetime's RecordOrigin (service + environment). Sent on the first
33
+ * batch of a launch and again when it changes; the server writes it as an
34
+ * in-stream `metadata` record keyed by `lifetime_id`.
35
+ */
36
+ origin?: RecordOrigin;
37
+ events: EventRecord[];
38
+ transactions: TransactionRecord[];
39
+ spans: SpanRecord[];
18
40
  }
19
- export interface LogEventItem {
41
+ /**
42
+ * Per-record context, shared by every record kind. `labels` is the arbitrary
43
+ * key-value attribute bag; `user` is the identity the record is attributed to.
44
+ * Mirrors the agent's native `context.labels` / `context.user`.
45
+ */
46
+ export interface RecordContext {
47
+ /** Arbitrary key-value attributes. */
48
+ labels?: Record<string, JsonValue>;
49
+ /** The user this record is attributed to. */
50
+ user?: {
51
+ id?: string;
52
+ };
53
+ }
54
+ /**
55
+ * A discrete log entry — something that happened at an instant: a log line or a
56
+ * behavioral event, carrying a level, message, and context labels. Events are
57
+ * NOT timed: a timed operation is a transaction/span, never an event with a
58
+ * duration.
59
+ */
60
+ export interface EventRecord {
20
61
  /** Event category, e.g. 'auth', 'billing', 'startup'. Default: 'client-log' */
21
62
  type: string;
22
- /** Epoch milliseconds */
63
+ /** Epoch microseconds */
23
64
  timestamp: number;
24
65
  level: LogLevel;
25
66
  message: string;
26
- /** Duration in milliseconds (for timed events that aren't span-shaped) */
27
- duration?: number;
28
67
  /** Serialized error info. `code` is the structured error code. */
29
68
  error?: {
30
69
  message: string;
@@ -32,8 +71,10 @@ export interface LogEventItem {
32
71
  code?: string;
33
72
  stack?: string;
34
73
  };
35
- /** Arbitrary key-value event data */
36
- params?: Record<string, JsonValue>;
74
+ /** UI locale at record time, e.g. 'en-US'. Can change mid-launch, so per-event. */
75
+ locale?: string;
76
+ /** Labels + user (see RecordContext). */
77
+ context?: RecordContext;
37
78
  /**
38
79
  * Minutes east of UTC at the moment the event was recorded (ISO-8601 sign:
39
80
  * `localWallClock = UTC + tz_offset`). Captured per-event because buffered
@@ -42,55 +83,99 @@ export interface LogEventItem {
42
83
  */
43
84
  tz_offset?: number;
44
85
  }
45
- export interface LogPerfItem {
46
- /** 16-char hex ID, generated client-side */
86
+ /**
87
+ * A root timed operation — the top of a trace (a request, a job, an agent run).
88
+ * Recorded as a `transaction`. Child work hangs off it as {@link SpanRecord}s.
89
+ */
90
+ export interface TransactionRecord {
91
+ /** 16-char hex ID, generated client-side. Also the trace's root id. */
47
92
  id: string;
48
- /** 32-char hex trace ID, shared by parent + children */
93
+ /** 32-char hex trace ID, shared by the whole trace */
49
94
  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' */
95
+ /** Operation name, e.g. 'parallel-search' */
55
96
  name: string;
56
- /** Perf category. Default: 'client-perf' */
97
+ /** Transaction type, e.g. 'request', 'agent', 'app'. Default: 'app' */
57
98
  type: string;
58
- /** Start time, epoch milliseconds */
99
+ /** Start time, epoch microseconds */
59
100
  timestamp: number;
60
101
  /** Duration in milliseconds */
61
102
  duration: number;
62
103
  outcome: 'success' | 'failure' | 'unknown';
63
- context?: {
64
- tags?: Record<string, JsonValue>;
65
- };
66
- /** Minutes east of UTC at record time (see LogEventItem.tz_offset). */
104
+ /** Labels + user (see RecordContext). */
105
+ context?: RecordContext;
106
+ /** Minutes east of UTC at record time (see EventRecord.tz_offset). */
67
107
  tz_offset?: number;
68
108
  }
69
- export interface ClientInfo {
70
- /** Application name, e.g. 'duiduidui-app' */
109
+ /**
110
+ * A timed sub-operation within a transaction — recorded as a `span`. Always has
111
+ * a parent (its transaction, or another span) and belongs to one transaction.
112
+ */
113
+ export interface SpanRecord {
114
+ /** 16-char hex ID, generated client-side */
115
+ id: string;
116
+ /** 32-char hex trace ID, shared by the whole trace */
117
+ trace_id: string;
118
+ /** ID of the transaction (trace root) this span belongs to */
119
+ transaction_id: string;
120
+ /** 16-char hex ID of the immediate parent (the transaction or another span) */
121
+ parent_id: string;
122
+ /** Operation name, e.g. 'search:hanzi' */
71
123
  name: string;
72
- /** Application version */
73
- version: string;
74
- os: {
124
+ /** Span type, e.g. 'db', 'external', 'app'. Default: 'app' */
125
+ type: string;
126
+ /** Start time, epoch microseconds */
127
+ timestamp: number;
128
+ /** Duration in milliseconds */
129
+ duration: number;
130
+ outcome: 'success' | 'failure' | 'unknown';
131
+ /** Labels + user (see RecordContext). */
132
+ context?: RecordContext;
133
+ /** Minutes east of UTC at record time (see EventRecord.tz_offset). */
134
+ tz_offset?: number;
135
+ }
136
+ /**
137
+ * Describes who/what produced records — a service and its environment. Carried
138
+ * by a `metadata` record in two scopes: the per-file header (the writer's
139
+ * origin, file-scoped) and, for a client, in-stream once per launch keyed by
140
+ * `lifetime_id`. Records don't carry the origin; they carry `lifetime_id` (or,
141
+ * server-side, sit in the file) and join to it.
142
+ *
143
+ * `service` + `runtime` are the common core; `host` is server-flavored; `device`
144
+ * is client-flavored. (locale/timezone are NOT here — they can change mid-launch,
145
+ * so they live per-record: `EventRecord.locale` and `tz_offset`.)
146
+ */
147
+ export interface RecordOrigin {
148
+ /** The SDK lifetime (app launch / process run) this RecordOrigin describes. Join key. */
149
+ lifetime_id?: string;
150
+ /** Application / service name + version. */
151
+ service: {
75
152
  name: string;
76
153
  version: string;
77
154
  };
78
- device: {
79
- model?: string;
80
- brand?: string;
81
- type: string;
82
- };
155
+ /** Runtime, e.g. 'react-native', 'node', 'browser'. */
83
156
  runtime: {
84
157
  name: string;
85
158
  version: string;
86
159
  };
87
- screen?: {
88
- width: number;
89
- height: number;
90
- pixel_ratio: number;
160
+ os?: {
161
+ name: string;
162
+ version: string;
163
+ };
164
+ /** Server-flavored: the host the service runs on. */
165
+ host?: {
166
+ name?: string;
167
+ };
168
+ /** Client-flavored: the device the app runs on. */
169
+ device?: {
170
+ model?: string;
171
+ brand?: string;
172
+ type?: string;
173
+ /** Device performance tier. */
174
+ year_class?: number;
175
+ screen?: {
176
+ width: number;
177
+ height: number;
178
+ pixel_ratio: number;
179
+ };
91
180
  };
92
- locale?: string;
93
- /** IANA timezone name for the session, e.g. 'America/New_York'. */
94
- timezone?: string;
95
- device_year_class?: number;
96
181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redthreadlabs/tracelog-schema",
3
- "version": "0.3.0",
3
+ "version": "0.4.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/",