@hasna/logs 0.3.5 → 0.3.7
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/cli/index.js +47 -7
- package/dist/diagnose-e0w5rwbc.js +9 -0
- package/dist/index-14dvwcf1.js +45 -0
- package/dist/index-1f2ghyhm.js +540 -0
- package/dist/index-4hj4sakk.js +1241 -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-exeq2gs6.js +79 -0
- package/dist/mcp/index.js +9 -74
- package/dist/query-6s5gqkck.js +15 -0
- package/dist/server/index.js +7 -5
- package/package.json +1 -1
- package/src/cli/index.ts +39 -1
- package/src/lib/summarize.ts +2 -1
package/dist/cli/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
import {
|
|
4
4
|
runJob
|
|
5
|
-
} from "../index-
|
|
5
|
+
} from "../index-7qhh666n.js";
|
|
6
6
|
import {
|
|
7
7
|
createPage,
|
|
8
8
|
createProject,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
listProjects,
|
|
13
13
|
resolveProjectId,
|
|
14
14
|
summarizeLogs
|
|
15
|
-
} from "../index-
|
|
15
|
+
} from "../index-1f2ghyhm.js";
|
|
16
16
|
import {
|
|
17
17
|
createJob,
|
|
18
18
|
listJobs
|
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
import {
|
|
21
21
|
searchLogs,
|
|
22
22
|
tailLogs
|
|
23
|
-
} from "../index-
|
|
23
|
+
} from "../index-exeq2gs6.js";
|
|
24
|
+
import"../index-997bkzr2.js";
|
|
24
25
|
import {
|
|
25
26
|
__commonJS,
|
|
26
27
|
__require,
|
|
@@ -2174,15 +2175,17 @@ function resolveProject(nameOrId) {
|
|
|
2174
2175
|
return resolveProjectId(getDb(), nameOrId) ?? nameOrId;
|
|
2175
2176
|
}
|
|
2176
2177
|
var program2 = new Command().name("logs").description("@hasna/logs \u2014 log aggregation and monitoring").version("0.0.1");
|
|
2177
|
-
program2.command("list").description("Search and list logs").option("--project <name|id>", "Filter by project name or ID").option("--page <id>", "Filter by page ID").option("--level <levels>", "Comma-separated levels (error,warn,info,debug,fatal)").option("--service <name>", "Filter by service").option("--since <iso>", "Since timestamp or relative (1h, 24h, 7d)").option("--text <query>", "Full-text search").option("--limit <n>", "Max results", "100").option("--format <fmt>", "Output format: table|json|compact", "table").action((opts) => {
|
|
2178
|
+
program2.command("list").description("Search and list logs").option("--project <name|id>", "Filter by project name or ID").option("--page <id>", "Filter by page ID").option("--level <levels>", "Comma-separated levels (error,warn,info,debug,fatal)").option("--service <name>", "Filter by service").option("--since <iso>", "Since timestamp or relative (1h, 24h, 7d)").option("--until <iso>", "Until timestamp or relative (e.g. logs list --since 2h --until 1h)").option("--text <query>", "Full-text search").option("--limit <n>", "Max results", "100").option("--format <fmt>", "Output format: table|json|compact", "table").action((opts) => {
|
|
2178
2179
|
const db = getDb();
|
|
2179
2180
|
const since = parseRelativeTime(opts.since);
|
|
2181
|
+
const until = parseRelativeTime(opts.until);
|
|
2180
2182
|
const rows = searchLogs(db, {
|
|
2181
2183
|
project_id: resolveProject(opts.project),
|
|
2182
2184
|
page_id: opts.page,
|
|
2183
2185
|
level: opts.level ? opts.level.split(",") : undefined,
|
|
2184
2186
|
service: opts.service,
|
|
2185
2187
|
since,
|
|
2188
|
+
until,
|
|
2186
2189
|
text: opts.text,
|
|
2187
2190
|
limit: Number(opts.limit)
|
|
2188
2191
|
});
|
|
@@ -2207,8 +2210,8 @@ program2.command("tail").description("Show most recent logs").option("--project
|
|
|
2207
2210
|
for (const r of rows)
|
|
2208
2211
|
console.log(colorRow(r.timestamp, r.level, r.service ?? "-", r.message));
|
|
2209
2212
|
});
|
|
2210
|
-
program2.command("summary").description("Error/warn summary by service").option("--project <name|id>", "Project name or ID").option("--since <time>", "Relative time (1h, 24h, 7d)", "24h").action((opts) => {
|
|
2211
|
-
const summary = summarizeLogs(getDb(), resolveProject(opts.project), parseRelativeTime(opts.since));
|
|
2213
|
+
program2.command("summary").description("Error/warn summary by service").option("--project <name|id>", "Project name or ID").option("--since <time>", "Relative time (1h, 24h, 7d)", "24h").option("--until <time>", "Upper bound time").action((opts) => {
|
|
2214
|
+
const summary = summarizeLogs(getDb(), resolveProject(opts.project), parseRelativeTime(opts.since), parseRelativeTime(opts.until));
|
|
2212
2215
|
if (!summary.length) {
|
|
2213
2216
|
console.log("No errors/warnings in this window.");
|
|
2214
2217
|
return;
|
|
@@ -2281,9 +2284,46 @@ program2.command("scan").description("Run an immediate scan for a job").option("
|
|
|
2281
2284
|
await runJob(db, job.id, job.project_id, job.page_id ?? undefined);
|
|
2282
2285
|
console.log("Scan complete.");
|
|
2283
2286
|
});
|
|
2287
|
+
program2.command("diagnose").description("Health diagnosis: score, top errors, trends, failing pages").option("--project <name|id>", "Project name or ID").option("--since <time>", "Time window (1h, 24h, 7d)", "24h").option("--include <items>", "Comma-separated: top_errors,error_rate,failing_pages,perf").action(async (opts) => {
|
|
2288
|
+
const { diagnose } = await import("../diagnose-e0w5rwbc.js");
|
|
2289
|
+
const projectId = resolveProject(opts.project);
|
|
2290
|
+
if (!projectId) {
|
|
2291
|
+
console.error("--project required");
|
|
2292
|
+
process.exit(1);
|
|
2293
|
+
}
|
|
2294
|
+
const include = opts.include ? opts.include.split(",") : undefined;
|
|
2295
|
+
const result = diagnose(getDb(), projectId, opts.since, include);
|
|
2296
|
+
const scoreColor = result.health_score >= 80 ? "\x1B[32m" : result.health_score >= 50 ? "\x1B[33m" : "\x1B[31m";
|
|
2297
|
+
console.log(`
|
|
2298
|
+
${C.bold}Health Score:${C.reset} ${scoreColor}${result.health_score}/100${C.reset}`);
|
|
2299
|
+
if (result.top_errors?.length) {
|
|
2300
|
+
console.log(`
|
|
2301
|
+
${C.bold}Top Errors:${C.reset}`);
|
|
2302
|
+
for (const e of result.top_errors) {
|
|
2303
|
+
console.log(` ${C.red}${pad(String(e.count), 5)}x${C.reset} ${C.cyan}${pad(e.service ?? "-", 12)}${C.reset} ${e.message}`);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
if (result.error_rate !== undefined) {
|
|
2307
|
+
console.log(`
|
|
2308
|
+
${C.bold}Error Rate:${C.reset} ${result.error_rate.toFixed(2)}%`);
|
|
2309
|
+
}
|
|
2310
|
+
if (result.failing_pages?.length) {
|
|
2311
|
+
console.log(`
|
|
2312
|
+
${C.bold}Failing Pages:${C.reset}`);
|
|
2313
|
+
for (const p of result.failing_pages)
|
|
2314
|
+
console.log(` ${C.red}\u2717${C.reset} ${p.url} (${p.error_count} errors)`);
|
|
2315
|
+
}
|
|
2316
|
+
if (result.perf_regressions?.length) {
|
|
2317
|
+
console.log(`
|
|
2318
|
+
${C.bold}Perf Regressions:${C.reset}`);
|
|
2319
|
+
for (const r of result.perf_regressions)
|
|
2320
|
+
console.log(` ${C.yellow}\u26A0${C.reset} ${r.page_url} p95=${r.p95_ms}ms`);
|
|
2321
|
+
}
|
|
2322
|
+
console.log("");
|
|
2323
|
+
});
|
|
2284
2324
|
program2.command("watch").description("Stream new logs in real time with color coding").option("--project <name|id>", "Filter by project name or ID").option("--level <levels>", "Comma-separated levels (debug,info,warn,error,fatal)").option("--service <name>", "Filter by service name").option("--interval <ms>", "Poll interval in milliseconds (default: 500)", "500").option("--since <time>", "Start from this time (default: now)").action(async (opts) => {
|
|
2285
2325
|
const db = getDb();
|
|
2286
|
-
const { searchLogs: searchLogs2 } = await import("../query-
|
|
2326
|
+
const { searchLogs: searchLogs2 } = await import("../query-6s5gqkck.js");
|
|
2287
2327
|
let projectId = opts.project;
|
|
2288
2328
|
if (projectId) {
|
|
2289
2329
|
const proj = db.query("SELECT id FROM projects WHERE id = ? OR name = ?").get(projectId, projectId);
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
return {
|
|
37
|
+
total,
|
|
38
|
+
errors: by_level["error"] ?? 0,
|
|
39
|
+
warns: by_level["warn"] ?? 0,
|
|
40
|
+
fatals: by_level["fatal"] ?? 0,
|
|
41
|
+
by_level
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { countLogs };
|