@kopai/sqlite-datasource 0.0.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/LICENSE +190 -0
- package/dist/index.cjs +1126 -0
- package/dist/index.d.cts +32 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1126 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +44 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1126 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { DummyDriver, Kysely, SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, sql } from "kysely";
|
|
3
|
+
import { otlp } from "@kopai/core";
|
|
4
|
+
|
|
5
|
+
//#region src/sqlite-datasource-error.ts
|
|
6
|
+
var SqliteDatasourceError = class extends Error {
|
|
7
|
+
constructor(message, options) {
|
|
8
|
+
super(message, options);
|
|
9
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var SqliteDatasourceQueryError = class extends SqliteDatasourceError {
|
|
13
|
+
code = "QUERY_ERROR";
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(message, options);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/datasource.ts
|
|
21
|
+
const queryBuilder = new Kysely({ dialect: {
|
|
22
|
+
createAdapter: () => new SqliteAdapter(),
|
|
23
|
+
createDriver: () => new DummyDriver(),
|
|
24
|
+
createIntrospector: (db) => new SqliteIntrospector(db),
|
|
25
|
+
createQueryCompiler: () => new SqliteQueryCompiler()
|
|
26
|
+
} });
|
|
27
|
+
var NodeSqliteTelemetryDatasource = class {
|
|
28
|
+
constructor(sqliteConnection) {
|
|
29
|
+
this.sqliteConnection = sqliteConnection;
|
|
30
|
+
}
|
|
31
|
+
async writeMetrics(metricsData) {
|
|
32
|
+
const gaugeRows = [];
|
|
33
|
+
const sumRows = [];
|
|
34
|
+
const histogramRows = [];
|
|
35
|
+
const expHistogramRows = [];
|
|
36
|
+
const summaryRows = [];
|
|
37
|
+
for (const resourceMetric of metricsData.resourceMetrics ?? []) {
|
|
38
|
+
const { resource, schemaUrl: resourceSchemaUrl } = resourceMetric;
|
|
39
|
+
for (const scopeMetric of resourceMetric.scopeMetrics ?? []) {
|
|
40
|
+
const { scope, schemaUrl: scopeSchemaUrl } = scopeMetric;
|
|
41
|
+
for (const metric of scopeMetric.metrics ?? []) {
|
|
42
|
+
if (metric.gauge) for (const dataPoint of metric.gauge.dataPoints ?? []) gaugeRows.push(toGaugeRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint));
|
|
43
|
+
if (metric.sum) for (const dataPoint of metric.sum.dataPoints ?? []) sumRows.push(toSumRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint, metric.sum.aggregationTemporality, metric.sum.isMonotonic));
|
|
44
|
+
if (metric.histogram) for (const dataPoint of metric.histogram.dataPoints ?? []) histogramRows.push(toHistogramRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint, metric.histogram.aggregationTemporality));
|
|
45
|
+
if (metric.exponentialHistogram) for (const dataPoint of metric.exponentialHistogram.dataPoints ?? []) expHistogramRows.push(toExpHistogramRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint, metric.exponentialHistogram.aggregationTemporality));
|
|
46
|
+
if (metric.summary) for (const dataPoint of metric.summary.dataPoints ?? []) summaryRows.push(toSummaryRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const { table, rows } of [
|
|
50
|
+
{
|
|
51
|
+
table: "otel_metrics_gauge",
|
|
52
|
+
rows: gaugeRows
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
table: "otel_metrics_sum",
|
|
56
|
+
rows: sumRows
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
table: "otel_metrics_histogram",
|
|
60
|
+
rows: histogramRows
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
table: "otel_metrics_exponential_histogram",
|
|
64
|
+
rows: expHistogramRows
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
table: "otel_metrics_summary",
|
|
68
|
+
rows: summaryRows
|
|
69
|
+
}
|
|
70
|
+
]) for (const row of rows) {
|
|
71
|
+
const { sql, parameters } = queryBuilder.insertInto(table).values(row).compile();
|
|
72
|
+
this.sqliteConnection.prepare(sql).run(...parameters);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { rejectedDataPoints: "" };
|
|
76
|
+
}
|
|
77
|
+
async writeTraces(tracesData) {
|
|
78
|
+
const spanRows = [];
|
|
79
|
+
const traceTimestamps = /* @__PURE__ */ new Map();
|
|
80
|
+
for (const resourceSpan of tracesData.resourceSpans ?? []) {
|
|
81
|
+
const { resource } = resourceSpan;
|
|
82
|
+
for (const scopeSpan of resourceSpan.scopeSpans ?? []) {
|
|
83
|
+
const { scope } = scopeSpan;
|
|
84
|
+
for (const span of scopeSpan.spans ?? []) {
|
|
85
|
+
const row = toSpanRow(resource, scope, span);
|
|
86
|
+
spanRows.push(row);
|
|
87
|
+
const traceId = span.traceId ?? "";
|
|
88
|
+
if (traceId) {
|
|
89
|
+
const timestamp = row.Timestamp;
|
|
90
|
+
const existing = traceTimestamps.get(traceId);
|
|
91
|
+
if (existing) {
|
|
92
|
+
existing.min = timestamp < existing.min ? timestamp : existing.min;
|
|
93
|
+
existing.max = timestamp > existing.max ? timestamp : existing.max;
|
|
94
|
+
} else traceTimestamps.set(traceId, {
|
|
95
|
+
min: timestamp,
|
|
96
|
+
max: timestamp
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (const row of spanRows) {
|
|
103
|
+
const { sql, parameters } = queryBuilder.insertInto("otel_traces").values(row).compile();
|
|
104
|
+
this.sqliteConnection.prepare(sql).run(...parameters);
|
|
105
|
+
}
|
|
106
|
+
for (const [traceId, { min, max }] of traceTimestamps) {
|
|
107
|
+
const { sql, parameters } = queryBuilder.insertInto("otel_traces_trace_id_ts").values({
|
|
108
|
+
TraceId: traceId,
|
|
109
|
+
Start: min,
|
|
110
|
+
End: max
|
|
111
|
+
}).onConflict((oc) => oc.column("TraceId").doUpdateSet({
|
|
112
|
+
Start: (eb) => eb.fn("min", [eb.ref("otel_traces_trace_id_ts.Start"), eb.val(min)]),
|
|
113
|
+
End: (eb) => eb.fn("max", [eb.ref("otel_traces_trace_id_ts.End"), eb.val(max)])
|
|
114
|
+
})).compile();
|
|
115
|
+
this.sqliteConnection.prepare(sql).run(...parameters);
|
|
116
|
+
}
|
|
117
|
+
return { rejectedSpans: "" };
|
|
118
|
+
}
|
|
119
|
+
async writeLogs(logsData) {
|
|
120
|
+
const logRows = [];
|
|
121
|
+
for (const resourceLog of logsData.resourceLogs ?? []) {
|
|
122
|
+
const { resource, schemaUrl: resourceSchemaUrl } = resourceLog;
|
|
123
|
+
for (const scopeLog of resourceLog.scopeLogs ?? []) {
|
|
124
|
+
const { scope, schemaUrl: scopeSchemaUrl } = scopeLog;
|
|
125
|
+
for (const logRecord of scopeLog.logRecords ?? []) logRows.push(toLogRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, logRecord));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const row of logRows) {
|
|
129
|
+
const { sql, parameters } = queryBuilder.insertInto("otel_logs").values(row).compile();
|
|
130
|
+
this.sqliteConnection.prepare(sql).run(...parameters);
|
|
131
|
+
}
|
|
132
|
+
return { rejectedLogRecords: "" };
|
|
133
|
+
}
|
|
134
|
+
async getTraces(filter) {
|
|
135
|
+
try {
|
|
136
|
+
const limit = filter.limit ?? 100;
|
|
137
|
+
const sortOrder = filter.sortOrder ?? "DESC";
|
|
138
|
+
let query = queryBuilder.selectFrom("otel_traces").selectAll();
|
|
139
|
+
if (filter.traceId) query = query.where("TraceId", "=", filter.traceId);
|
|
140
|
+
if (filter.spanId) query = query.where("SpanId", "=", filter.spanId);
|
|
141
|
+
if (filter.parentSpanId) query = query.where("ParentSpanId", "=", filter.parentSpanId);
|
|
142
|
+
if (filter.serviceName) query = query.where("ServiceName", "=", filter.serviceName);
|
|
143
|
+
if (filter.spanName) query = query.where("SpanName", "=", filter.spanName);
|
|
144
|
+
if (filter.spanKind) query = query.where("SpanKind", "=", filter.spanKind);
|
|
145
|
+
if (filter.statusCode) query = query.where("StatusCode", "=", filter.statusCode);
|
|
146
|
+
if (filter.scopeName) query = query.where("ScopeName", "=", filter.scopeName);
|
|
147
|
+
if (filter.timestampMin != null) query = query.where("Timestamp", ">=", BigInt(filter.timestampMin));
|
|
148
|
+
if (filter.timestampMax != null) query = query.where("Timestamp", "<=", BigInt(filter.timestampMax));
|
|
149
|
+
if (filter.durationMin != null) query = query.where("Duration", ">=", BigInt(filter.durationMin));
|
|
150
|
+
if (filter.durationMax != null) query = query.where("Duration", "<=", BigInt(filter.durationMax));
|
|
151
|
+
if (filter.cursor) {
|
|
152
|
+
const colonIdx = filter.cursor.indexOf(":");
|
|
153
|
+
const cursorTs = BigInt(filter.cursor.slice(0, colonIdx));
|
|
154
|
+
const cursorSpanId = filter.cursor.slice(colonIdx + 1);
|
|
155
|
+
if (sortOrder === "DESC") query = query.where((eb) => eb.or([eb("Timestamp", "<", cursorTs), eb.and([eb("Timestamp", "=", cursorTs), eb("SpanId", "<", cursorSpanId)])]));
|
|
156
|
+
else query = query.where((eb) => eb.or([eb("Timestamp", ">", cursorTs), eb.and([eb("Timestamp", "=", cursorTs), eb("SpanId", ">", cursorSpanId)])]));
|
|
157
|
+
}
|
|
158
|
+
if (filter.spanAttributes) for (const [key, value] of Object.entries(filter.spanAttributes)) {
|
|
159
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
160
|
+
query = query.where(sql`json_extract(SpanAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
161
|
+
}
|
|
162
|
+
if (filter.resourceAttributes) for (const [key, value] of Object.entries(filter.resourceAttributes)) {
|
|
163
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
164
|
+
query = query.where(sql`json_extract(ResourceAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
165
|
+
}
|
|
166
|
+
query = query.orderBy("Timestamp", sortOrder === "ASC" ? "asc" : "desc").orderBy("SpanId", sortOrder === "ASC" ? "asc" : "desc").limit(limit + 1);
|
|
167
|
+
const { sql: sql$1, parameters } = query.compile();
|
|
168
|
+
const stmt = this.sqliteConnection.prepare(sql$1);
|
|
169
|
+
stmt.setReadBigInts(true);
|
|
170
|
+
const rows = stmt.all(...parameters);
|
|
171
|
+
const hasMore = rows.length > limit;
|
|
172
|
+
const data = hasMore ? rows.slice(0, limit) : rows;
|
|
173
|
+
const lastRow = data[data.length - 1];
|
|
174
|
+
const nextCursor = hasMore && lastRow ? `${lastRow.Timestamp}:${lastRow.SpanId}` : null;
|
|
175
|
+
return {
|
|
176
|
+
data: data.map(mapRowToOtelTraces),
|
|
177
|
+
nextCursor
|
|
178
|
+
};
|
|
179
|
+
} catch (error) {
|
|
180
|
+
throw new SqliteDatasourceQueryError("Failed to query traces", { cause: error });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async getMetrics(filter) {
|
|
184
|
+
try {
|
|
185
|
+
const limit = filter.limit ?? 100;
|
|
186
|
+
const sortOrder = filter.sortOrder ?? "DESC";
|
|
187
|
+
const metricType = filter.metricType;
|
|
188
|
+
const table = {
|
|
189
|
+
Gauge: "otel_metrics_gauge",
|
|
190
|
+
Sum: "otel_metrics_sum",
|
|
191
|
+
Histogram: "otel_metrics_histogram",
|
|
192
|
+
ExponentialHistogram: "otel_metrics_exponential_histogram",
|
|
193
|
+
Summary: "otel_metrics_summary"
|
|
194
|
+
}[metricType];
|
|
195
|
+
let query = queryBuilder.selectFrom(table).select([
|
|
196
|
+
"TimeUnix",
|
|
197
|
+
"StartTimeUnix",
|
|
198
|
+
"Attributes",
|
|
199
|
+
"MetricName",
|
|
200
|
+
"MetricDescription",
|
|
201
|
+
"MetricUnit",
|
|
202
|
+
"ResourceAttributes",
|
|
203
|
+
"ResourceSchemaUrl",
|
|
204
|
+
"ScopeAttributes",
|
|
205
|
+
"ScopeDroppedAttrCount",
|
|
206
|
+
"ScopeName",
|
|
207
|
+
"ScopeSchemaUrl",
|
|
208
|
+
"ScopeVersion",
|
|
209
|
+
"ServiceName",
|
|
210
|
+
sql`rowid`.as("_rowid")
|
|
211
|
+
]);
|
|
212
|
+
if (metricType !== "Summary") query = query.select([
|
|
213
|
+
sql`"Exemplars.FilteredAttributes"`.as("Exemplars.FilteredAttributes"),
|
|
214
|
+
sql`"Exemplars.SpanId"`.as("Exemplars.SpanId"),
|
|
215
|
+
sql`"Exemplars.TimeUnix"`.as("Exemplars.TimeUnix"),
|
|
216
|
+
sql`"Exemplars.TraceId"`.as("Exemplars.TraceId"),
|
|
217
|
+
sql`"Exemplars.Value"`.as("Exemplars.Value")
|
|
218
|
+
]);
|
|
219
|
+
if (metricType === "Gauge") query = query.select(["Value", "Flags"]);
|
|
220
|
+
else if (metricType === "Sum") query = query.select([
|
|
221
|
+
"Value",
|
|
222
|
+
"Flags",
|
|
223
|
+
"AggTemporality",
|
|
224
|
+
"IsMonotonic"
|
|
225
|
+
]);
|
|
226
|
+
else if (metricType === "Histogram") query = query.select([
|
|
227
|
+
"Count",
|
|
228
|
+
"Sum",
|
|
229
|
+
"BucketCounts",
|
|
230
|
+
"ExplicitBounds",
|
|
231
|
+
"Min",
|
|
232
|
+
"Max",
|
|
233
|
+
"AggTemporality"
|
|
234
|
+
]);
|
|
235
|
+
else if (metricType === "ExponentialHistogram") query = query.select([
|
|
236
|
+
"Count",
|
|
237
|
+
"Sum",
|
|
238
|
+
"Scale",
|
|
239
|
+
"ZeroCount",
|
|
240
|
+
"PositiveOffset",
|
|
241
|
+
"PositiveBucketCounts",
|
|
242
|
+
"NegativeOffset",
|
|
243
|
+
"NegativeBucketCounts",
|
|
244
|
+
"Min",
|
|
245
|
+
"Max",
|
|
246
|
+
"ZeroThreshold",
|
|
247
|
+
"AggTemporality"
|
|
248
|
+
]);
|
|
249
|
+
else if (metricType === "Summary") {
|
|
250
|
+
query = query.select(["Count", "Sum"]);
|
|
251
|
+
query = query.select([sql`"ValueAtQuantiles.Quantile"`.as("ValueAtQuantiles.Quantile"), sql`"ValueAtQuantiles.Value"`.as("ValueAtQuantiles.Value")]);
|
|
252
|
+
}
|
|
253
|
+
if (filter.metricName) query = query.where("MetricName", "=", filter.metricName);
|
|
254
|
+
if (filter.serviceName) query = query.where("ServiceName", "=", filter.serviceName);
|
|
255
|
+
if (filter.scopeName) query = query.where("ScopeName", "=", filter.scopeName);
|
|
256
|
+
if (filter.timeUnixMin != null) query = query.where("TimeUnix", ">=", BigInt(filter.timeUnixMin));
|
|
257
|
+
if (filter.timeUnixMax != null) query = query.where("TimeUnix", "<=", BigInt(filter.timeUnixMax));
|
|
258
|
+
if (filter.cursor) {
|
|
259
|
+
const colonIdx = filter.cursor.indexOf(":");
|
|
260
|
+
const cursorTs = BigInt(filter.cursor.slice(0, colonIdx));
|
|
261
|
+
const cursorRowid = parseInt(filter.cursor.slice(colonIdx + 1), 10);
|
|
262
|
+
if (sortOrder === "DESC") query = query.where((eb) => eb.or([eb("TimeUnix", "<", cursorTs), eb.and([eb("TimeUnix", "=", cursorTs), eb(sql`rowid`, "<", cursorRowid)])]));
|
|
263
|
+
else query = query.where((eb) => eb.or([eb("TimeUnix", ">", cursorTs), eb.and([eb("TimeUnix", "=", cursorTs), eb(sql`rowid`, ">", cursorRowid)])]));
|
|
264
|
+
}
|
|
265
|
+
if (filter.attributes) for (const [key, value] of Object.entries(filter.attributes)) {
|
|
266
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
267
|
+
query = query.where(sql`json_extract(Attributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
268
|
+
}
|
|
269
|
+
if (filter.resourceAttributes) for (const [key, value] of Object.entries(filter.resourceAttributes)) {
|
|
270
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
271
|
+
query = query.where(sql`json_extract(ResourceAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
272
|
+
}
|
|
273
|
+
if (filter.scopeAttributes) for (const [key, value] of Object.entries(filter.scopeAttributes)) {
|
|
274
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
275
|
+
query = query.where(sql`json_extract(ScopeAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
276
|
+
}
|
|
277
|
+
query = query.orderBy("TimeUnix", sortOrder === "ASC" ? "asc" : "desc").orderBy(sql`rowid`, sortOrder === "ASC" ? "asc" : "desc").limit(limit + 1);
|
|
278
|
+
const { sql: sql$2, parameters } = query.compile();
|
|
279
|
+
const stmt = this.sqliteConnection.prepare(sql$2);
|
|
280
|
+
stmt.setReadBigInts(true);
|
|
281
|
+
const rows = stmt.all(...parameters);
|
|
282
|
+
const hasMore = rows.length > limit;
|
|
283
|
+
const data = hasMore ? rows.slice(0, limit) : rows;
|
|
284
|
+
const lastRow = data[data.length - 1];
|
|
285
|
+
const nextCursor = hasMore && lastRow ? `${lastRow.TimeUnix}:${lastRow._rowid}` : null;
|
|
286
|
+
return {
|
|
287
|
+
data: data.map((row) => mapRowToOtelMetrics(row, metricType)),
|
|
288
|
+
nextCursor
|
|
289
|
+
};
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (error instanceof SqliteDatasourceQueryError) throw error;
|
|
292
|
+
throw new SqliteDatasourceQueryError("Failed to query metrics", { cause: error });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async getLogs(filter) {
|
|
296
|
+
try {
|
|
297
|
+
const limit = filter.limit ?? 100;
|
|
298
|
+
const sortOrder = filter.sortOrder ?? "DESC";
|
|
299
|
+
let query = queryBuilder.selectFrom("otel_logs").select([
|
|
300
|
+
"Timestamp",
|
|
301
|
+
"TraceId",
|
|
302
|
+
"SpanId",
|
|
303
|
+
"TraceFlags",
|
|
304
|
+
"SeverityText",
|
|
305
|
+
"SeverityNumber",
|
|
306
|
+
"Body",
|
|
307
|
+
"LogAttributes",
|
|
308
|
+
"ResourceAttributes",
|
|
309
|
+
"ResourceSchemaUrl",
|
|
310
|
+
"ServiceName",
|
|
311
|
+
"ScopeName",
|
|
312
|
+
"ScopeVersion",
|
|
313
|
+
"ScopeAttributes",
|
|
314
|
+
"ScopeSchemaUrl",
|
|
315
|
+
sql`rowid`.as("_rowid")
|
|
316
|
+
]);
|
|
317
|
+
if (filter.traceId) query = query.where("TraceId", "=", filter.traceId);
|
|
318
|
+
if (filter.spanId) query = query.where("SpanId", "=", filter.spanId);
|
|
319
|
+
if (filter.serviceName) query = query.where("ServiceName", "=", filter.serviceName);
|
|
320
|
+
if (filter.scopeName) query = query.where("ScopeName", "=", filter.scopeName);
|
|
321
|
+
if (filter.severityText) query = query.where("SeverityText", "=", filter.severityText);
|
|
322
|
+
if (filter.severityNumberMin != null) query = query.where("SeverityNumber", ">=", filter.severityNumberMin);
|
|
323
|
+
if (filter.severityNumberMax != null) query = query.where("SeverityNumber", "<=", filter.severityNumberMax);
|
|
324
|
+
if (filter.timestampMin != null) query = query.where("Timestamp", ">=", BigInt(filter.timestampMin));
|
|
325
|
+
if (filter.timestampMax != null) query = query.where("Timestamp", "<=", BigInt(filter.timestampMax));
|
|
326
|
+
if (filter.bodyContains) query = query.where(sql`INSTR(Body, ${filter.bodyContains})`, ">", 0);
|
|
327
|
+
if (filter.cursor) {
|
|
328
|
+
const colonIdx = filter.cursor.indexOf(":");
|
|
329
|
+
const cursorTs = BigInt(filter.cursor.slice(0, colonIdx));
|
|
330
|
+
const cursorRowid = parseInt(filter.cursor.slice(colonIdx + 1), 10);
|
|
331
|
+
if (sortOrder === "DESC") query = query.where((eb) => eb.or([eb("Timestamp", "<", cursorTs), eb.and([eb("Timestamp", "=", cursorTs), eb(sql`rowid`, "<", cursorRowid)])]));
|
|
332
|
+
else query = query.where((eb) => eb.or([eb("Timestamp", ">", cursorTs), eb.and([eb("Timestamp", "=", cursorTs), eb(sql`rowid`, ">", cursorRowid)])]));
|
|
333
|
+
}
|
|
334
|
+
if (filter.logAttributes) for (const [key, value] of Object.entries(filter.logAttributes)) {
|
|
335
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
336
|
+
query = query.where(sql`json_extract(LogAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
337
|
+
}
|
|
338
|
+
if (filter.resourceAttributes) for (const [key, value] of Object.entries(filter.resourceAttributes)) {
|
|
339
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
340
|
+
query = query.where(sql`json_extract(ResourceAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
341
|
+
}
|
|
342
|
+
if (filter.scopeAttributes) for (const [key, value] of Object.entries(filter.scopeAttributes)) {
|
|
343
|
+
const jsonPath = `$."${key.replace(/"/g, "\"\"")}"`;
|
|
344
|
+
query = query.where(sql`json_extract(ScopeAttributes, ${sql.lit(jsonPath)})`, "=", value);
|
|
345
|
+
}
|
|
346
|
+
query = query.orderBy("Timestamp", sortOrder === "ASC" ? "asc" : "desc").orderBy(sql`rowid`, sortOrder === "ASC" ? "asc" : "desc").limit(limit + 1);
|
|
347
|
+
const { sql: sql$3, parameters } = query.compile();
|
|
348
|
+
const stmt = this.sqliteConnection.prepare(sql$3);
|
|
349
|
+
stmt.setReadBigInts(true);
|
|
350
|
+
const rows = stmt.all(...parameters);
|
|
351
|
+
const hasMore = rows.length > limit;
|
|
352
|
+
const data = hasMore ? rows.slice(0, limit) : rows;
|
|
353
|
+
const lastRow = data[data.length - 1];
|
|
354
|
+
const nextCursor = hasMore && lastRow ? `${lastRow.Timestamp}:${lastRow._rowid}` : null;
|
|
355
|
+
return {
|
|
356
|
+
data: data.map(mapRowToOtelLogs),
|
|
357
|
+
nextCursor
|
|
358
|
+
};
|
|
359
|
+
} catch (error) {
|
|
360
|
+
throw new SqliteDatasourceQueryError("Failed to query logs", { cause: error });
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async discoverMetrics() {
|
|
364
|
+
try {
|
|
365
|
+
const distinctMetricsSql = METRIC_TABLES.map(({ table, type }) => `SELECT DISTINCT MetricName, MetricUnit, MetricDescription, '${type}' as MetricType FROM ${table}`).join(" UNION ");
|
|
366
|
+
const distinctMetrics = this.sqliteConnection.prepare(distinctMetricsSql).all();
|
|
367
|
+
const metrics = [];
|
|
368
|
+
for (const metric of distinctMetrics) {
|
|
369
|
+
const table = METRIC_TABLES.find((t) => t.type === metric.MetricType).table;
|
|
370
|
+
const attrKeysSql = `
|
|
371
|
+
SELECT DISTINCT json_each.key as key
|
|
372
|
+
FROM ${table}, json_each(Attributes)
|
|
373
|
+
WHERE MetricName = ?
|
|
374
|
+
`;
|
|
375
|
+
const attrKeys = this.sqliteConnection.prepare(attrKeysSql).all(metric.MetricName);
|
|
376
|
+
let attrsTruncated = false;
|
|
377
|
+
const attributes = {};
|
|
378
|
+
for (const { key } of attrKeys) {
|
|
379
|
+
const valuesSql = `
|
|
380
|
+
SELECT DISTINCT json_each.value as value
|
|
381
|
+
FROM ${table}, json_each(Attributes)
|
|
382
|
+
WHERE MetricName = ? AND json_each.key = ?
|
|
383
|
+
LIMIT ${MAX_ATTR_VALUES + 1}
|
|
384
|
+
`;
|
|
385
|
+
const values = this.sqliteConnection.prepare(valuesSql).all(metric.MetricName, key);
|
|
386
|
+
if (values.length > MAX_ATTR_VALUES) {
|
|
387
|
+
attrsTruncated = true;
|
|
388
|
+
attributes[key] = values.slice(0, MAX_ATTR_VALUES).map((v) => String(v.value));
|
|
389
|
+
} else attributes[key] = values.map((v) => String(v.value));
|
|
390
|
+
}
|
|
391
|
+
const resAttrKeysSql = `
|
|
392
|
+
SELECT DISTINCT json_each.key as key
|
|
393
|
+
FROM ${table}, json_each(ResourceAttributes)
|
|
394
|
+
WHERE MetricName = ?
|
|
395
|
+
`;
|
|
396
|
+
const resAttrKeys = this.sqliteConnection.prepare(resAttrKeysSql).all(metric.MetricName);
|
|
397
|
+
let resAttrsTruncated = false;
|
|
398
|
+
const resourceAttributes = {};
|
|
399
|
+
for (const { key } of resAttrKeys) {
|
|
400
|
+
const valuesSql = `
|
|
401
|
+
SELECT DISTINCT json_each.value as value
|
|
402
|
+
FROM ${table}, json_each(ResourceAttributes)
|
|
403
|
+
WHERE MetricName = ? AND json_each.key = ?
|
|
404
|
+
LIMIT ${MAX_ATTR_VALUES + 1}
|
|
405
|
+
`;
|
|
406
|
+
const values = this.sqliteConnection.prepare(valuesSql).all(metric.MetricName, key);
|
|
407
|
+
if (values.length > MAX_ATTR_VALUES) {
|
|
408
|
+
resAttrsTruncated = true;
|
|
409
|
+
resourceAttributes[key] = values.slice(0, MAX_ATTR_VALUES).map((v) => String(v.value));
|
|
410
|
+
} else resourceAttributes[key] = values.map((v) => String(v.value));
|
|
411
|
+
}
|
|
412
|
+
metrics.push({
|
|
413
|
+
name: metric.MetricName,
|
|
414
|
+
type: metric.MetricType,
|
|
415
|
+
unit: metric.MetricUnit || void 0,
|
|
416
|
+
description: metric.MetricDescription || void 0,
|
|
417
|
+
attributes: {
|
|
418
|
+
values: attributes,
|
|
419
|
+
...attrsTruncated && { _truncated: true }
|
|
420
|
+
},
|
|
421
|
+
resourceAttributes: {
|
|
422
|
+
values: resourceAttributes,
|
|
423
|
+
...resAttrsTruncated && { _truncated: true }
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
return { metrics };
|
|
428
|
+
} catch (error) {
|
|
429
|
+
if (error instanceof SqliteDatasourceQueryError) throw error;
|
|
430
|
+
throw new SqliteDatasourceQueryError("Failed to discover metrics", { cause: error });
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
function toSpanRow(resource, scope, span) {
|
|
435
|
+
const events = span.events ?? [];
|
|
436
|
+
const links = span.links ?? [];
|
|
437
|
+
const startNanos = nanosToSqlite(span.startTimeUnixNano);
|
|
438
|
+
const durationNanos = nanosToSqlite(span.endTimeUnixNano) - startNanos;
|
|
439
|
+
return {
|
|
440
|
+
TraceId: span.traceId ?? "",
|
|
441
|
+
SpanId: span.spanId ?? "",
|
|
442
|
+
ParentSpanId: span.parentSpanId ?? "",
|
|
443
|
+
TraceState: span.traceState ?? "",
|
|
444
|
+
SpanName: span.name ?? "",
|
|
445
|
+
SpanKind: spanKindToString(span.kind),
|
|
446
|
+
ServiceName: extractServiceName(resource),
|
|
447
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
448
|
+
ScopeName: scope?.name ?? "",
|
|
449
|
+
ScopeVersion: scope?.version ?? "",
|
|
450
|
+
SpanAttributes: keyValueArrayToJson(span.attributes),
|
|
451
|
+
Timestamp: startNanos,
|
|
452
|
+
Duration: durationNanos,
|
|
453
|
+
StatusCode: statusCodeToString(span.status?.code),
|
|
454
|
+
StatusMessage: span.status?.message ?? "",
|
|
455
|
+
"Events.Timestamp": JSON.stringify(events.map((e) => String(nanosToSqlite(e.timeUnixNano)))),
|
|
456
|
+
"Events.Name": JSON.stringify(events.map((e) => e.name ?? "")),
|
|
457
|
+
"Events.Attributes": JSON.stringify(events.map((e) => keyValueArrayToObject(e.attributes))),
|
|
458
|
+
"Links.TraceId": JSON.stringify(links.map((l) => l.traceId ?? "")),
|
|
459
|
+
"Links.SpanId": JSON.stringify(links.map((l) => l.spanId ?? "")),
|
|
460
|
+
"Links.TraceState": JSON.stringify(links.map((l) => l.traceState ?? "")),
|
|
461
|
+
"Links.Attributes": JSON.stringify(links.map((l) => keyValueArrayToObject(l.attributes)))
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
function toLogRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, logRecord) {
|
|
465
|
+
return {
|
|
466
|
+
Timestamp: nanosToSqlite(logRecord.timeUnixNano),
|
|
467
|
+
TraceId: logRecord.traceId ?? "",
|
|
468
|
+
SpanId: logRecord.spanId ?? "",
|
|
469
|
+
TraceFlags: logRecord.flags ?? 0,
|
|
470
|
+
SeverityText: logRecord.severityText ?? "",
|
|
471
|
+
SeverityNumber: logRecord.severityNumber ?? 0,
|
|
472
|
+
Body: anyValueToBodyString(logRecord.body),
|
|
473
|
+
LogAttributes: keyValueArrayToJson(logRecord.attributes),
|
|
474
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
475
|
+
ResourceSchemaUrl: resourceSchemaUrl ?? "",
|
|
476
|
+
ServiceName: extractServiceName(resource),
|
|
477
|
+
ScopeName: scope?.name ?? "",
|
|
478
|
+
ScopeVersion: scope?.version ?? "",
|
|
479
|
+
ScopeAttributes: keyValueArrayToJson(scope?.attributes),
|
|
480
|
+
ScopeSchemaUrl: scopeSchemaUrl ?? ""
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function spanKindToString(kind) {
|
|
484
|
+
if (kind === void 0) return "";
|
|
485
|
+
return otlp.SpanKind[kind] ?? "";
|
|
486
|
+
}
|
|
487
|
+
function statusCodeToString(code) {
|
|
488
|
+
if (code === void 0) return "";
|
|
489
|
+
return otlp.StatusCode[code] ?? "";
|
|
490
|
+
}
|
|
491
|
+
function toGaugeRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint) {
|
|
492
|
+
const exemplars = dataPoint.exemplars ?? [];
|
|
493
|
+
return {
|
|
494
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
495
|
+
ResourceSchemaUrl: resourceSchemaUrl ?? "",
|
|
496
|
+
ScopeName: scope?.name ?? "",
|
|
497
|
+
ScopeVersion: scope?.version ?? "",
|
|
498
|
+
ScopeAttributes: keyValueArrayToJson(scope?.attributes),
|
|
499
|
+
ScopeDroppedAttrCount: scope?.droppedAttributesCount ?? 0,
|
|
500
|
+
ScopeSchemaUrl: scopeSchemaUrl ?? "",
|
|
501
|
+
ServiceName: extractServiceName(resource),
|
|
502
|
+
MetricName: metric.name ?? "",
|
|
503
|
+
MetricDescription: metric.description ?? "",
|
|
504
|
+
MetricUnit: metric.unit ?? "",
|
|
505
|
+
Attributes: keyValueArrayToJson(dataPoint.attributes),
|
|
506
|
+
StartTimeUnix: nanosToSqlite(dataPoint.startTimeUnixNano),
|
|
507
|
+
TimeUnix: nanosToSqlite(dataPoint.timeUnixNano),
|
|
508
|
+
Value: dataPoint.asDouble ?? Number(dataPoint.asInt ?? 0),
|
|
509
|
+
Flags: dataPoint.flags ?? 0,
|
|
510
|
+
"Exemplars.FilteredAttributes": exemplarsArrayToJson(exemplars, (e) => keyValueArrayToObject(e.filteredAttributes)),
|
|
511
|
+
"Exemplars.TimeUnix": exemplarsArrayToJson(exemplars, (e) => String(nanosToSqlite(e.timeUnixNano))),
|
|
512
|
+
"Exemplars.Value": exemplarsArrayToJson(exemplars, (e) => e.asDouble ?? Number(e.asInt ?? 0)),
|
|
513
|
+
"Exemplars.SpanId": exemplarsArrayToJson(exemplars, (e) => e.spanId ?? ""),
|
|
514
|
+
"Exemplars.TraceId": exemplarsArrayToJson(exemplars, (e) => e.traceId ? bufferToHex(e.traceId) : "")
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function toSumRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint, aggregationTemporality, isMonotonic) {
|
|
518
|
+
const exemplars = dataPoint.exemplars ?? [];
|
|
519
|
+
return {
|
|
520
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
521
|
+
ResourceSchemaUrl: resourceSchemaUrl ?? "",
|
|
522
|
+
ScopeName: scope?.name ?? "",
|
|
523
|
+
ScopeVersion: scope?.version ?? "",
|
|
524
|
+
ScopeAttributes: keyValueArrayToJson(scope?.attributes),
|
|
525
|
+
ScopeDroppedAttrCount: scope?.droppedAttributesCount ?? 0,
|
|
526
|
+
ScopeSchemaUrl: scopeSchemaUrl ?? "",
|
|
527
|
+
ServiceName: extractServiceName(resource),
|
|
528
|
+
MetricName: metric.name ?? "",
|
|
529
|
+
MetricDescription: metric.description ?? "",
|
|
530
|
+
MetricUnit: metric.unit ?? "",
|
|
531
|
+
Attributes: keyValueArrayToJson(dataPoint.attributes),
|
|
532
|
+
StartTimeUnix: nanosToSqlite(dataPoint.startTimeUnixNano),
|
|
533
|
+
TimeUnix: nanosToSqlite(dataPoint.timeUnixNano),
|
|
534
|
+
Value: dataPoint.asDouble ?? Number(dataPoint.asInt ?? 0),
|
|
535
|
+
Flags: dataPoint.flags ?? 0,
|
|
536
|
+
"Exemplars.FilteredAttributes": exemplarsArrayToJson(exemplars, (e) => keyValueArrayToObject(e.filteredAttributes)),
|
|
537
|
+
"Exemplars.TimeUnix": exemplarsArrayToJson(exemplars, (e) => String(nanosToSqlite(e.timeUnixNano))),
|
|
538
|
+
"Exemplars.Value": exemplarsArrayToJson(exemplars, (e) => e.asDouble ?? Number(e.asInt ?? 0)),
|
|
539
|
+
"Exemplars.SpanId": exemplarsArrayToJson(exemplars, (e) => e.spanId ?? ""),
|
|
540
|
+
"Exemplars.TraceId": exemplarsArrayToJson(exemplars, (e) => e.traceId ? bufferToHex(e.traceId) : ""),
|
|
541
|
+
AggTemporality: aggTemporalityToString(aggregationTemporality),
|
|
542
|
+
IsMonotonic: isMonotonic ? 1 : 0
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function toHistogramRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint, aggregationTemporality) {
|
|
546
|
+
const exemplars = dataPoint.exemplars ?? [];
|
|
547
|
+
return {
|
|
548
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
549
|
+
ResourceSchemaUrl: resourceSchemaUrl ?? "",
|
|
550
|
+
ScopeName: scope?.name ?? "",
|
|
551
|
+
ScopeVersion: scope?.version ?? "",
|
|
552
|
+
ScopeAttributes: keyValueArrayToJson(scope?.attributes),
|
|
553
|
+
ScopeDroppedAttrCount: scope?.droppedAttributesCount ?? 0,
|
|
554
|
+
ScopeSchemaUrl: scopeSchemaUrl ?? "",
|
|
555
|
+
ServiceName: extractServiceName(resource),
|
|
556
|
+
MetricName: metric.name ?? "",
|
|
557
|
+
MetricDescription: metric.description ?? "",
|
|
558
|
+
MetricUnit: metric.unit ?? "",
|
|
559
|
+
Attributes: keyValueArrayToJson(dataPoint.attributes),
|
|
560
|
+
StartTimeUnix: nanosToSqlite(dataPoint.startTimeUnixNano),
|
|
561
|
+
TimeUnix: nanosToSqlite(dataPoint.timeUnixNano),
|
|
562
|
+
Count: Number(dataPoint.count ?? 0),
|
|
563
|
+
Sum: dataPoint.sum ?? 0,
|
|
564
|
+
BucketCounts: JSON.stringify(dataPoint.bucketCounts ?? []),
|
|
565
|
+
ExplicitBounds: JSON.stringify(dataPoint.explicitBounds ?? []),
|
|
566
|
+
Min: dataPoint.min ?? null,
|
|
567
|
+
Max: dataPoint.max ?? null,
|
|
568
|
+
"Exemplars.FilteredAttributes": exemplarsArrayToJson(exemplars, (e) => keyValueArrayToObject(e.filteredAttributes)),
|
|
569
|
+
"Exemplars.TimeUnix": exemplarsArrayToJson(exemplars, (e) => String(nanosToSqlite(e.timeUnixNano))),
|
|
570
|
+
"Exemplars.Value": exemplarsArrayToJson(exemplars, (e) => e.asDouble ?? Number(e.asInt ?? 0)),
|
|
571
|
+
"Exemplars.SpanId": exemplarsArrayToJson(exemplars, (e) => e.spanId ?? ""),
|
|
572
|
+
"Exemplars.TraceId": exemplarsArrayToJson(exemplars, (e) => e.traceId ? bufferToHex(e.traceId) : ""),
|
|
573
|
+
AggTemporality: aggTemporalityToString(aggregationTemporality)
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
function toExpHistogramRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint, aggregationTemporality) {
|
|
577
|
+
const exemplars = dataPoint.exemplars ?? [];
|
|
578
|
+
return {
|
|
579
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
580
|
+
ResourceSchemaUrl: resourceSchemaUrl ?? "",
|
|
581
|
+
ScopeName: scope?.name ?? "",
|
|
582
|
+
ScopeVersion: scope?.version ?? "",
|
|
583
|
+
ScopeAttributes: keyValueArrayToJson(scope?.attributes),
|
|
584
|
+
ScopeDroppedAttrCount: scope?.droppedAttributesCount ?? 0,
|
|
585
|
+
ScopeSchemaUrl: scopeSchemaUrl ?? "",
|
|
586
|
+
ServiceName: extractServiceName(resource),
|
|
587
|
+
MetricName: metric.name ?? "",
|
|
588
|
+
MetricDescription: metric.description ?? "",
|
|
589
|
+
MetricUnit: metric.unit ?? "",
|
|
590
|
+
Attributes: keyValueArrayToJson(dataPoint.attributes),
|
|
591
|
+
StartTimeUnix: nanosToSqlite(dataPoint.startTimeUnixNano),
|
|
592
|
+
TimeUnix: nanosToSqlite(dataPoint.timeUnixNano),
|
|
593
|
+
Count: Number(dataPoint.count ?? 0),
|
|
594
|
+
Sum: dataPoint.sum ?? 0,
|
|
595
|
+
Scale: dataPoint.scale ?? 0,
|
|
596
|
+
ZeroCount: Number(dataPoint.zeroCount ?? 0),
|
|
597
|
+
PositiveOffset: dataPoint.positive?.offset ?? 0,
|
|
598
|
+
PositiveBucketCounts: JSON.stringify(dataPoint.positive?.bucketCounts ?? []),
|
|
599
|
+
NegativeOffset: dataPoint.negative?.offset ?? 0,
|
|
600
|
+
NegativeBucketCounts: JSON.stringify(dataPoint.negative?.bucketCounts ?? []),
|
|
601
|
+
Min: dataPoint.min ?? null,
|
|
602
|
+
Max: dataPoint.max ?? null,
|
|
603
|
+
ZeroThreshold: dataPoint.zeroThreshold ?? 0,
|
|
604
|
+
"Exemplars.FilteredAttributes": exemplarsArrayToJson(exemplars, (e) => keyValueArrayToObject(e.filteredAttributes)),
|
|
605
|
+
"Exemplars.TimeUnix": exemplarsArrayToJson(exemplars, (e) => String(nanosToSqlite(e.timeUnixNano))),
|
|
606
|
+
"Exemplars.Value": exemplarsArrayToJson(exemplars, (e) => e.asDouble ?? Number(e.asInt ?? 0)),
|
|
607
|
+
"Exemplars.SpanId": exemplarsArrayToJson(exemplars, (e) => e.spanId ?? ""),
|
|
608
|
+
"Exemplars.TraceId": exemplarsArrayToJson(exemplars, (e) => e.traceId ? bufferToHex(e.traceId) : ""),
|
|
609
|
+
AggTemporality: aggTemporalityToString(aggregationTemporality)
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
function toSummaryRow(resource, resourceSchemaUrl, scope, scopeSchemaUrl, metric, dataPoint) {
|
|
613
|
+
const quantileValues = dataPoint.quantileValues ?? [];
|
|
614
|
+
return {
|
|
615
|
+
ResourceAttributes: keyValueArrayToJson(resource?.attributes),
|
|
616
|
+
ResourceSchemaUrl: resourceSchemaUrl ?? "",
|
|
617
|
+
ScopeName: scope?.name ?? "",
|
|
618
|
+
ScopeVersion: scope?.version ?? "",
|
|
619
|
+
ScopeAttributes: keyValueArrayToJson(scope?.attributes),
|
|
620
|
+
ScopeDroppedAttrCount: scope?.droppedAttributesCount ?? 0,
|
|
621
|
+
ScopeSchemaUrl: scopeSchemaUrl ?? "",
|
|
622
|
+
ServiceName: extractServiceName(resource),
|
|
623
|
+
MetricName: metric.name ?? "",
|
|
624
|
+
MetricDescription: metric.description ?? "",
|
|
625
|
+
MetricUnit: metric.unit ?? "",
|
|
626
|
+
Attributes: keyValueArrayToJson(dataPoint.attributes),
|
|
627
|
+
StartTimeUnix: nanosToSqlite(dataPoint.startTimeUnixNano),
|
|
628
|
+
TimeUnix: nanosToSqlite(dataPoint.timeUnixNano),
|
|
629
|
+
Count: Number(dataPoint.count ?? 0),
|
|
630
|
+
Sum: dataPoint.sum ?? 0,
|
|
631
|
+
"ValueAtQuantiles.Quantile": JSON.stringify(quantileValues.map((q) => q.quantile ?? 0)),
|
|
632
|
+
"ValueAtQuantiles.Value": JSON.stringify(quantileValues.map((q) => q.value ?? 0))
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function aggTemporalityToString(agg) {
|
|
636
|
+
if (agg === void 0) return "";
|
|
637
|
+
return otlp.AggregationTemporality[agg] ?? "";
|
|
638
|
+
}
|
|
639
|
+
function anyValueToSimple(value) {
|
|
640
|
+
if (!value) return null;
|
|
641
|
+
if (value.stringValue !== void 0) return value.stringValue;
|
|
642
|
+
if (value.boolValue !== void 0) return value.boolValue;
|
|
643
|
+
if (value.intValue !== void 0) return value.intValue;
|
|
644
|
+
if (value.doubleValue !== void 0) return value.doubleValue;
|
|
645
|
+
if (value.bytesValue !== void 0) return value.bytesValue;
|
|
646
|
+
if (value.arrayValue !== void 0) return value.arrayValue.values?.map((v) => anyValueToSimple(v)) ?? [];
|
|
647
|
+
if (value.kvlistValue !== void 0) {
|
|
648
|
+
const obj = {};
|
|
649
|
+
for (const kv of value.kvlistValue.values ?? []) if (kv.key) obj[kv.key] = anyValueToSimple(kv.value);
|
|
650
|
+
return obj;
|
|
651
|
+
}
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
function anyValueToBodyString(value) {
|
|
655
|
+
const simple = anyValueToSimple(value);
|
|
656
|
+
if (typeof simple === "string") return simple;
|
|
657
|
+
return JSON.stringify(simple);
|
|
658
|
+
}
|
|
659
|
+
function keyValueArrayToObject(attrs) {
|
|
660
|
+
const obj = {};
|
|
661
|
+
if (!attrs) return obj;
|
|
662
|
+
for (const kv of attrs) if (kv.key) obj[kv.key] = anyValueToSimple(kv.value);
|
|
663
|
+
return obj;
|
|
664
|
+
}
|
|
665
|
+
function keyValueArrayToJson(attrs) {
|
|
666
|
+
if (!attrs || attrs.length === 0) return "{}";
|
|
667
|
+
return JSON.stringify(keyValueArrayToObject(attrs));
|
|
668
|
+
}
|
|
669
|
+
function extractServiceName(resource) {
|
|
670
|
+
if (!resource?.attributes) return "";
|
|
671
|
+
for (const kv of resource.attributes) if (kv.key === "service.name" && kv.value?.stringValue) return kv.value.stringValue;
|
|
672
|
+
return "";
|
|
673
|
+
}
|
|
674
|
+
function nanosToSqlite(nanos) {
|
|
675
|
+
return BigInt(nanos ?? "0");
|
|
676
|
+
}
|
|
677
|
+
function exemplarsArrayToJson(exemplars, extractor) {
|
|
678
|
+
if (exemplars.length === 0) return "[]";
|
|
679
|
+
return JSON.stringify(exemplars.map(extractor));
|
|
680
|
+
}
|
|
681
|
+
function bufferToHex(buf) {
|
|
682
|
+
return Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
683
|
+
}
|
|
684
|
+
function mapRowToOtelTraces(row) {
|
|
685
|
+
return {
|
|
686
|
+
TraceId: row.TraceId,
|
|
687
|
+
SpanId: row.SpanId,
|
|
688
|
+
Timestamp: String(row.Timestamp),
|
|
689
|
+
ParentSpanId: row.ParentSpanId,
|
|
690
|
+
TraceState: row.TraceState,
|
|
691
|
+
SpanName: row.SpanName,
|
|
692
|
+
SpanKind: row.SpanKind,
|
|
693
|
+
ServiceName: row.ServiceName,
|
|
694
|
+
ResourceAttributes: parseJsonField(row.ResourceAttributes),
|
|
695
|
+
ScopeName: row.ScopeName,
|
|
696
|
+
ScopeVersion: row.ScopeVersion,
|
|
697
|
+
SpanAttributes: parseJsonField(row.SpanAttributes),
|
|
698
|
+
Duration: row.Duration != null ? String(row.Duration) : void 0,
|
|
699
|
+
StatusCode: row.StatusCode,
|
|
700
|
+
StatusMessage: row.StatusMessage,
|
|
701
|
+
"Events.Timestamp": parseStringArrayField(row["Events.Timestamp"]),
|
|
702
|
+
"Events.Name": parseStringArrayField(row["Events.Name"]),
|
|
703
|
+
"Events.Attributes": parseJsonArrayField(row["Events.Attributes"]),
|
|
704
|
+
"Links.TraceId": parseStringArrayField(row["Links.TraceId"]),
|
|
705
|
+
"Links.SpanId": parseStringArrayField(row["Links.SpanId"]),
|
|
706
|
+
"Links.TraceState": parseStringArrayField(row["Links.TraceState"]),
|
|
707
|
+
"Links.Attributes": parseJsonArrayField(row["Links.Attributes"])
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function parseJsonField(value) {
|
|
711
|
+
if (typeof value !== "string") return void 0;
|
|
712
|
+
try {
|
|
713
|
+
return JSON.parse(value);
|
|
714
|
+
} catch {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
function parseJsonArrayField(value) {
|
|
719
|
+
if (typeof value !== "string") return void 0;
|
|
720
|
+
try {
|
|
721
|
+
return JSON.parse(value);
|
|
722
|
+
} catch {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
function parseStringArrayField(value) {
|
|
727
|
+
if (typeof value !== "string") return void 0;
|
|
728
|
+
try {
|
|
729
|
+
return JSON.parse(value);
|
|
730
|
+
} catch {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
function parseNumberArrayField(value) {
|
|
735
|
+
if (typeof value !== "string") return void 0;
|
|
736
|
+
try {
|
|
737
|
+
return JSON.parse(value);
|
|
738
|
+
} catch {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
function toNumber(value) {
|
|
743
|
+
if (value == null) return void 0;
|
|
744
|
+
if (typeof value === "bigint") return Number(value);
|
|
745
|
+
if (typeof value === "number") return value;
|
|
746
|
+
}
|
|
747
|
+
function mapRowToOtelLogs(row) {
|
|
748
|
+
return {
|
|
749
|
+
Timestamp: String(row.Timestamp),
|
|
750
|
+
TraceId: row.TraceId,
|
|
751
|
+
SpanId: row.SpanId,
|
|
752
|
+
TraceFlags: toNumber(row.TraceFlags),
|
|
753
|
+
SeverityText: row.SeverityText,
|
|
754
|
+
SeverityNumber: toNumber(row.SeverityNumber),
|
|
755
|
+
Body: row.Body,
|
|
756
|
+
LogAttributes: parseJsonField(row.LogAttributes),
|
|
757
|
+
ResourceAttributes: parseJsonField(row.ResourceAttributes),
|
|
758
|
+
ResourceSchemaUrl: row.ResourceSchemaUrl,
|
|
759
|
+
ServiceName: row.ServiceName,
|
|
760
|
+
ScopeName: row.ScopeName,
|
|
761
|
+
ScopeVersion: row.ScopeVersion,
|
|
762
|
+
ScopeAttributes: parseJsonField(row.ScopeAttributes),
|
|
763
|
+
ScopeSchemaUrl: row.ScopeSchemaUrl
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
const METRIC_TABLES = [
|
|
767
|
+
{
|
|
768
|
+
table: "otel_metrics_gauge",
|
|
769
|
+
type: "Gauge"
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
table: "otel_metrics_sum",
|
|
773
|
+
type: "Sum"
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
table: "otel_metrics_histogram",
|
|
777
|
+
type: "Histogram"
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
table: "otel_metrics_exponential_histogram",
|
|
781
|
+
type: "ExponentialHistogram"
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
table: "otel_metrics_summary",
|
|
785
|
+
type: "Summary"
|
|
786
|
+
}
|
|
787
|
+
];
|
|
788
|
+
const MAX_ATTR_VALUES = 100;
|
|
789
|
+
function mapRowToOtelMetrics(row, metricType) {
|
|
790
|
+
const base = {
|
|
791
|
+
TimeUnix: String(row.TimeUnix),
|
|
792
|
+
StartTimeUnix: String(row.StartTimeUnix),
|
|
793
|
+
Attributes: parseJsonField(row.Attributes),
|
|
794
|
+
MetricName: row.MetricName,
|
|
795
|
+
MetricDescription: row.MetricDescription,
|
|
796
|
+
MetricUnit: row.MetricUnit,
|
|
797
|
+
ResourceAttributes: parseJsonField(row.ResourceAttributes),
|
|
798
|
+
ResourceSchemaUrl: row.ResourceSchemaUrl,
|
|
799
|
+
ScopeAttributes: parseJsonField(row.ScopeAttributes),
|
|
800
|
+
ScopeDroppedAttrCount: toNumber(row.ScopeDroppedAttrCount),
|
|
801
|
+
ScopeName: row.ScopeName,
|
|
802
|
+
ScopeSchemaUrl: row.ScopeSchemaUrl,
|
|
803
|
+
ScopeVersion: row.ScopeVersion,
|
|
804
|
+
ServiceName: row.ServiceName,
|
|
805
|
+
"Exemplars.FilteredAttributes": parseJsonArrayField(row["Exemplars.FilteredAttributes"]),
|
|
806
|
+
"Exemplars.SpanId": parseStringArrayField(row["Exemplars.SpanId"]),
|
|
807
|
+
"Exemplars.TimeUnix": parseStringArrayField(row["Exemplars.TimeUnix"]),
|
|
808
|
+
"Exemplars.TraceId": parseStringArrayField(row["Exemplars.TraceId"]),
|
|
809
|
+
"Exemplars.Value": parseNumberArrayField(row["Exemplars.Value"])
|
|
810
|
+
};
|
|
811
|
+
if (metricType === "Gauge") return {
|
|
812
|
+
...base,
|
|
813
|
+
MetricType: "Gauge",
|
|
814
|
+
Value: row.Value,
|
|
815
|
+
Flags: toNumber(row.Flags)
|
|
816
|
+
};
|
|
817
|
+
if (metricType === "Sum") return {
|
|
818
|
+
...base,
|
|
819
|
+
MetricType: "Sum",
|
|
820
|
+
Value: row.Value,
|
|
821
|
+
Flags: toNumber(row.Flags),
|
|
822
|
+
AggTemporality: row.AggTemporality,
|
|
823
|
+
IsMonotonic: toNumber(row.IsMonotonic)
|
|
824
|
+
};
|
|
825
|
+
if (metricType === "Histogram") return {
|
|
826
|
+
...base,
|
|
827
|
+
MetricType: "Histogram",
|
|
828
|
+
Count: toNumber(row.Count),
|
|
829
|
+
Sum: row.Sum,
|
|
830
|
+
Min: row.Min,
|
|
831
|
+
Max: row.Max,
|
|
832
|
+
BucketCounts: parseNumberArrayField(row.BucketCounts),
|
|
833
|
+
ExplicitBounds: parseNumberArrayField(row.ExplicitBounds),
|
|
834
|
+
AggTemporality: row.AggTemporality
|
|
835
|
+
};
|
|
836
|
+
if (metricType === "ExponentialHistogram") return {
|
|
837
|
+
...base,
|
|
838
|
+
MetricType: "ExponentialHistogram",
|
|
839
|
+
Count: toNumber(row.Count),
|
|
840
|
+
Sum: row.Sum,
|
|
841
|
+
Min: row.Min,
|
|
842
|
+
Max: row.Max,
|
|
843
|
+
Scale: toNumber(row.Scale),
|
|
844
|
+
ZeroCount: toNumber(row.ZeroCount),
|
|
845
|
+
PositiveOffset: toNumber(row.PositiveOffset),
|
|
846
|
+
PositiveBucketCounts: parseNumberArrayField(row.PositiveBucketCounts),
|
|
847
|
+
NegativeOffset: toNumber(row.NegativeOffset),
|
|
848
|
+
NegativeBucketCounts: parseNumberArrayField(row.NegativeBucketCounts),
|
|
849
|
+
AggTemporality: row.AggTemporality
|
|
850
|
+
};
|
|
851
|
+
return {
|
|
852
|
+
...base,
|
|
853
|
+
MetricType: "Summary",
|
|
854
|
+
Count: toNumber(row.Count),
|
|
855
|
+
Sum: row.Sum,
|
|
856
|
+
"ValueAtQuantiles.Quantile": parseNumberArrayField(row["ValueAtQuantiles.Quantile"]),
|
|
857
|
+
"ValueAtQuantiles.Value": parseNumberArrayField(row["ValueAtQuantiles.Value"])
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
//#endregion
|
|
862
|
+
//#region src/sqlite-opentelemetry-ddl.ts
|
|
863
|
+
const ddl = `
|
|
864
|
+
-- OpenTelemetry SQLite Schema
|
|
865
|
+
-- Migrated from ClickHouse OTEL exporter schema v0.136.0
|
|
866
|
+
--
|
|
867
|
+
-- Conversion notes:
|
|
868
|
+
-- - Map/Array types → JSON TEXT columns
|
|
869
|
+
-- - DateTime64(9) → INTEGER (unix nanoseconds)
|
|
870
|
+
-- - LowCardinality(String) → TEXT (CH optimization removed)
|
|
871
|
+
-- - Removed: CODEC compression, PARTITION BY, TTL, bloom filters, MergeTree engine
|
|
872
|
+
-- - Skipped: otel_traces_trace_id_ts_mv materialized view
|
|
873
|
+
-- - Column names with dots (e.g. "Events.Timestamp") preserved for compatibility
|
|
874
|
+
--
|
|
875
|
+
-- Source: /k8s/migrations/clickhouse/002-otel-schema-v136.sql
|
|
876
|
+
|
|
877
|
+
-- =============================================================================
|
|
878
|
+
-- 1. LOGS TABLE
|
|
879
|
+
-- =============================================================================
|
|
880
|
+
|
|
881
|
+
CREATE TABLE IF NOT EXISTS otel_logs (
|
|
882
|
+
Timestamp INTEGER NOT NULL,
|
|
883
|
+
TimestampTime INTEGER GENERATED ALWAYS AS (Timestamp / 1000000000) STORED,
|
|
884
|
+
TraceId TEXT NOT NULL DEFAULT '',
|
|
885
|
+
SpanId TEXT NOT NULL DEFAULT '',
|
|
886
|
+
TraceFlags INTEGER NOT NULL DEFAULT 0,
|
|
887
|
+
SeverityText TEXT NOT NULL DEFAULT '',
|
|
888
|
+
SeverityNumber INTEGER NOT NULL DEFAULT 0,
|
|
889
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
890
|
+
Body TEXT NOT NULL DEFAULT '',
|
|
891
|
+
ResourceSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
892
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
893
|
+
ScopeSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
894
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
895
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
896
|
+
ScopeAttributes TEXT NOT NULL DEFAULT '{}',
|
|
897
|
+
LogAttributes TEXT NOT NULL DEFAULT '{}'
|
|
898
|
+
);
|
|
899
|
+
|
|
900
|
+
CREATE INDEX IF NOT EXISTS idx_otel_logs_service_time ON otel_logs (ServiceName, TimestampTime);
|
|
901
|
+
CREATE INDEX IF NOT EXISTS idx_otel_logs_trace_id ON otel_logs (TraceId) WHERE TraceId != '';
|
|
902
|
+
CREATE INDEX IF NOT EXISTS idx_otel_logs_severity ON otel_logs (SeverityNumber);
|
|
903
|
+
|
|
904
|
+
-- =============================================================================
|
|
905
|
+
-- 2. TRACES TABLE
|
|
906
|
+
-- =============================================================================
|
|
907
|
+
|
|
908
|
+
CREATE TABLE IF NOT EXISTS otel_traces (
|
|
909
|
+
Timestamp INTEGER NOT NULL,
|
|
910
|
+
TraceId TEXT NOT NULL,
|
|
911
|
+
SpanId TEXT NOT NULL,
|
|
912
|
+
ParentSpanId TEXT NOT NULL DEFAULT '',
|
|
913
|
+
TraceState TEXT NOT NULL DEFAULT '',
|
|
914
|
+
SpanName TEXT NOT NULL DEFAULT '',
|
|
915
|
+
SpanKind TEXT NOT NULL DEFAULT '',
|
|
916
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
917
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
918
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
919
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
920
|
+
SpanAttributes TEXT NOT NULL DEFAULT '{}',
|
|
921
|
+
Duration INTEGER NOT NULL DEFAULT 0,
|
|
922
|
+
StatusCode TEXT NOT NULL DEFAULT '',
|
|
923
|
+
StatusMessage TEXT NOT NULL DEFAULT '',
|
|
924
|
+
"Events.Timestamp" TEXT NOT NULL DEFAULT '[]',
|
|
925
|
+
"Events.Name" TEXT NOT NULL DEFAULT '[]',
|
|
926
|
+
"Events.Attributes" TEXT NOT NULL DEFAULT '[]',
|
|
927
|
+
"Links.TraceId" TEXT NOT NULL DEFAULT '[]',
|
|
928
|
+
"Links.SpanId" TEXT NOT NULL DEFAULT '[]',
|
|
929
|
+
"Links.TraceState" TEXT NOT NULL DEFAULT '[]',
|
|
930
|
+
"Links.Attributes" TEXT NOT NULL DEFAULT '[]'
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
CREATE INDEX IF NOT EXISTS idx_otel_traces_service_span_time ON otel_traces (ServiceName, SpanName, Timestamp);
|
|
934
|
+
CREATE INDEX IF NOT EXISTS idx_otel_traces_trace_id ON otel_traces (TraceId);
|
|
935
|
+
CREATE INDEX IF NOT EXISTS idx_otel_traces_parent_span ON otel_traces (ParentSpanId) WHERE ParentSpanId != '';
|
|
936
|
+
CREATE INDEX IF NOT EXISTS idx_otel_traces_duration ON otel_traces (Duration);
|
|
937
|
+
CREATE INDEX IF NOT EXISTS idx_otel_traces_timestamp_span ON otel_traces (Timestamp, SpanId);
|
|
938
|
+
|
|
939
|
+
-- =============================================================================
|
|
940
|
+
-- 3. TRACE LOOKUP TABLE
|
|
941
|
+
-- =============================================================================
|
|
942
|
+
|
|
943
|
+
CREATE TABLE IF NOT EXISTS otel_traces_trace_id_ts (
|
|
944
|
+
TraceId TEXT NOT NULL PRIMARY KEY,
|
|
945
|
+
Start INTEGER NOT NULL,
|
|
946
|
+
End INTEGER NOT NULL
|
|
947
|
+
);
|
|
948
|
+
|
|
949
|
+
CREATE INDEX IF NOT EXISTS idx_otel_traces_trace_id_ts_start ON otel_traces_trace_id_ts (Start);
|
|
950
|
+
|
|
951
|
+
-- =============================================================================
|
|
952
|
+
-- 4. METRICS - GAUGE TABLE
|
|
953
|
+
-- =============================================================================
|
|
954
|
+
|
|
955
|
+
CREATE TABLE IF NOT EXISTS otel_metrics_gauge (
|
|
956
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
957
|
+
ResourceSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
958
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
959
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
960
|
+
ScopeAttributes TEXT NOT NULL DEFAULT '{}',
|
|
961
|
+
ScopeDroppedAttrCount INTEGER NOT NULL DEFAULT 0,
|
|
962
|
+
ScopeSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
963
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
964
|
+
MetricName TEXT NOT NULL DEFAULT '',
|
|
965
|
+
MetricDescription TEXT NOT NULL DEFAULT '',
|
|
966
|
+
MetricUnit TEXT NOT NULL DEFAULT '',
|
|
967
|
+
Attributes TEXT NOT NULL DEFAULT '{}',
|
|
968
|
+
StartTimeUnix INTEGER NOT NULL,
|
|
969
|
+
TimeUnix INTEGER NOT NULL,
|
|
970
|
+
Value REAL NOT NULL,
|
|
971
|
+
Flags INTEGER NOT NULL DEFAULT 0,
|
|
972
|
+
"Exemplars.FilteredAttributes" TEXT NOT NULL DEFAULT '[]',
|
|
973
|
+
"Exemplars.TimeUnix" TEXT NOT NULL DEFAULT '[]',
|
|
974
|
+
"Exemplars.Value" TEXT NOT NULL DEFAULT '[]',
|
|
975
|
+
"Exemplars.SpanId" TEXT NOT NULL DEFAULT '[]',
|
|
976
|
+
"Exemplars.TraceId" TEXT NOT NULL DEFAULT '[]'
|
|
977
|
+
);
|
|
978
|
+
|
|
979
|
+
CREATE INDEX IF NOT EXISTS idx_otel_metrics_gauge_service_metric_time ON otel_metrics_gauge (ServiceName, MetricName, TimeUnix);
|
|
980
|
+
|
|
981
|
+
-- =============================================================================
|
|
982
|
+
-- 5. METRICS - SUM TABLE
|
|
983
|
+
-- =============================================================================
|
|
984
|
+
|
|
985
|
+
CREATE TABLE IF NOT EXISTS otel_metrics_sum (
|
|
986
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
987
|
+
ResourceSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
988
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
989
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
990
|
+
ScopeAttributes TEXT NOT NULL DEFAULT '{}',
|
|
991
|
+
ScopeDroppedAttrCount INTEGER NOT NULL DEFAULT 0,
|
|
992
|
+
ScopeSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
993
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
994
|
+
MetricName TEXT NOT NULL DEFAULT '',
|
|
995
|
+
MetricDescription TEXT NOT NULL DEFAULT '',
|
|
996
|
+
MetricUnit TEXT NOT NULL DEFAULT '',
|
|
997
|
+
Attributes TEXT NOT NULL DEFAULT '{}',
|
|
998
|
+
StartTimeUnix INTEGER NOT NULL,
|
|
999
|
+
TimeUnix INTEGER NOT NULL,
|
|
1000
|
+
Value REAL NOT NULL,
|
|
1001
|
+
Flags INTEGER NOT NULL DEFAULT 0,
|
|
1002
|
+
"Exemplars.FilteredAttributes" TEXT NOT NULL DEFAULT '[]',
|
|
1003
|
+
"Exemplars.TimeUnix" TEXT NOT NULL DEFAULT '[]',
|
|
1004
|
+
"Exemplars.Value" TEXT NOT NULL DEFAULT '[]',
|
|
1005
|
+
"Exemplars.SpanId" TEXT NOT NULL DEFAULT '[]',
|
|
1006
|
+
"Exemplars.TraceId" TEXT NOT NULL DEFAULT '[]',
|
|
1007
|
+
AggTemporality TEXT NOT NULL DEFAULT '',
|
|
1008
|
+
IsMonotonic INTEGER NOT NULL DEFAULT 0
|
|
1009
|
+
);
|
|
1010
|
+
|
|
1011
|
+
CREATE INDEX IF NOT EXISTS idx_otel_metrics_sum_service_metric_time ON otel_metrics_sum (ServiceName, MetricName, TimeUnix);
|
|
1012
|
+
|
|
1013
|
+
-- =============================================================================
|
|
1014
|
+
-- 6. METRICS - HISTOGRAM TABLE
|
|
1015
|
+
-- =============================================================================
|
|
1016
|
+
|
|
1017
|
+
CREATE TABLE IF NOT EXISTS otel_metrics_histogram (
|
|
1018
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
1019
|
+
ResourceSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
1020
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
1021
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
1022
|
+
ScopeAttributes TEXT NOT NULL DEFAULT '{}',
|
|
1023
|
+
ScopeDroppedAttrCount INTEGER NOT NULL DEFAULT 0,
|
|
1024
|
+
ScopeSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
1025
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
1026
|
+
MetricName TEXT NOT NULL DEFAULT '',
|
|
1027
|
+
MetricDescription TEXT NOT NULL DEFAULT '',
|
|
1028
|
+
MetricUnit TEXT NOT NULL DEFAULT '',
|
|
1029
|
+
Attributes TEXT NOT NULL DEFAULT '{}',
|
|
1030
|
+
StartTimeUnix INTEGER NOT NULL,
|
|
1031
|
+
TimeUnix INTEGER NOT NULL,
|
|
1032
|
+
Count INTEGER NOT NULL DEFAULT 0,
|
|
1033
|
+
Sum REAL NOT NULL DEFAULT 0,
|
|
1034
|
+
BucketCounts TEXT NOT NULL DEFAULT '[]',
|
|
1035
|
+
ExplicitBounds TEXT NOT NULL DEFAULT '[]',
|
|
1036
|
+
"Exemplars.FilteredAttributes" TEXT NOT NULL DEFAULT '[]',
|
|
1037
|
+
"Exemplars.TimeUnix" TEXT NOT NULL DEFAULT '[]',
|
|
1038
|
+
"Exemplars.Value" TEXT NOT NULL DEFAULT '[]',
|
|
1039
|
+
"Exemplars.SpanId" TEXT NOT NULL DEFAULT '[]',
|
|
1040
|
+
"Exemplars.TraceId" TEXT NOT NULL DEFAULT '[]',
|
|
1041
|
+
Min REAL,
|
|
1042
|
+
Max REAL,
|
|
1043
|
+
AggTemporality TEXT NOT NULL DEFAULT ''
|
|
1044
|
+
);
|
|
1045
|
+
|
|
1046
|
+
CREATE INDEX IF NOT EXISTS idx_otel_metrics_histogram_service_metric_time ON otel_metrics_histogram (ServiceName, MetricName, TimeUnix);
|
|
1047
|
+
|
|
1048
|
+
-- =============================================================================
|
|
1049
|
+
-- 7. METRICS - EXPONENTIAL HISTOGRAM TABLE
|
|
1050
|
+
-- =============================================================================
|
|
1051
|
+
|
|
1052
|
+
CREATE TABLE IF NOT EXISTS otel_metrics_exponential_histogram (
|
|
1053
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
1054
|
+
ResourceSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
1055
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
1056
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
1057
|
+
ScopeAttributes TEXT NOT NULL DEFAULT '{}',
|
|
1058
|
+
ScopeDroppedAttrCount INTEGER NOT NULL DEFAULT 0,
|
|
1059
|
+
ScopeSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
1060
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
1061
|
+
MetricName TEXT NOT NULL DEFAULT '',
|
|
1062
|
+
MetricDescription TEXT NOT NULL DEFAULT '',
|
|
1063
|
+
MetricUnit TEXT NOT NULL DEFAULT '',
|
|
1064
|
+
Attributes TEXT NOT NULL DEFAULT '{}',
|
|
1065
|
+
StartTimeUnix INTEGER NOT NULL,
|
|
1066
|
+
TimeUnix INTEGER NOT NULL,
|
|
1067
|
+
Count INTEGER NOT NULL DEFAULT 0,
|
|
1068
|
+
Sum REAL NOT NULL DEFAULT 0,
|
|
1069
|
+
Scale INTEGER NOT NULL DEFAULT 0,
|
|
1070
|
+
ZeroCount INTEGER NOT NULL DEFAULT 0,
|
|
1071
|
+
PositiveOffset INTEGER NOT NULL DEFAULT 0,
|
|
1072
|
+
PositiveBucketCounts TEXT NOT NULL DEFAULT '[]',
|
|
1073
|
+
NegativeOffset INTEGER NOT NULL DEFAULT 0,
|
|
1074
|
+
NegativeBucketCounts TEXT NOT NULL DEFAULT '[]',
|
|
1075
|
+
"Exemplars.FilteredAttributes" TEXT NOT NULL DEFAULT '[]',
|
|
1076
|
+
"Exemplars.TimeUnix" TEXT NOT NULL DEFAULT '[]',
|
|
1077
|
+
"Exemplars.Value" TEXT NOT NULL DEFAULT '[]',
|
|
1078
|
+
"Exemplars.SpanId" TEXT NOT NULL DEFAULT '[]',
|
|
1079
|
+
"Exemplars.TraceId" TEXT NOT NULL DEFAULT '[]',
|
|
1080
|
+
Min REAL,
|
|
1081
|
+
Max REAL,
|
|
1082
|
+
ZeroThreshold REAL NOT NULL DEFAULT 0,
|
|
1083
|
+
AggTemporality TEXT NOT NULL DEFAULT ''
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
CREATE INDEX IF NOT EXISTS idx_otel_metrics_exp_histogram_service_metric_time ON otel_metrics_exponential_histogram (ServiceName, MetricName, TimeUnix);
|
|
1087
|
+
|
|
1088
|
+
-- =============================================================================
|
|
1089
|
+
-- 8. METRICS - SUMMARY TABLE
|
|
1090
|
+
-- =============================================================================
|
|
1091
|
+
|
|
1092
|
+
CREATE TABLE IF NOT EXISTS otel_metrics_summary (
|
|
1093
|
+
ResourceAttributes TEXT NOT NULL DEFAULT '{}',
|
|
1094
|
+
ResourceSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
1095
|
+
ScopeName TEXT NOT NULL DEFAULT '',
|
|
1096
|
+
ScopeVersion TEXT NOT NULL DEFAULT '',
|
|
1097
|
+
ScopeAttributes TEXT NOT NULL DEFAULT '{}',
|
|
1098
|
+
ScopeDroppedAttrCount INTEGER NOT NULL DEFAULT 0,
|
|
1099
|
+
ScopeSchemaUrl TEXT NOT NULL DEFAULT '',
|
|
1100
|
+
ServiceName TEXT NOT NULL DEFAULT '',
|
|
1101
|
+
MetricName TEXT NOT NULL DEFAULT '',
|
|
1102
|
+
MetricDescription TEXT NOT NULL DEFAULT '',
|
|
1103
|
+
MetricUnit TEXT NOT NULL DEFAULT '',
|
|
1104
|
+
Attributes TEXT NOT NULL DEFAULT '{}',
|
|
1105
|
+
StartTimeUnix INTEGER NOT NULL,
|
|
1106
|
+
TimeUnix INTEGER NOT NULL,
|
|
1107
|
+
Count INTEGER NOT NULL DEFAULT 0,
|
|
1108
|
+
Sum REAL NOT NULL DEFAULT 0,
|
|
1109
|
+
"ValueAtQuantiles.Quantile" TEXT NOT NULL DEFAULT '[]',
|
|
1110
|
+
"ValueAtQuantiles.Value" TEXT NOT NULL DEFAULT '[]'
|
|
1111
|
+
);
|
|
1112
|
+
|
|
1113
|
+
CREATE INDEX IF NOT EXISTS idx_otel_metrics_summary_service_metric_time ON otel_metrics_summary (ServiceName, MetricName, TimeUnix);
|
|
1114
|
+
`;
|
|
1115
|
+
|
|
1116
|
+
//#endregion
|
|
1117
|
+
//#region src/initialize-database.ts
|
|
1118
|
+
function initializeDatabase(path, opts) {
|
|
1119
|
+
const database = new DatabaseSync(path, opts ?? {});
|
|
1120
|
+
database.exec(ddl);
|
|
1121
|
+
return database;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
//#endregion
|
|
1125
|
+
export { NodeSqliteTelemetryDatasource, initializeDatabase };
|
|
1126
|
+
//# sourceMappingURL=index.mjs.map
|