UNPKG

logsdx

Version:

log streaming with dx on the 🧠

179 lines (156 loc) • 4.74 kB
import { type LineParser, type LineParseResult, type LogLevel, } from "@/src/types"; export type CustomParserOptions = { name: string; description?: string; canParse?: (line: string) => boolean; parse: (line: string) => LineParseResult | undefined; validate?: () => boolean; }; /** * Creates a custom parser with the given options * @param options Parser options * @returns A line parser function */ export function createCustomParser(options: CustomParserOptions): LineParser { // Validate the parser if a validation function is provided if (options.validate && !options.validate()) { throw new Error(`Invalid configuration for parser '${options.name}'`); } // Create the parser function const parser: LineParser = (line: string): LineParseResult | undefined => { // Check if the parser can handle this line if (options.canParse && !options.canParse(line)) { return undefined; } // Parse the line return options.parse(line); }; // Add metadata to the parser function (parser as any).name = options.name; (parser as any).description = options.description || `Custom parser: ${options.name}`; return parser; } /** * Creates a parser factory function for registering with the parser registry * @param options Parser options * @returns A parser factory function */ export function createParserFactory(options: CustomParserOptions) { return async (): Promise<LineParser> => { return createCustomParser(options); }; } /** * Helper function to map log levels from various formats to standard levels * @param level The log level to map * @returns A standardized log level */ export function mapLogLevel(level: string): LogLevel { const levelMap: Record<string, LogLevel> = { // 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"; } /** * Example: Creates a parser for CSV-formatted logs */ export function createCsvLogParser() { return createParserFactory({ name: "csv-logs", description: "Parser for CSV-formatted logs", canParse: (line: string) => line.startsWith("CSV_LOG:"), parse: (line: string): LineParseResult | undefined => { // Remove the prefix const csvContent = line.substring(8); // Parse the CSV-like format const parts = csvContent.split(","); if (parts.length < 3) { return undefined; } // Extract information const timestamp = parts[0]?.trim() || ""; const level = mapLogLevel(parts[1]?.trim() || ""); const message = parts[2]?.trim() || ""; // Create the result const result: LineParseResult = { timestamp, level, message, format: "csv", }; // Add any additional fields for (let i = 3; i < parts.length; i++) { const part = parts[i]; if (part) { const [key, value] = part.split("="); if (key && value) { result[key.trim()] = value.trim(); } } } return result; }, }); } /** * Example: Creates a parser for application-specific logs */ export function createAppLogParser() { return createParserFactory({ name: "app-logs", description: "Parser for application-specific logs", canParse: (line: string) => line.startsWith("[APP]"), parse: (line: string): LineParseResult | undefined => { // Match application-specific log format const appLogRegex = /^\[APP\]\s+(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.*)$/; const appLogMatch = line.match(appLogRegex); if (appLogMatch && appLogMatch[1] && appLogMatch[2] && appLogMatch[3]) { return { timestamp: appLogMatch[1], level: mapLogLevel(appLogMatch[2]), message: appLogMatch[3], service: "app", }; } // Match error stack traces const errorRegex = /^\[APP\]\s+ERROR\s+(.*?):\s+(.*)$/; const errorMatch = line.match(errorRegex); if (errorMatch && errorMatch[1] && errorMatch[2]) { return { level: "error", message: `${errorMatch[1]}: ${errorMatch[2]}`, service: "app", }; } return undefined; }, }); }