-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy patherrors.py
More file actions
74 lines (61 loc) · 2.41 KB
/
errors.py
File metadata and controls
74 lines (61 loc) · 2.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""Centralized error handling and logging for Attestix."""
import sys
import logging
from enum import Enum
from typing import Optional, Union
from pythonjsonlogger import json as jsonlogger
logger = logging.getLogger("attestix")
class ErrorCategory(str, Enum):
IDENTITY = "IDENTITY"
DID = "DID"
AGENT_CARD = "AGENT_CARD"
DELEGATION = "DELEGATION"
REPUTATION = "REPUTATION"
CRYPTO = "CRYPTO"
CONFIG = "CONFIG"
STORAGE = "STORAGE"
NETWORK = "NETWORK"
COMPLIANCE = "COMPLIANCE"
CREDENTIAL = "CREDENTIAL"
PROVENANCE = "PROVENANCE"
BLOCKCHAIN = "BLOCKCHAIN"
def setup_logging(log_file: str = "attestix_errors.log"):
"""Configure dual logging: stderr (human-readable) + file (JSON structured)."""
logger.setLevel(logging.DEBUG)
# Console handler (stderr)
console = logging.StreamHandler(sys.stderr)
console.setLevel(logging.INFO)
console.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
logger.addHandler(console)
# File handler (JSON)
file_handler = logging.FileHandler(log_file)
file_handler.setLevel(logging.WARNING)
json_formatter = jsonlogger.JsonFormatter(
"%(asctime)s %(levelname)s %(name)s %(message)s"
)
file_handler.setFormatter(json_formatter)
logger.addHandler(file_handler)
# Suppress noisy third-party loggers
for name in ("httpx", "urllib3", "httpcore"):
logging.getLogger(name).setLevel(logging.WARNING)
def log_and_format_error(
function_name: str,
error: Exception,
category: Optional[Union[ErrorCategory, str]] = None,
user_message: Optional[str] = None,
**context,
) -> str:
"""Log error with context and return user-friendly message."""
cat = category.value if isinstance(category, ErrorCategory) else (category or "UNKNOWN")
ctx_str = ", ".join(f"{k}={v}" for k, v in context.items()) if context else ""
logger.error(
f"[{cat}] {function_name}: {error}" + (f" | {ctx_str}" if ctx_str else ""),
exc_info=True,
extra={"category": cat, "function": function_name, **context},
)
if user_message:
return f"Error [{cat}]: {user_message}"
# Sanitize: only return the exception type, not the full message
# (which may contain file paths, private keys, or internal details)
err_type = type(error).__name__
return f"Error [{cat}] in {function_name}: {err_type}. Check server logs for details."