Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion stackinator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,31 @@ def generate_logfile_name(name=""):
def configure_logging(logfile):
root_logger.setLevel(logging.DEBUG)

class ColoredFormatter(logging.Formatter):
# ANSI escape codes (CSI Control Sequence Introducer)
COLORS = {
logging.WARNING: "\033[1;33m",
logging.ERROR: "\033[1;31m",
logging.CRITICAL: "\033[1;41m",
}
RESET = "\033[0m"
Comment on lines +36 to +43
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ColoredFormatter class applies ANSI color codes unconditionally, which may cause issues in non-TTY environments (e.g., CI/CD pipelines, log files viewed in plain text editors). Consider checking if the output stream is a TTY using sys.stdout.isatty() before applying colors, or provide a way to disable colored output.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be a problem afaict, since I've already seen colors in CI/CD logs (and ANSI escape codes in raw log output)

Copy link
Member

@bcumming bcumming Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a simple tool like this, I don't think we need to worry about toggling color output, because doing it properly requires a combination of detecting TTY, inspecting the environment (https://no-color.org/) and supporting explicit --color and --no-color flags, and determining the precedence of each method.


def format(self, record):
message = super().format(record)

# Prepend level name for warnings and above
if record.levelno >= logging.WARNING:
message = f"{record.levelname}: {message}"

# Apply color based on log level
color = self.COLORS.get(record.levelno, self.RESET)

return f"{color}{message}{self.RESET}"

# create stdout handler and set level to info
ch = logging.StreamHandler(stream=sys.stdout)
ch.setLevel(logging.INFO)
ch.setFormatter(logging.Formatter("%(message)s"))
ch.setFormatter(ColoredFormatter())
root_logger.addHandler(ch)

# create log file handler and set level to debug
Expand Down