From cf5b0a02b032aea29dd50a34442120cc56773e39 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Mon, 2 Feb 2026 10:09:30 +0000 Subject: [PATCH] Add formatters (table, JSON, text) --- loglens/formatters/text_formatter.py | 99 ++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/loglens/formatters/text_formatter.py b/loglens/formatters/text_formatter.py index 08323c2..2363f38 100644 --- a/loglens/formatters/text_formatter.py +++ b/loglens/formatters/text_formatter.py @@ -1,34 +1,93 @@ +"""Text output formatter.""" + from typing import Any from loglens.analyzers.analyzer import AnalysisResult +from loglens.formatters.base import OutputFormatter +from loglens.parsers.base import ParsedLogEntry -class TextFormatter: - """Format analysis results as plain text.""" +class TextFormatter(OutputFormatter): + """Simple text output formatter.""" - def format(self, result: Any) -> str: - """Format result as text.""" - if not hasattr(result, "to_dict"): - return str(result) + def format(self, data: Any) -> str: + """Format data as text.""" + if isinstance(data, AnalysisResult): + return self._format_analysis_result(data) + elif isinstance(data, list): + return self._format_entries(data) + else: + return str(data) - data = result.to_dict() + def _format_analysis_result(self, result: AnalysisResult) -> str: + """Format analysis result as text summary.""" lines = [] lines.append("=" * 60) - lines.append("LOG ANALYSIS") + lines.append("LOG ANALYSIS SUMMARY") lines.append("=" * 60) - lines.append(f"Total Lines: {data['total_lines']}") - lines.append(f"Format: {data['format_detected']}") - lines.append("") - lines.append("Severity Counts:") - lines.append(f" Critical: {data['critical_count']}") - lines.append(f" Error: {data['error_count']}") - lines.append(f" Warning: {data['warning_count']}") - lines.append(f" Debug: {data['debug_count']}") + lines.append(f"Total Lines: {result.total_lines}") + lines.append(f"Parsed Entries: {result.parsed_count}") + lines.append(f"Format Detected: {result.format_detected.value.upper()}") + lines.append(f"Analysis Time: {result.analysis_time.isoformat()}") - if data.get("suggestions"): + if result.time_range: + lines.append(f"Time Range: {result.time_range[0]} to {result.time_range[1]}") + + lines.append("") + lines.append("SEVERITY BREAKDOWN:") + lines.append("-" * 40) + for level in ["critical", "error", "warning", "info", "debug"]: + count = getattr(result, f"{level}_count", 0) + lines.append(f" {level.upper():10} : {count}") + + lines.append("") + lines.append("TOP ERROR PATTERNS:") + lines.append("-" * 40) + for item in result.top_errors[:10]: + lines.append(f" {item['pattern']:30} : {item['count']}") + + if result.suggestions: lines.append("") - lines.append("Suggestions:") - for suggestion in data["suggestions"]: - lines.append(f" - {suggestion}") + lines.append("SUGGESTIONS:") + lines.append("-" * 40) + for i, suggestion in enumerate(result.suggestions, 1): + lines.append(f" {i}. {suggestion}") + + lines.append("=" * 60) + + return "\n".join(lines) + + def _format_entries(self, entries: list[ParsedLogEntry]) -> str: + """Format log entries as text lines.""" + lines = [] + for entry in entries: + parts = [] + + if entry.timestamp: + parts.append(entry.timestamp.strftime("%Y-%m-%d %H:%M:%S")) + + severity = (entry.severity or "UNKNOWN").upper() + parts.append(f"[{severity:8}]") + + parts.append(entry.message or entry.raw_line[:100]) + + if entry.error_pattern: + parts.append(f" <{entry.error_pattern}>") + + lines.append(" ".join(parts)) + + return "\n".join(lines) + + def format_entries_compact(self, entries: list[ParsedLogEntry], max_lines: int = 100) -> str: + """Format entries compactly.""" + lines = [] + for entry in entries[:max_lines]: + severity = (entry.severity or "?").upper()[0] + ts = entry.timestamp.strftime("%H:%M:%S") if entry.timestamp else "??:??:??" + message = entry.message or entry.raw_line[:80] + lines.append(f"{ts} {severity} {message}") + + if len(entries) > max_lines: + lines.append(f"... and {len(entries) - max_lines} more entries") return "\n".join(lines)