logsdx
Version:
log streaming with dx on the ðŸ§
361 lines (337 loc) • 12.5 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
var _chunkMA4X2JPVcjs = require('./chunk-MA4X2JPV.cjs');
var _chunkQ46SBW3Rcjs = require('./chunk-Q46SBW3R.cjs');
// src/cli/index.ts
var _commander = require('commander');
var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);
// src/parsers/regex/line.ts
function createRegexLineParser(rules) {
return (line) => {
let result;
for (const rule of rules) {
const match = line.match(rule.match);
if (match) {
const extracted = _optionalChain([rule, 'access', _ => _.extract, 'optionalCall', _2 => _2(line, match)]) || {};
if (extracted.timestamp && extracted.level && extracted.message) {
return extracted;
}
result = {
...extracted,
...result
// This ensures earlier matches take precedence
};
}
}
if (result) {
if (!result.timestamp) {
const timestampMatch = line.match(
/(\d{4}-\d{2}-\d{2}(?:T|\s+)\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)/
);
if (timestampMatch) {
result.timestamp = timestampMatch[1];
}
}
if (!result.message) {
const messageMatch = line.match(
/(?:\]|\d{2}(?:Z|[+-]\d{2}:?\d{2})?)\s+(?:\[\w+\])?\s+(.+)$/
);
if (messageMatch) {
result.message = messageMatch[1];
}
}
return result;
}
return void 0;
};
}
// src/parsers/json/index.ts
var _json5 = require('json5'); var _json52 = _interopRequireDefault(_json5);
var DEFAULT_JSON_RULES = [
{
match: "\\{.*\\}",
lang: "json",
level: "info",
meta: {
service: "service",
timestamp: "timestamp",
message: "message",
level: "level"
}
}
];
function mapLogLevel(level) {
const levelMap = {
// Standard levels
debug: "debug",
info: "info",
warn: "warn",
warning: "warn",
error: "error",
err: "error",
success: "success",
trace: "trace",
// Common variations
fatal: "error",
critical: "error",
notice: "info",
verbose: "debug",
silly: "debug",
// Status-based levels
fail: "error",
failed: "error",
failure: "error",
pending: "warn",
in_progress: "info",
completed: "success"
};
const normalizedLevel = level.toLowerCase().trim();
return levelMap[normalizedLevel] || "info";
}
async function loadJsonRules(filePath) {
let rules = DEFAULT_JSON_RULES;
if (filePath) {
try {
const data = _fs2.default.readFileSync(filePath, "utf-8");
const customRules = _json52.default.parse(data);
if (Array.isArray(customRules) && customRules.length > 0) {
rules = customRules;
}
} catch (error) {
_chunkMA4X2JPVcjs.logger.warn(
`Failed to load custom JSON rules: ${_json52.default.stringify(error)}`
);
_chunkMA4X2JPVcjs.logger.info("Using default JSON rules instead");
}
}
return (line) => {
try {
if (!line.trim().startsWith("{") || !line.trim().endsWith("}")) {
return void 0;
}
const json = _json52.default.parse(line);
const result = {
level: mapLogLevel(
json.level || json.status || json.severity || "info"
),
timestamp: json.timestamp || json.time || json.date || json["@timestamp"],
message: json.message || json.msg || json.log || json.text,
language: "json"
};
for (const [key, value] of Object.entries(json)) {
if (![
"level",
"status",
"severity",
"timestamp",
"time",
"date",
"@timestamp",
"message",
"msg",
"log",
"text"
].includes(key)) {
result[key] = value;
}
}
return result;
} catch (error) {
return void 0;
}
};
}
// src/parsers/default.ts
var defaultLineParser = (line) => {
const result = {};
if (line.startsWith("[json]")) result.lang = "json";
if (line.startsWith("[sql]")) result.lang = "sql";
if (line.includes("ERROR")) result.level = "error";
if (line.includes("WARN")) result.level = "warn";
if (line.includes("INFO")) result.level = "info";
return result;
};
// src/parsers/registry.ts
var DEFAULT_CONFIG = {
defaultRules: [
{
match: /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z)\s+\[(\w+)\]\s+(.*)$/,
extract: (line, match) => ({
timestamp: match[1],
level: match[2].toLowerCase(),
message: match[3]
})
}
],
levels: {
debug: 0,
info: 1,
warn: 2,
error: 3
}
};
var parserRegistry = {
// Default parser
default: async () => defaultLineParser,
// Built-in parsers
regex: async () => {
return createRegexLineParser(DEFAULT_CONFIG.defaultRules);
},
json: async (options) => {
return loadJsonRules(_optionalChain([options, 'optionalAccess', _3 => _3.rulesFile]));
}
};
function registerParser(name, factory) {
parserRegistry[name] = factory;
}
async function getParser(name, options) {
if (!parserRegistry[name]) {
throw new Error(
`Parser '${name}' not found. Available parsers: ${Object.keys(parserRegistry).join(", ")}`
);
}
return parserRegistry[name](options);
}
function getRegisteredParsers() {
return Object.keys(parserRegistry);
}
// src/cli/index.ts
var program = new (0, _commander.Command)();
program.name("logsdx").description("A powerful log parsing and formatting tool").version("0.0.1");
program.option("-q, --quiet", "Suppress all output except errors").option("-d, --debug", "Enable debug mode").option("-l, --level <level>", "Minimum log level to display", "info").option("-p, --parser <parser>", "Parser to use for log parsing", "default").option("-r, --rules <file>", "Path to custom rules file").option("-o, --output <file>", "Path to output file").option("--list-parsers", "List available parsers").option(
"-t, --theme <theme>",
"Theme to use (default, dark, light, minimal, or custom theme name)"
).option("--list-themes", "List available themes").argument("[input]", "Input file to process (defaults to stdin)").action(async (input, options) => {
try {
if (options.listParsers) {
const parsers = getRegisteredParsers();
_chunkMA4X2JPVcjs.logger.info("Available parsers:");
parsers.forEach((parser2) => _chunkMA4X2JPVcjs.logger.info(` - ${parser2}`));
process.exit(0);
}
if (options.listThemes) {
const config2 = _chunkQ46SBW3Rcjs.loadConfig.call(void 0, );
const themes = config2 ? Object.keys(config2.customThemes || {}) : [];
_chunkMA4X2JPVcjs.logger.info("Available themes:");
_chunkMA4X2JPVcjs.logger.info("Built-in themes:");
_chunkMA4X2JPVcjs.logger.info(" - default");
_chunkMA4X2JPVcjs.logger.info(" - dark");
_chunkMA4X2JPVcjs.logger.info(" - light");
_chunkMA4X2JPVcjs.logger.info(" - minimal");
if (themes.length > 0) {
_chunkMA4X2JPVcjs.logger.info("Custom themes:");
themes.forEach((theme) => _chunkMA4X2JPVcjs.logger.info(` - ${theme}`));
}
process.exit(0);
}
if (options.debug) {
_chunkMA4X2JPVcjs.logger.withConfig({ level: "debug", prefix: "CLI" }).debug("Debug mode enabled");
}
const config = _chunkQ46SBW3Rcjs.loadConfig.call(void 0, );
if (options.theme) {
if (options.debug) {
_chunkMA4X2JPVcjs.logger.withConfig({ level: "debug", prefix: "CLI" }).debug(`Using theme: ${options.theme}`);
}
_chunkQ46SBW3Rcjs.setTheme.call(void 0, options.theme);
} else if (_optionalChain([config, 'optionalAccess', _4 => _4.theme])) {
if (options.debug) {
_chunkMA4X2JPVcjs.logger.withConfig({ level: "debug", prefix: "CLI" }).debug(`Using theme from config: ${config.theme}`);
}
_chunkQ46SBW3Rcjs.setTheme.call(void 0, config.theme);
}
if (options.level && !["debug", "info", "warn", "error"].includes(options.level)) {
throw new Error(`Invalid log level: ${options.level}`);
}
const inputStream = input ? _fs2.default.createReadStream(input) : process.stdin;
if (input && options.debug) {
_chunkMA4X2JPVcjs.logger.withConfig({ level: "debug", prefix: "CLI" }).debug(`Input file set to: ${input}`);
}
const outputStream = options.output ? _fs2.default.createWriteStream(options.output) : process.stdout;
if (options.output && options.debug) {
_chunkMA4X2JPVcjs.logger.withConfig({ level: "debug", prefix: "CLI" }).debug(`Output file set to: ${options.output}`);
}
const parser = await getParserForOptions(options);
let buffer = "";
inputStream.on("data", (chunk) => {
buffer += chunk.toString();
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (!line.trim()) continue;
const parsed = parser(line);
const level = _optionalChain([parsed, 'optionalAccess', _5 => _5.level]) || "info";
if (shouldRender(level, options.level)) {
const formattedLine = _chunkQ46SBW3Rcjs.styleManager.styleLine(
line,
parsed,
options.parser || "default"
);
if (outputStream === process.stdout) {
process.stdout.write(formattedLine + "\n");
} else {
outputStream.write(formattedLine + "\n");
}
}
}
});
inputStream.on("end", () => {
if (buffer.trim()) {
const parsed = parser(buffer);
const level = _optionalChain([parsed, 'optionalAccess', _6 => _6.level]) || "info";
if (shouldRender(level, options.level)) {
const formattedLine = _chunkQ46SBW3Rcjs.styleManager.styleLine(
buffer,
parsed,
options.parser || "default"
);
if (outputStream === process.stdout) {
process.stdout.write(formattedLine + "\n");
} else {
outputStream.write(formattedLine + "\n");
}
}
}
if (options.output) {
outputStream.end();
}
});
inputStream.on("error", (error) => {
_chunkMA4X2JPVcjs.logger.error("Error reading input:", error);
process.exit(1);
});
} catch (error) {
_chunkMA4X2JPVcjs.logger.error("Error:", error);
process.exit(1);
}
});
program.parse();
async function getParserForOptions(options) {
const parserName = options.parser || "default";
try {
if (options.debug) {
_chunkMA4X2JPVcjs.logger.withConfig({ level: "debug", prefix: "CLI" }).debug(`Using parser: ${parserName}`);
}
return await getParser(parserName, {
rulesFile: options.rules
});
} catch (error) {
_chunkMA4X2JPVcjs.logger.error(`Error loading parser '${parserName}':`, error);
_chunkMA4X2JPVcjs.logger.info(`Available parsers: ${getRegisteredParsers().join(", ")}`);
process.exit(1);
}
}
function shouldRender(level, minLevel) {
if (!minLevel || !level) return true;
const levelPriorities = {
debug: 0,
info: 1,
warn: 2,
error: 3,
success: 1,
trace: 0
};
const current = _nullishCoalesce(levelPriorities[level], () => ( 0));
const min = _nullishCoalesce(levelPriorities[minLevel], () => ( 0));
return current >= min;
}
exports.createRegexLineParser = createRegexLineParser; exports.DEFAULT_JSON_RULES = DEFAULT_JSON_RULES; exports.loadJsonRules = loadJsonRules; exports.defaultLineParser = defaultLineParser; exports.registerParser = registerParser; exports.getParser = getParser; exports.getRegisteredParsers = getRegisteredParsers; exports.program = program; exports.getParserForOptions = getParserForOptions; exports.shouldRender = shouldRender;
//# sourceMappingURL=chunk-QBEC4U26.cjs.map