Skip to content

Commit

Permalink
Colourise log output (#2114)
Browse files Browse the repository at this point in the history
  • Loading branch information
vkbo authored Nov 22, 2024
2 parents 7a9da5f + 893f18c commit 8c51363
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 5 deletions.
29 changes: 27 additions & 2 deletions novelwriter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
=======================
File History:
Created: 2018-09-22 [0.0.1]
Created: 2018-09-22 [0.0.1] main
Created: 2024-11-22 [2.6b2] ColorFormatter
This file is a part of novelWriter
Copyright 2018–2024, Veronica Berglyd Olsen
Expand Down Expand Up @@ -77,6 +78,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
"version",
"info",
"debug",
"color",
"style=",
"config=",
"data=",
Expand All @@ -98,6 +100,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
" -v, --version Print program version and exit.\n"
" --info Print additional runtime information.\n"
" --debug Print debug output. Includes --info.\n"
" --color Add ANSI colors to log output.\n"
" --meminfo Show memory usage information in the status bar.\n"
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
" --config= Alternative config file.\n"
Expand All @@ -107,6 +110,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
# Defaults
logLevel = logging.WARN
logFormat = "{levelname:8} {message:}"
logFormatter = logging.Formatter
confPath = None
dataPath = None
testMode = False
Expand Down Expand Up @@ -137,6 +141,8 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
CONFIG.isDebug = True
logLevel = logging.DEBUG
logFormat = "[{asctime:}] {filename:>18}:{lineno:<4d} {levelname:8} {message:}"
elif inOpt == "--color":
logFormatter = ColorFormatter
elif inOpt == "--style":
qtStyle = inArg
elif inOpt == "--config":
Expand All @@ -154,7 +160,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
if len(pkgLogger.handlers) == 0:
# Make sure we only create one logger (mostly an issue with tests)
cHandle = logging.StreamHandler()
cHandle.setFormatter(logging.Formatter(fmt=logFormat, style="{"))
cHandle.setFormatter(logFormatter(fmt=logFormat, style="{"))
pkgLogger.addHandler(cHandle)

logger.info("Starting novelWriter %s (%s) %s", __version__, __hexversion__, __date__)
Expand Down Expand Up @@ -241,3 +247,22 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
nwGUI.postLaunchTasks(cmdOpen)

sys.exit(app.exec())


class ColorFormatter(logging.Formatter):

def __init__(self, fmt: str, style: str) -> None:
super().__init__(fmt, style="{")
self._formats = {
logging.DEBUG: f"\033[1;34m{fmt}\033[0m",
logging.INFO: f"\033[1;32m{fmt}\033[0m",
logging.WARNING: f"\033[1;33m{fmt}\033[0m",
logging.ERROR: f"\033[1;31m{fmt}\033[0m",
logging.CRITICAL: f"\033[1;31m{fmt}\033[0m",
}
return

def format(self, record: logging.LogRecord) -> str:
"""Overload the format string for each record."""
self._style._fmt = self._formats.get(record.levelno, "ERR")
return super().format(record)
27 changes: 24 additions & 3 deletions tests/test_base/test_base_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

import pytest

from novelwriter import CONFIG, logger, main
from novelwriter import CONFIG, ColorFormatter, logger, main

from tests.mocked import MockGuiMain

Expand Down Expand Up @@ -99,14 +99,14 @@ def testBaseInit_Options(monkeypatch, fncPath):

# Log Levels
nwGUI = main(
["--testmode", "--info", f"--config={fncPath}", f"--data={fncPath}"]
["--testmode", "--info", "--color", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI is not None
assert logger.getEffectiveLevel() == logging.INFO
assert nwGUI.closeMain() == "closeMain"

nwGUI = main(
["--testmode", "--debug", f"--config={fncPath}", f"--data={fncPath}"]
["--testmode", "--debug", "--color", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI is not None
assert logger.getEffectiveLevel() == logging.DEBUG
Expand Down Expand Up @@ -171,3 +171,24 @@ def testBaseInit_Imports(caplog, monkeypatch, fncPath):
assert "At least Python" in caplog.messages[0]
assert "At least Qt5" in caplog.messages[1]
assert "At least PyQt5" in caplog.messages[2]


@pytest.mark.base
def testBaseInit_ColorFormatter(qtbot, monkeypatch, fncPath, tstPaths):
"""Check launching the main GUI."""
formatter = ColorFormatter(fmt="<{message:}>", style="{")

record = logging.LogRecord("", logging.INFO, "", 1, "Info", None, None)
assert formatter.format(record) == "\x1b[1;32m<Info>\x1b[0m"

record = logging.LogRecord("", logging.DEBUG, "", 1, "Debug", None, None)
assert formatter.format(record) == "\x1b[1;34m<Debug>\x1b[0m"

record = logging.LogRecord("", logging.WARNING, "", 1, "Warning", None, None)
assert formatter.format(record) == "\x1b[1;33m<Warning>\x1b[0m"

record = logging.LogRecord("", logging.ERROR, "", 1, "Error", None, None)
assert formatter.format(record) == "\x1b[1;31m<Error>\x1b[0m"

record = logging.LogRecord("", logging.CRITICAL, "", 1, "Critical", None, None)
assert formatter.format(record) == "\x1b[1;31m<Critical>\x1b[0m"

0 comments on commit 8c51363

Please sign in to comment.