Some checks failed
- Added @click.version_option decorator to main() in commands.py - Imported __version__ from loglens package - Resolves CI build failure: 'loglens --version' command not found
223 lines
8.0 KiB
Python
223 lines
8.0 KiB
Python
from dataclasses import dataclass
|
|
from typing import Optional
|
|
|
|
|
|
@dataclass
|
|
class ErrorPattern:
|
|
"""Error pattern definition."""
|
|
|
|
name: str
|
|
pattern: str
|
|
severity: str
|
|
description: str
|
|
group: str = "general"
|
|
|
|
|
|
class PatternLibrary:
|
|
"""Library of error detection patterns."""
|
|
|
|
def __init__(self):
|
|
self._patterns = self._load_patterns()
|
|
|
|
def _load_patterns(self) -> list[ErrorPattern]:
|
|
"""Load all error patterns."""
|
|
return [
|
|
ErrorPattern(
|
|
name="Python Exception",
|
|
pattern=r"(?:Traceback|Exception|Error|Error:)",
|
|
severity="error",
|
|
description="Python exception or error",
|
|
group="exceptions",
|
|
),
|
|
ErrorPattern(
|
|
name="Python Traceback",
|
|
pattern=r"Traceback \(most recent call last\)",
|
|
severity="error",
|
|
description="Python traceback",
|
|
group="exceptions",
|
|
),
|
|
ErrorPattern(
|
|
name="Java Exception",
|
|
pattern=r"(?:Exception|Error|NullPointerException|IllegalArgumentException)",
|
|
severity="error",
|
|
description="Java exception",
|
|
group="exceptions",
|
|
),
|
|
ErrorPattern(
|
|
name="Stack Trace",
|
|
pattern=r"(?:at [a-zA-Z0-9_.]+\([a-zA-Z0-9_.]+\.java:[0-9]+\)|\(Unknown Source\))",
|
|
severity="error",
|
|
description="Stack trace element",
|
|
group="exceptions",
|
|
),
|
|
ErrorPattern(
|
|
name="Connection Refused",
|
|
pattern=r"(?:Connection refused|ECONNREFUSED)",
|
|
severity="error",
|
|
description="Connection refused by remote host",
|
|
group="network",
|
|
),
|
|
ErrorPattern(
|
|
name="Connection Timeout",
|
|
pattern=r"(?:Connection timed out|ETIMEDOUT|Timeout)",
|
|
severity="error",
|
|
description="Connection timeout",
|
|
group="network",
|
|
),
|
|
ErrorPattern(
|
|
name="DNS Error",
|
|
pattern=r"(?:DNS|NXDOMAIN|host not found)",
|
|
severity="error",
|
|
description="DNS resolution error",
|
|
group="network",
|
|
),
|
|
ErrorPattern(
|
|
name="HTTP 5xx Error",
|
|
pattern=r"(?:HTTP/[0-9\.]+\s+[5][0-9]{2}|Status: 5\d{2})",
|
|
severity="error",
|
|
description="HTTP server error (5xx)",
|
|
group="http",
|
|
),
|
|
ErrorPattern(
|
|
name="HTTP 4xx Error",
|
|
pattern=r"(?:HTTP/[0-9\.]+\s+[4][0-9]{2}|Status: 4\d{2})",
|
|
severity="warning",
|
|
description="HTTP client error (4xx)",
|
|
group="http",
|
|
),
|
|
ErrorPattern(
|
|
name="Database Connection",
|
|
pattern=r"(?:Cannot connect to database|MongoDB|SQL|ConnectionString|pymongo)",
|
|
severity="error",
|
|
description="Database connection issue",
|
|
group="database",
|
|
),
|
|
ErrorPattern(
|
|
name="Authentication Failed",
|
|
pattern=r"(?:Authentication failed|Auth failed|Invalid credentials|Permission denied)",
|
|
severity="error",
|
|
description="Authentication failure",
|
|
group="security",
|
|
),
|
|
ErrorPattern(
|
|
name="SSL/TLS Error",
|
|
pattern=r"(?:SSL|TLS|handshake|certificate|HTTPSConnection)",
|
|
severity="error",
|
|
description="SSL/TLS error",
|
|
group="security",
|
|
),
|
|
ErrorPattern(
|
|
name="Disk Full",
|
|
pattern=r"(?:No space left on device|Disk full|ENOSPC)",
|
|
severity="critical",
|
|
description="Disk space exhausted",
|
|
group="system",
|
|
),
|
|
ErrorPattern(
|
|
name="Memory Error",
|
|
pattern=r"(?:Out of memory|Killed|OOM|MemoryError)",
|
|
severity="critical",
|
|
description="Memory exhaustion",
|
|
group="system",
|
|
),
|
|
ErrorPattern(
|
|
name="Segmentation Fault",
|
|
pattern=r"(?:Segmentation fault|SegFault|SIGSEGV)",
|
|
severity="critical",
|
|
description="Segmentation fault",
|
|
group="system",
|
|
),
|
|
ErrorPattern(
|
|
name="Process Crashed",
|
|
pattern=r"(?:Process.*exited|Crashed|exit code|signaled)",
|
|
severity="error",
|
|
description="Process crash",
|
|
group="system",
|
|
),
|
|
ErrorPattern(
|
|
name="Deprecation Warning",
|
|
pattern=r"(?:DeprecationWarning|Deprecation|PendingDeprecationWarning)",
|
|
severity="debug",
|
|
description="Deprecation warning",
|
|
group="code",
|
|
),
|
|
ErrorPattern(
|
|
name="Import Error",
|
|
pattern=r"(?:ImportError|ModuleNotFoundError|Cannot import|No module named)",
|
|
severity="error",
|
|
description="Import error",
|
|
group="code",
|
|
),
|
|
ErrorPattern(
|
|
name="Key Error",
|
|
pattern=r"(?:KeyError|AttributeError|NoneType is not)",
|
|
severity="error",
|
|
description="Key/Attribute error",
|
|
group="code",
|
|
),
|
|
ErrorPattern(
|
|
name="Syntax Error",
|
|
pattern=r"(?:SyntaxError|Parse error|invalid syntax)",
|
|
severity="error",
|
|
description="Syntax error",
|
|
group="code",
|
|
),
|
|
ErrorPattern(
|
|
name="File Not Found",
|
|
pattern=r"(?:FileNotFoundError|No such file or directory)",
|
|
severity="error",
|
|
description="File not found",
|
|
group="system",
|
|
),
|
|
ErrorPattern(
|
|
name="Permission Denied",
|
|
pattern=r"(?:Permission denied|EACCES|EPERM)",
|
|
severity="error",
|
|
description="Permission denied",
|
|
group="system",
|
|
),
|
|
ErrorPattern(
|
|
name="Assertion Failed",
|
|
pattern=r"(?:AssertionError|Assertion failed)",
|
|
severity="error",
|
|
description="Assertion failed",
|
|
group="code",
|
|
),
|
|
ErrorPattern(
|
|
name="Value Error",
|
|
pattern=r"(?:ValueError|Invalid value)",
|
|
severity="error",
|
|
description="Value error",
|
|
group="code",
|
|
),
|
|
ErrorPattern(
|
|
name="Container Error",
|
|
pattern=r"(?:IndexError|TypeError|list index out of range)",
|
|
severity="error",
|
|
description="Container error",
|
|
group="code",
|
|
),
|
|
]
|
|
|
|
def get_patterns_for_content(self, content: str) -> list[ErrorPattern]:
|
|
"""Get matching patterns for content."""
|
|
matches = []
|
|
for pattern in self._patterns:
|
|
if re.search(pattern.pattern, content, re.IGNORECASE):
|
|
matches.append(pattern)
|
|
return matches
|
|
|
|
def get_all_patterns(self) -> dict[str, list[dict]]:
|
|
"""Get all patterns grouped by category."""
|
|
groups = {}
|
|
for pattern in self._patterns:
|
|
if pattern.group not in groups:
|
|
groups[pattern.group] = []
|
|
groups[pattern.group].append({
|
|
"name": pattern.name,
|
|
"pattern": pattern.pattern,
|
|
"severity": pattern.severity,
|
|
"description": pattern.description,
|
|
})
|
|
return groups
|