UNPKG

@flanksource/clicky-ui

Version:

Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.

191 lines (190 loc) 7.04 kB
const headerRe = /^"(?<name>[^"]*)"(?<rest>.*)$/; const stateRe = /^\s*java\.lang\.Thread\.State:\s+(?<state>[A-Z_]+)(?:\s+\((?<sub>[^)]+)\))?/; const frameRe = /^\s*at\s+(?<fn>[^\s(]+)\((?<src>[^)]+)\)\s*$/; const srcLineRe = /^(?<file>[^:]+):(?<line>\d+)$/; const annotationRe = /^\s*-\s+(?<kind>locked|waiting on|waiting to lock|parking to wait for)\b(?<rest>.*)$/; function parseJvmThreadDump(text) { const trimmed = text.trim(); if (!trimmed) return []; const blocks = splitIntoThreadBlocks(trimmed); const threads = []; for (const block of blocks) { const parsed = parseThreadBlock(block); if (parsed) threads.push(parsed); } return threads; } function splitIntoThreadBlocks(text) { const out = []; let current = []; const lines = text.split("\n"); for (const raw of lines) { const line = raw.replace(/\r$/, ""); if (line.startsWith('"') && current.length > 0) { out.push(current.join("\n")); current = [line]; } else { current.push(line); } } if (current.length > 0) out.push(current.join("\n")); return out; } function parseThreadBlock(block) { var _a, _b, _c, _d; const lines = block.split("\n"); const header = ((_a = lines[0]) == null ? void 0 : _a.trim()) ?? ""; const headerMatch = headerRe.exec(header); if (!(headerMatch == null ? void 0 : headerMatch.groups)) return null; const name = headerMatch.groups.name; if (!name) return null; const rest = headerMatch.groups.rest ?? ""; const idMatch = /#(\d+)\b/.exec(rest); const prioMatch = /\bprio=(\d+)/.exec(rest); const nidMatch = /\bnid=(0x[0-9a-f]+)/i.exec(rest); const daemon = /\bdaemon\b/.test(rest); const headerStateTrail = extractHeaderStateTrail(rest); let rawState = headerStateTrail ?? ""; let state = normalizeJvmState(rawState); const frames = []; for (let i = 1; i < lines.length; i++) { const line = lines[i]; if (line == null) continue; if (!line.trim()) continue; const stateMatch = stateRe.exec(line); if (stateMatch == null ? void 0 : stateMatch.groups) { const primary = stateMatch.groups.state; if (!primary) continue; const sub = stateMatch.groups.sub; rawState = sub ? `${primary} (${sub})` : primary; state = normalizeJvmState(primary); continue; } const frameMatch = frameRe.exec(line); if (frameMatch == null ? void 0 : frameMatch.groups) { const functionName = frameMatch.groups.fn; const src = frameMatch.groups.src; if (!functionName || !src) continue; const frame = { functionName, displayName: sanitizeJvmFunctionName(functionName), kind: "frame", runtime: isJvmRuntimeFrame(functionName), nativeMethod: src === "Native Method" }; const srcMatch = srcLineRe.exec(src); if (((_b = srcMatch == null ? void 0 : srcMatch.groups) == null ? void 0 : _b.file) && srcMatch.groups.line) { frame.file = srcMatch.groups.file; frame.line = Number(srcMatch.groups.line); frame.location = `${frame.file}:${frame.line}`; } else if (src === "Native Method") { frame.location = "Native Method"; } else { frame.location = src; } frames.push(frame); continue; } const annoMatch = annotationRe.exec(line); if ((_c = annoMatch == null ? void 0 : annoMatch.groups) == null ? void 0 : _c.kind) { const annotationKind = annoMatch.groups.kind; const kind = mapAnnotationKind(annotationKind); frames.push({ functionName: annotationKind, displayName: annotationKind, kind, runtime: false, nativeMethod: false, annotationText: (annoMatch.groups.rest ?? "").trim() }); continue; } } const userFrameCount = frames.filter((f) => f.kind === "frame" && !f.runtime).length; const topFunction = (_d = frames.find((f) => f.kind === "frame")) == null ? void 0 : _d.functionName; const searchText = [ header, ...frames.map((f) => `${f.functionName} ${f.location ?? ""} ${f.annotationText ?? ""}`) ].join("\n").toLowerCase(); return { id: idMatch ? Number(idMatch[1]) : deriveSyntheticId(name, rest), name, state: state || "unknown", rawState: rawState || "", daemon, frames, raw: block, userFrameCount, searchText, ...(nidMatch == null ? void 0 : nidMatch[1]) !== void 0 ? { nid: nidMatch[1] } : {}, ...(prioMatch == null ? void 0 : prioMatch[1]) !== void 0 ? { priority: Number(prioMatch[1]) } : {}, ...topFunction !== void 0 ? { topFunction } : {} }; } function extractHeaderStateTrail(rest) { var _a, _b; const tail = rest.match(/nid=0x[0-9a-f]+\s+(?<desc>[^[]+?)(?:\s+\[0x[0-9a-f]+\])?\s*$/i); return (_b = (_a = tail == null ? void 0 : tail.groups) == null ? void 0 : _a.desc) == null ? void 0 : _b.trim(); } function deriveSyntheticId(name, rest) { const tid = /\btid=(0x[0-9a-f]+)/i.exec(rest); if (tid == null ? void 0 : tid[1]) { const hex = tid[1].slice(2); const n = Number.parseInt(hex.slice(-8), 16); if (Number.isFinite(n)) return n; } let h = 0; for (let i = 0; i < name.length; i++) h = h * 31 + name.charCodeAt(i) | 0; return Math.abs(h); } function mapAnnotationKind(kind) { switch (kind) { case "locked": return "locked"; case "waiting on": return "waiting_on"; case "waiting to lock": return "waiting_to_lock"; case "parking to wait for": return "parking"; default: return "frame"; } } function countThreadsByState(threads) { const counts = /* @__PURE__ */ new Map(); for (const t of threads) counts.set(t.state, (counts.get(t.state) ?? 0) + 1); return counts; } function normalizeJvmState(value) { if (!value) return ""; const upper = value.trim().toUpperCase(); if (upper.startsWith("RUNNABLE")) return "runnable"; if (upper.startsWith("TIMED_WAITING")) return "timed_waiting"; if (upper.startsWith("WAITING")) return "waiting"; if (upper.startsWith("BLOCKED")) return "blocked"; if (upper.startsWith("NEW")) return "new"; if (upper.startsWith("TERMINATED")) return "terminated"; const lower = value.trim().toLowerCase(); if (lower.includes("runnable")) return "runnable"; if (lower.includes("waiting on condition") || lower.includes("sleeping")) return "timed_waiting"; if (lower.includes("waiting")) return "waiting"; if (lower.includes("blocked")) return "blocked"; return lower.split(/\s+/)[0] ?? ""; } const runtimePrefixes = ["java.", "javax.", "sun.", "jdk.", "com.sun.", "oracle.jrockit."]; function isJvmRuntimeFrame(functionName) { return runtimePrefixes.some((p) => functionName.startsWith(p)); } function sanitizeJvmFunctionName(functionName) { const parts = functionName.split("."); if (parts.length < 2) return functionName; const method = parts[parts.length - 1]; const cls = parts[parts.length - 2]; return `${cls}.${method}`; } export { countThreadsByState, parseJvmThreadDump }; //# sourceMappingURL=jvm-stacktrace.js.map