@flanksource/clicky-ui
Version:
Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.
120 lines (119 loc) • 4.56 kB
JavaScript
import { countThreadsByState, parseJvmThreadDump } from "./jvm-stacktrace.js";
function detectDumpFormat(text) {
const trimmed = text.trim();
if (!trimmed) return "unknown";
if (/^"[^"]*"[^\n]*\b(prio=|tid=|nid=)/m.test(trimmed)) return "jvm";
if (/^goroutine\s+\d+\s+\[[^\]]+\]:/m.test(trimmed)) return "go";
return "unknown";
}
function parseStackDump(text) {
const format = detectDumpFormat(text);
if (format === "jvm") {
return { format: "jvm", threads: parseJvmThreadDump(text) };
}
if (format === "go") {
return { format: "go", goroutines: parseGoroutineDump(text) };
}
return { format: "unknown", goroutines: [], threads: [] };
}
function countStackByState(stack) {
if (stack.format === "jvm") return countThreadsByState(stack.threads);
if (stack.format === "go") return countGoroutinesByState(stack.goroutines);
return /* @__PURE__ */ new Map();
}
const headerRe = /^goroutine\s+(\d+)\s+\[(.+?)\]:$/;
const fileRe = /^\s*(.+?):(\d+)(?:\s+\+0x[0-9a-f]+)?$/i;
const goSrcPrefixRe = /^\/usr\/local\/go[\d.]+\/src\//;
const goWorkspacePrefixRe = /^.*?\/go\/src\//;
const goPkgModPrefixRe = /^.*?\/go\/pkg\/mod\//;
function parseGoroutineDump(text) {
var _a, _b;
const trimmed = text.trim();
if (!trimmed) return [];
const blocks = trimmed.split(/\n\s*\n+/);
const goroutines = [];
for (const block of blocks) {
const lines = block.split("\n").map((line) => line.replace(/\r$/, ""));
const header = (_a = lines[0]) == null ? void 0 : _a.trim();
const match = headerRe.exec(header || "");
if (!match) continue;
const id = Number(match[1] ?? 0);
const rawState = match[2] ?? "";
const state = normalizeState(rawState);
const frames = [];
for (let i = 1; i < lines.length; i++) {
const line = lines[i];
if (line == null) continue;
const trimmedLine = line.trim();
if (!trimmedLine) continue;
const fileMatch = fileRe.exec(trimmedLine);
const previousFrame = frames[frames.length - 1];
if (fileMatch && previousFrame && !previousFrame.file) {
previousFrame.file = fileMatch[1] ?? "";
previousFrame.line = Number(fileMatch[2] ?? 0);
continue;
}
const kind = trimmedLine.startsWith("created by ") ? "created_by" : "frame";
const functionName = kind === "created_by" ? trimmedLine.slice("created by ".length) : trimmedLine;
frames.push({
functionName,
displayName: sanitizeFunctionName(functionName),
kind,
runtime: isRuntimeFrame(functionName)
});
}
for (const frame of frames) {
if (frame.file) {
frame.file = normalizeFilePath(frame.file);
frame.location = `${frame.file}${frame.line ? `:${frame.line}` : ""}`;
}
}
const topFunction = (_b = frames.find((frame) => frame.kind === "frame")) == null ? void 0 : _b.functionName;
goroutines.push({
id,
state,
rawState,
frames,
raw: block,
userFrameCount: frames.filter((frame) => !frame.runtime && frame.kind === "frame").length,
searchText: `${header}
${frames.map((frame) => `${frame.functionName} ${frame.file || ""}`).join("\n")}`.toLowerCase(),
...topFunction !== void 0 ? { topFunction } : {}
});
}
return goroutines;
}
function countGoroutinesByState(goroutines) {
const counts = /* @__PURE__ */ new Map();
for (const goroutine of goroutines) {
counts.set(goroutine.state, (counts.get(goroutine.state) || 0) + 1);
}
return counts;
}
function normalizeState(value) {
return (value.split(",")[0] ?? "").trim().toLowerCase();
}
function isRuntimeFrame(functionName) {
return functionName.startsWith("runtime.") || functionName.startsWith("runtime/") || functionName.startsWith("internal/") || functionName.startsWith("runtime/internal/") || functionName.startsWith("syscall.") || functionName.startsWith("reflect.");
}
function sanitizeFunctionName(functionName) {
let name = functionName.trim();
const paren = name.indexOf("(");
if (paren !== -1) name = name.slice(0, paren);
name = name.replace(/\.\(\*([^)]+)\)\./g, ".$1.");
return stripPackageQualifier(name);
}
function stripPackageQualifier(name) {
return name.replace(/^((?:[^./\s]+\/)+)([^./\s]+)\./, "$2.");
}
function normalizeFilePath(path) {
return path.replace(goSrcPrefixRe, "").replace(goWorkspacePrefixRe, "").replace(goPkgModPrefixRe, "");
}
export {
countGoroutinesByState,
countStackByState,
detectDumpFormat,
parseGoroutineDump,
parseStackDump
};
//# sourceMappingURL=stacktrace.js.map