@hasna/logs 0.3.21 → 0.3.23
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 +2 -1
- package/README.md +15 -0
- package/bun.lock +375 -0
- package/dist/cli/index.js +4 -3
- package/dist/count-x3n7qg3c.js +9 -0
- package/dist/diagnose-e0w5rwbc.js +9 -0
- package/dist/export-c3eqjste.js +10 -0
- package/dist/export-yjaar93b.js +10 -0
- package/dist/health-3f6ezg5c.js +8 -0
- package/dist/health-9792c1rc.js +8 -0
- package/dist/health-egdb00st.js +8 -0
- package/dist/http-0wsh40x1.js +1240 -0
- package/dist/index-14dvwcf1.js +45 -0
- package/dist/index-1f2ghyhm.js +540 -0
- package/dist/index-2sbhn1ye.js +1241 -0
- package/dist/index-3dr7d80h.js +57 -0
- package/dist/index-4ba0sabv.js +1241 -0
- package/dist/index-4hj4sakk.js +1241 -0
- package/dist/index-5cj74qka.js +10803 -0
- package/dist/index-5qwba140.js +1241 -0
- package/dist/index-5tvnhvgr.js +536 -0
- package/dist/index-6y8pmes4.js +45 -0
- package/dist/index-6zrkek5y.js +9454 -0
- package/dist/index-7qhh666n.js +1241 -0
- package/dist/index-7w7v7hnr.js +76 -0
- package/dist/index-86j0hn03.js +540 -0
- package/dist/index-997bkzr2.js +15 -0
- package/dist/index-cpvq9np9.js +39 -0
- package/dist/index-edn08m6f.js +51 -0
- package/dist/index-eh9bkbpa.js +70 -0
- package/dist/index-exeq2gs6.js +79 -0
- package/dist/index-fzmz9aqs.js +1241 -0
- package/dist/index-g8dczzvv.js +30 -0
- package/dist/index-hjzbctgt.js +5868 -0
- package/dist/index-rbrsvsyh.js +88 -0
- package/dist/index-re3ntm60.js +48 -0
- package/dist/index-t97ttm0a.js +543 -0
- package/dist/index-vmr85wa1.js +9579 -0
- package/dist/index-wbsq8qjd.js +1241 -0
- package/dist/index-ww5ggfv3.js +90 -0
- package/dist/index-xjn8gam3.js +39 -0
- package/dist/index-yb8yd4j6.js +39 -0
- package/dist/index-zmayq5kj.js +1241 -0
- package/dist/index.js +156 -0
- package/dist/jobs-02z4fzsn.js +22 -0
- package/dist/jobs-ypmmc2ma.js +22 -0
- package/dist/mcp/index.js +1207 -7021
- package/dist/query-6s5gqkck.js +15 -0
- package/dist/query-7jwj05er.js +15 -0
- package/dist/query-shjjj67k.js +14 -0
- package/dist/query-tcg3bm9s.js +14 -0
- package/dist/server/index.js +15 -7
- package/package.json +3 -3
- package/sdk/package.json +9 -4
- package/src/cli/entrypoints.test.ts +1 -1
- package/src/index.ts +1 -0
- package/src/mcp/http.test.ts +92 -0
- package/src/mcp/http.ts +135 -0
- package/src/mcp/index.ts +37 -6
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
parseTime
|
|
4
|
+
} from "./index-997bkzr2.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/count.ts
|
|
7
|
+
function countLogs(db, opts) {
|
|
8
|
+
const conditions = [];
|
|
9
|
+
const params = {};
|
|
10
|
+
if (opts.project_id) {
|
|
11
|
+
conditions.push("project_id = $p");
|
|
12
|
+
params.$p = opts.project_id;
|
|
13
|
+
}
|
|
14
|
+
if (opts.service) {
|
|
15
|
+
conditions.push("service = $service");
|
|
16
|
+
params.$service = opts.service;
|
|
17
|
+
}
|
|
18
|
+
if (opts.level) {
|
|
19
|
+
conditions.push("level = $level");
|
|
20
|
+
params.$level = opts.level;
|
|
21
|
+
}
|
|
22
|
+
const since = parseTime(opts.since);
|
|
23
|
+
const until = parseTime(opts.until);
|
|
24
|
+
if (since) {
|
|
25
|
+
conditions.push("timestamp >= $since");
|
|
26
|
+
params.$since = since;
|
|
27
|
+
}
|
|
28
|
+
if (until) {
|
|
29
|
+
conditions.push("timestamp <= $until");
|
|
30
|
+
params.$until = until;
|
|
31
|
+
}
|
|
32
|
+
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
33
|
+
const byLevel = db.prepare(`SELECT level, COUNT(*) as c FROM logs ${where} GROUP BY level`).all(params);
|
|
34
|
+
const by_level = Object.fromEntries(byLevel.map((r) => [r.level, r.c]));
|
|
35
|
+
const total = byLevel.reduce((s, r) => s + r.c, 0);
|
|
36
|
+
let by_service;
|
|
37
|
+
if (opts.group_by === "service") {
|
|
38
|
+
const bySvc = db.prepare(`SELECT COALESCE(service, '-') as service, COUNT(*) as c FROM logs ${where} GROUP BY service ORDER BY c DESC`).all(params);
|
|
39
|
+
by_service = Object.fromEntries(bySvc.map((r) => [r.service, r.c]));
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
total,
|
|
43
|
+
errors: by_level["error"] ?? 0,
|
|
44
|
+
warns: by_level["warn"] ?? 0,
|
|
45
|
+
fatals: by_level["fatal"] ?? 0,
|
|
46
|
+
by_level,
|
|
47
|
+
by_service
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { countLogs };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/lib/export.ts
|
|
3
|
+
function* iterLogs(db, opts) {
|
|
4
|
+
const conditions = [];
|
|
5
|
+
const params = {};
|
|
6
|
+
if (opts.project_id) {
|
|
7
|
+
conditions.push("project_id = $p");
|
|
8
|
+
params.$p = opts.project_id;
|
|
9
|
+
}
|
|
10
|
+
if (opts.since) {
|
|
11
|
+
conditions.push("timestamp >= $since");
|
|
12
|
+
params.$since = opts.since;
|
|
13
|
+
}
|
|
14
|
+
if (opts.until) {
|
|
15
|
+
conditions.push("timestamp <= $until");
|
|
16
|
+
params.$until = opts.until;
|
|
17
|
+
}
|
|
18
|
+
if (opts.level) {
|
|
19
|
+
conditions.push("level = $level");
|
|
20
|
+
params.$level = opts.level;
|
|
21
|
+
}
|
|
22
|
+
if (opts.service) {
|
|
23
|
+
conditions.push("service = $service");
|
|
24
|
+
params.$service = opts.service;
|
|
25
|
+
}
|
|
26
|
+
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
27
|
+
const limit = opts.limit ?? 1e5;
|
|
28
|
+
let offset = 0;
|
|
29
|
+
while (offset < limit) {
|
|
30
|
+
const batch = db.prepare(`SELECT * FROM logs ${where} ORDER BY timestamp ASC LIMIT 1000 OFFSET $offset`).all({ ...params, $offset: offset });
|
|
31
|
+
if (!batch.length)
|
|
32
|
+
break;
|
|
33
|
+
yield* batch;
|
|
34
|
+
offset += batch.length;
|
|
35
|
+
if (batch.length < 1000)
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function exportToJson(db, opts, writeLine) {
|
|
40
|
+
writeLine("[");
|
|
41
|
+
let count = 0;
|
|
42
|
+
for (const row of iterLogs(db, opts)) {
|
|
43
|
+
writeLine((count > 0 ? "," : "") + JSON.stringify(row));
|
|
44
|
+
count++;
|
|
45
|
+
}
|
|
46
|
+
writeLine("]");
|
|
47
|
+
return count;
|
|
48
|
+
}
|
|
49
|
+
var CSV_HEADER = `id,timestamp,level,service,message,trace_id,url
|
|
50
|
+
`;
|
|
51
|
+
function exportToCsv(db, opts, writeLine) {
|
|
52
|
+
writeLine(CSV_HEADER);
|
|
53
|
+
let count = 0;
|
|
54
|
+
for (const row of iterLogs(db, opts)) {
|
|
55
|
+
const fields = [row.id, row.timestamp, row.level, row.service ?? "", escapeCSV(row.message), row.trace_id ?? "", row.url ?? ""];
|
|
56
|
+
writeLine(fields.join(",") + `
|
|
57
|
+
`);
|
|
58
|
+
count++;
|
|
59
|
+
}
|
|
60
|
+
return count;
|
|
61
|
+
}
|
|
62
|
+
function escapeCSV(s) {
|
|
63
|
+
if (s.includes(",") || s.includes('"') || s.includes(`
|
|
64
|
+
`)) {
|
|
65
|
+
return `"${s.replace(/"/g, '""')}"`;
|
|
66
|
+
}
|
|
67
|
+
return s;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { exportToJson, exportToCsv };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
parseTime
|
|
4
|
+
} from "./index-997bkzr2.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/query.ts
|
|
7
|
+
function searchLogs(db, q) {
|
|
8
|
+
const conditions = [];
|
|
9
|
+
const params = {};
|
|
10
|
+
if (q.project_id) {
|
|
11
|
+
conditions.push("l.project_id = $project_id");
|
|
12
|
+
params.$project_id = q.project_id;
|
|
13
|
+
}
|
|
14
|
+
if (q.page_id) {
|
|
15
|
+
conditions.push("l.page_id = $page_id");
|
|
16
|
+
params.$page_id = q.page_id;
|
|
17
|
+
}
|
|
18
|
+
if (q.service) {
|
|
19
|
+
conditions.push("l.service = $service");
|
|
20
|
+
params.$service = q.service;
|
|
21
|
+
}
|
|
22
|
+
if (q.trace_id) {
|
|
23
|
+
conditions.push("l.trace_id = $trace_id");
|
|
24
|
+
params.$trace_id = q.trace_id;
|
|
25
|
+
}
|
|
26
|
+
if (q.since) {
|
|
27
|
+
conditions.push("l.timestamp >= $since");
|
|
28
|
+
params.$since = parseTime(q.since) ?? q.since;
|
|
29
|
+
}
|
|
30
|
+
if (q.until) {
|
|
31
|
+
conditions.push("l.timestamp <= $until");
|
|
32
|
+
params.$until = parseTime(q.until) ?? q.until;
|
|
33
|
+
}
|
|
34
|
+
if (q.level) {
|
|
35
|
+
const levels = Array.isArray(q.level) ? q.level : [q.level];
|
|
36
|
+
const placeholders = levels.map((_, i) => `$level${i}`).join(",");
|
|
37
|
+
levels.forEach((lv, i) => {
|
|
38
|
+
params[`$level${i}`] = lv;
|
|
39
|
+
});
|
|
40
|
+
conditions.push(`l.level IN (${placeholders})`);
|
|
41
|
+
}
|
|
42
|
+
const limit = q.limit ?? 100;
|
|
43
|
+
const offset = q.offset ?? 0;
|
|
44
|
+
params.$limit = limit;
|
|
45
|
+
params.$offset = offset;
|
|
46
|
+
if (q.text) {
|
|
47
|
+
params.$text = q.text;
|
|
48
|
+
const where2 = conditions.length ? `WHERE ${conditions.join(" AND ")} AND` : "WHERE";
|
|
49
|
+
const sql2 = `
|
|
50
|
+
SELECT l.* FROM logs l
|
|
51
|
+
${where2} l.rowid IN (SELECT rowid FROM logs_fts WHERE logs_fts MATCH $text)
|
|
52
|
+
ORDER BY l.timestamp DESC
|
|
53
|
+
LIMIT $limit OFFSET $offset
|
|
54
|
+
`;
|
|
55
|
+
return db.prepare(sql2).all(params);
|
|
56
|
+
}
|
|
57
|
+
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
58
|
+
const sql = `SELECT * FROM logs l ${where} ORDER BY l.timestamp DESC LIMIT $limit OFFSET $offset`;
|
|
59
|
+
return db.prepare(sql).all(params);
|
|
60
|
+
}
|
|
61
|
+
function tailLogs(db, projectId, n = 50) {
|
|
62
|
+
if (projectId) {
|
|
63
|
+
return db.prepare("SELECT * FROM logs WHERE project_id = $p ORDER BY timestamp DESC LIMIT $n").all({ $p: projectId, $n: n });
|
|
64
|
+
}
|
|
65
|
+
return db.prepare("SELECT * FROM logs ORDER BY timestamp DESC LIMIT $n").all({ $n: n });
|
|
66
|
+
}
|
|
67
|
+
function getLogContext(db, traceId) {
|
|
68
|
+
return db.prepare("SELECT * FROM logs WHERE trace_id = $t ORDER BY timestamp ASC").all({ $t: traceId });
|
|
69
|
+
}
|
|
70
|
+
function getLogContextFromId(db, logId) {
|
|
71
|
+
const log = db.prepare("SELECT * FROM logs WHERE id = $id").get({ $id: logId });
|
|
72
|
+
if (!log)
|
|
73
|
+
return [];
|
|
74
|
+
if (log.trace_id)
|
|
75
|
+
return getLogContext(db, log.trace_id);
|
|
76
|
+
return [log];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { searchLogs, tailLogs, getLogContext, getLogContextFromId };
|