-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
145 lines (117 loc) · 3.83 KB
/
Copy pathutils.py
File metadata and controls
145 lines (117 loc) · 3.83 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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""
# =============================================================================
# Script: utils.py
# Author: maxdaylight
# Last Updated: 2025-10-08 00:02:51 UTC
# Updated By: maxdaylight
# Version: 1.0.0
# Additional Info: Color output and logging utilities
# with ANSI stripping for files
# =============================================================================
Utilities for consistent colorized console output and structured logging
with UTC timestamps.
"""
from __future__ import annotations
import datetime
import logging
import os
import re
import socket
import sys
try:
from colorama import Fore as _Fore
from colorama import Style as _Style
from colorama import init as colorama_init
HAS_COLORAMA = True
# Expose names for type checkers
Fore = _Fore
Style = _Style
colorama_init(autoreset=True)
except Exception: # pragma: no cover - optional dependency
HAS_COLORAMA = False
from typing import Any
Fore = None
Style = None
def colorama_init(
*args: Any, **kwargs: Any
) -> None:
return None
ANSI_COLORS: dict[str, str] = {
"reset": "\033[0m",
"white": "\033[37m",
"cyan": "\033[36m",
"green": "\033[32m",
"yellow": "\033[33m",
"red": "\033[31m",
"magenta": "\033[35m",
"darkgray": "\033[90m",
}
ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
def strip_ansi(s: str) -> str:
return ANSI_RE.sub("", s)
def write_color_output(message: str, *, color: str = "white") -> None:
"""Write a message to stdout with the specified color.
Ensures color reset to avoid bleeding. Falls back to plain text if color
not supported.
"""
color_key = color.lower()
if HAS_COLORAMA:
assert Fore is not None and Style is not None
color_map = {
"white": Fore.WHITE,
"cyan": Fore.CYAN,
"green": Fore.GREEN,
"yellow": Fore.YELLOW,
"red": Fore.RED,
"magenta": Fore.MAGENTA,
"darkgray": Fore.LIGHTBLACK_EX,
}
prefix = color_map.get(color_key, Fore.WHITE)
print(f"{prefix}{message}{Style.RESET_ALL}")
else:
# If not TTY or on platforms without ANSI support, print plain text
if sys.stdout.isatty():
prefix = ANSI_COLORS.get(color_key, ANSI_COLORS["white"])
else:
prefix = ""
reset = ANSI_COLORS["reset"] if prefix else ""
print(f"{prefix}{message}{reset}")
class AnsiStrippingFileHandler(logging.FileHandler):
def emit(
self, record: logging.LogRecord
) -> None:
if isinstance(record.msg, str):
record.msg = strip_ansi(record.msg)
super().emit(record)
def build_logger(
name: str = "app",
*,
log_dir: str | None = None
) -> logging.Logger:
"""Create a logger that writes UTC timestamps and strips ANSI from files.
The log file is named: {name}_{hostname}_{YYYY-MM-DD_HH-MM-SS}.log
"""
logger = logging.getLogger(name)
if logger.handlers:
return logger
logger.setLevel(logging.INFO)
# UTC ISO-like timestamps
fmt = logging.Formatter(
fmt="%(asctime)sZ %(levelname)s %(name)s %(message)s",
datefmt="%Y-%m-%dT%H:%M:%S",
)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(fmt)
logger.addHandler(console)
host = socket.gethostname()
ts = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d_%H-%M-%S")
base_dir = log_dir or os.path.dirname(__file__)
os.makedirs(base_dir, exist_ok=True)
log_path = os.path.join(base_dir, f"{name}_{host}_{ts}.log")
file_handler = AnsiStrippingFileHandler(log_path, encoding="utf-8")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(fmt)
logger.addHandler(file_handler)
logger.info("Logger initialized (UTC timestamps)")
return logger