-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathlog.py
More file actions
81 lines (63 loc) · 2.4 KB
/
log.py
File metadata and controls
81 lines (63 loc) · 2.4 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
75
76
77
78
79
80
81
"""Versor logging system.
Provides structured logging under the ``versor`` hierarchy.
All task/model output goes through :func:`get_logger` instead of ``print()``.
Environment variables:
VERSOR_LOG_LEVEL - DEBUG / INFO (default) / WARNING / ERROR
VERSOR_LOG_FILE - optional path; appends plain-text log lines
"""
import logging
import os
import sys
_CONFIGURED = False
# ANSI colour codes (used only when stderr is a TTY)
_COLORS = {
logging.DEBUG: "\033[36m", # cyan
logging.INFO: "\033[32m", # green
logging.WARNING: "\033[33m", # yellow
logging.ERROR: "\033[31m", # red
logging.CRITICAL: "\033[35m", # magenta
}
_RESET = "\033[0m"
class _ColorFormatter(logging.Formatter):
"""Adds ANSI colour to level names when writing to a TTY."""
def __init__(self, fmt: str, use_color: bool = True):
super().__init__(fmt)
self.use_color = use_color
def format(self, record: logging.LogRecord) -> str:
if self.use_color:
color = _COLORS.get(record.levelno, "")
record.levelname = f"{color}{record.levelname}{_RESET}"
return super().format(record)
def _configure_once() -> None:
"""One-time lazy init of the ``versor`` root logger."""
global _CONFIGURED
if _CONFIGURED:
return
_CONFIGURED = True
root = logging.getLogger("versor")
level_name = os.environ.get("VERSOR_LOG_LEVEL", "INFO").upper()
root.setLevel(getattr(logging, level_name, logging.INFO))
root.propagate = False
# Console handler (stderr, so tqdm on stderr is unaffected)
fmt = "%(levelname)s %(name)s: %(message)s"
use_color = hasattr(sys.stderr, "isatty") and sys.stderr.isatty()
console = logging.StreamHandler(sys.stderr)
console.setFormatter(_ColorFormatter(fmt, use_color=use_color))
root.addHandler(console)
# Optional file handler
log_file = os.environ.get("VERSOR_LOG_FILE")
if log_file:
fh = logging.FileHandler(log_file, mode="a")
fh.setFormatter(logging.Formatter(
"%(asctime)s %(levelname)s %(name)s: %(message)s"
))
root.addHandler(fh)
def get_logger(name: str) -> logging.Logger:
"""Return a logger under the ``versor`` hierarchy.
Args:
name: Typically ``__name__`` of the calling module.
Returns:
A :class:`logging.Logger` instance.
"""
_configure_once()
return logging.getLogger(f"versor.{name}")