From 433fd46b168e7b3847f7ebea78258b74b39716a5 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Mon, 2 Feb 2026 08:05:03 +0000 Subject: [PATCH] Add analyzers: patterns, severity, and main analyzer --- loglens/analyzers/patterns.py | 316 ++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 loglens/analyzers/patterns.py diff --git a/loglens/analyzers/patterns.py b/loglens/analyzers/patterns.py new file mode 100644 index 0000000..8e44601 --- /dev/null +++ b/loglens/analyzers/patterns.py @@ -0,0 +1,316 @@ +"""Pattern library for error detection.""" + +import re +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Tuple + + +@dataclass +class ErrorPattern: + """Represents an error detection pattern.""" + name: str + pattern: str + severity: str = "error" + description: str = "" + suggestion: str = "" + group: str = "general" + enabled: bool = True + + def __post_init__(self): + try: + self._regex = re.compile(self.pattern, re.IGNORECASE) + except re.error: + self._regex = re.compile(re.escape(self.pattern), re.IGNORECASE) + + def match(self, text: str) -> Optional[re.Match]: + """Match pattern against text.""" + if not self.enabled: + return None + return self._regex.search(text) + + +@dataclass +class PatternGroup: + """Group of related patterns.""" + name: str + patterns: List[ErrorPattern] = field(default_factory=list) + + +class PatternLibrary: + """Library of error detection patterns.""" + + def __init__(self): + self._patterns: List[ErrorPattern] = [] + self._groups: Dict[str, PatternGroup] = {} + self._load_default_patterns() + + def _load_default_patterns(self) -> None: + """Load default error patterns.""" + self._patterns = [ + ErrorPattern( + name="Python Exception", + pattern=r"(Traceback|Exception|Error|Traceback \(most recent call last\))", + severity="error", + description="Python exception detected", + suggestion="Check the exception type and stack trace to identify the root cause", + group="exceptions" + ), + ErrorPattern( + name="Java Stack Trace", + pattern=r"(java\.lang\.|Exception in thread|at \w+\.\w+\.\w+)", + severity="error", + description="Java exception/stack trace detected", + suggestion="Review the Java stack trace for the exception cause", + group="exceptions" + ), + ErrorPattern( + name="Connection Refused", + pattern=r"Connection refused|ECONNREFUSED", + severity="error", + description="Connection was refused", + suggestion="Check if the service is running and the port is correct", + group="network" + ), + ErrorPattern( + name="Connection Timeout", + pattern=r"Connection timed out|ETIMEDOUT|timeout|Timed out", + severity="error", + description="Connection timed out", + suggestion="Check network connectivity and server responsiveness", + group="network" + ), + ErrorPattern( + name="Database Error", + pattern=r"(mysql|postgres|sqlite|mongodb|redis).*(error|exception|failed)", + severity="error", + description="Database error detected", + suggestion="Check database connectivity and query syntax", + group="database" + ), + ErrorPattern( + name="SQL Error", + pattern=r"(syntax error|undefined column|duplicate key|constraint violation)", + severity="error", + description="SQL error detected", + suggestion="Review the SQL query for syntax errors", + group="database" + ), + ErrorPattern( + name="HTTP 5xx Error", + pattern=r"HTTP Error (5\d{2})|Status: (5\d{2})", + severity="error", + description="Server-side HTTP error", + suggestion="Check server logs for the root cause", + group="http" + ), + ErrorPattern( + name="HTTP 4xx Error", + pattern=r"HTTP Error (4\d{2})|Status: (4\d{2})", + severity="warning", + description="Client-side HTTP error", + suggestion="Check request URL and parameters", + group="http" + ), + ErrorPattern( + name="Null Pointer", + pattern=r"(NullPointerException|null reference|NoneType|is None)", + severity="error", + description="Null pointer/null reference error", + suggestion="Add null checks before accessing objects", + group="exceptions" + ), + ErrorPattern( + name="Index Error", + pattern=r"(IndexError|array index|list index|index out of range)", + severity="error", + description="Index out of bounds error", + suggestion="Check array/list bounds before access", + group="exceptions" + ), + ErrorPattern( + name="Key Error", + pattern=r"(KeyError|missing key|dict key|Key not found)", + severity="error", + description="Key not found in dictionary/map", + suggestion="Add key existence checks or use .get() method", + group="exceptions" + ), + ErrorPattern( + name="Permission Denied", + pattern=r"(Permission denied|EACCES|Access denied)", + severity="error", + description="Permission denied error", + suggestion="Check file/directory permissions", + group="system" + ), + ErrorPattern( + name="Disk Full", + pattern=r"(No space left|ENOSPC|Disk full|Out of space)", + severity="critical", + description="Disk space exhausted", + suggestion="Free up disk space or increase storage", + group="system" + ), + ErrorPattern( + name="Memory Error", + pattern=r"(MemoryError|Out of memory|Killed|OOM)", + severity="critical", + description="Out of memory error", + suggestion="Increase memory or optimize memory usage", + group="system" + ), + ErrorPattern( + name="Segmentation Fault", + pattern=r"(Segmentation fault|SegFault|SIGSEGV|core dumped)", + severity="critical", + description="Segmentation fault", + suggestion="Check for null pointer dereferences or buffer overflows", + group="system" + ), + ErrorPattern( + name="Panic", + pattern=r"(panic|PANIC|fatal error)", + severity="critical", + description="Application panic", + suggestion="Review panic message and stack trace", + group="system" + ), + ErrorPattern( + name="Deprecated", + pattern=r"(deprecated|DeprecationWarning|deprecated method)", + severity="info", + description="Deprecated feature usage", + suggestion="Update to the recommended replacement", + group="code_quality" + ), + ErrorPattern( + name="Warning", + pattern=r"(warning|Warning|WARN)", + severity="warning", + description="General warning", + suggestion="Review warning message for potential issues", + group="general" + ), + ErrorPattern( + name="Debug", + pattern=r"(debug|DEBUG|Trace)", + severity="debug", + description="Debug message", + suggestion="Ignore unless debugging", + group="general" + ), + ErrorPattern( + name="Authentication Failed", + pattern=r"(Authentication failed|Login failed|Invalid credentials|401 Unauthorized)", + severity="error", + description="Authentication failure", + suggestion="Verify username/password or API key", + group="security" + ), + ErrorPattern( + name="SSL/TLS Error", + pattern=r"(SSL|Certificate|TLS|handshake|ssl error)", + severity="error", + description="SSL/TLS error", + suggestion="Check certificate validity and configuration", + group="security" + ), + ] + + self._groups = { + "exceptions": PatternGroup( + name="Exceptions", + patterns=[p for p in self._patterns if p.group == "exceptions"] + ), + "network": PatternGroup( + name="Network", + patterns=[p for p in self._patterns if p.group == "network"] + ), + "database": PatternGroup( + name="Database", + patterns=[p for p in self._patterns if p.group == "database"] + ), + "http": PatternGroup( + name="HTTP", + patterns=[p for p in self._patterns if p.group == "http"] + ), + "system": PatternGroup( + name="System", + patterns=[p for p in self._patterns if p.group == "system"] + ), + "security": PatternGroup( + name="Security", + patterns=[p for p in self._patterns if p.group == "security"] + ), + "code_quality": PatternGroup( + name="Code Quality", + patterns=[p for p in self._patterns if p.group == "code_quality"] + ), + "general": PatternGroup( + name="General", + patterns=[p for p in self._patterns if p.group == "general"] + ), + } + + def detect(self, text: str) -> List[Tuple[ErrorPattern, re.Match]]: + """Detect all patterns matching the text.""" + matches = [] + for pattern in self._patterns: + if pattern.enabled: + match = pattern.match(text) + if match: + matches.append((pattern, match)) + return matches + + def find_match(self, text: str) -> Optional[Tuple[ErrorPattern, re.Match]]: + """Find the first matching pattern.""" + for pattern in self._patterns: + if pattern.enabled: + match = pattern.match(text) + if match: + return (pattern, match) + return None + + def get_patterns_by_severity(self, severity: str) -> List[ErrorPattern]: + """Get patterns by severity level.""" + return [p for p in self._patterns if p.severity == severity] + + def get_patterns_by_group(self, group: str) -> List[ErrorPattern]: + """Get patterns by group.""" + return [p for p in self._patterns if p.group == group] + + def add_pattern(self, pattern: ErrorPattern) -> None: + """Add a custom pattern.""" + self._patterns.append(pattern) + + def remove_pattern(self, name: str) -> bool: + """Remove a pattern by name.""" + for i, p in enumerate(self._patterns): + if p.name == name: + self._patterns.pop(i) + return True + return False + + def disable_pattern(self, name: str) -> bool: + """Disable a pattern by name.""" + for p in self._patterns: + if p.name == name: + p.enabled = False + return True + return False + + def enable_pattern(self, name: str) -> bool: + """Enable a pattern by name.""" + for p in self._patterns: + if p.name == name: + p.enabled = True + return True + return False + + def list_patterns(self) -> List[ErrorPattern]: + """List all patterns.""" + return self._patterns.copy() + + def list_groups(self) -> Dict[str, List[ErrorPattern]]: + """List patterns by group.""" + return {name: group.patterns.copy() for name, group in self._groups.items()}