Coverage for session_mgmt_mcp/utils/logging.py: 41.18%
41 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-01 05:22 -0700
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-01 05:22 -0700
1#!/usr/bin/env python3
2"""Structured logging utilities for session management."""
4import json
5import logging
6import sys
7from datetime import datetime
8from pathlib import Path
11class SessionLogger:
12 """Structured logging for session management with context."""
14 def __init__(self, log_dir: Path) -> None:
15 self.log_dir = log_dir
16 self.log_dir.mkdir(parents=True, exist_ok=True)
17 self.log_file = (
18 log_dir / f"session_management_{datetime.now().strftime('%Y%m%d')}.log"
19 )
21 # Configure logger
22 self.logger = logging.getLogger("session_management")
23 self.logger.setLevel(logging.INFO)
25 # Avoid duplicate handlers
26 if not self.logger.handlers: 26 ↛ 28line 26 didn't jump to line 28 because the condition on line 26 was never true
27 # File handler with structured format
28 file_handler = logging.FileHandler(self.log_file)
29 file_handler.setLevel(logging.INFO)
31 # Console handler for errors
32 console_handler = logging.StreamHandler(sys.stderr)
33 console_handler.setLevel(logging.ERROR)
35 # Structured formatter
36 formatter = logging.Formatter(
37 "%(asctime)s | %(levelname)s | %(funcName)s:%(lineno)d | %(message)s",
38 )
39 file_handler.setFormatter(formatter)
40 console_handler.setFormatter(formatter)
42 self.logger.addHandler(file_handler)
43 self.logger.addHandler(console_handler)
45 def info(self, message: str, **context) -> None:
46 """Log info with optional context."""
47 if context:
48 message = f"{message} | Context: {json.dumps(context)}"
49 self.logger.info(message)
51 def warning(self, message: str, **context) -> None:
52 """Log warning with optional context."""
53 if context:
54 message = f"{message} | Context: {json.dumps(context)}"
55 self.logger.warning(message)
57 def error(self, message: str, **context) -> None:
58 """Log error with optional context."""
59 if context:
60 message = f"{message} | Context: {json.dumps(context)}"
61 self.logger.error(message)
63 def debug(self, message: str, **context) -> None:
64 """Log debug with optional context."""
65 if context:
66 message = f"{message} | Context: {json.dumps(context)}"
67 self.logger.debug(message)
70def get_session_logger() -> SessionLogger:
71 """Get the global session logger instance."""
72 claude_dir = Path.home() / ".claude"
73 return SessionLogger(claude_dir / "logs")