Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

logging.py: CPython-compatible logging improvements. #806

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
46 changes: 40 additions & 6 deletions python-stdlib/logging/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
_stream = sys.stderr
_default_fmt = "%(levelname)s:%(name)s:%(message)s"
_default_datefmt = "%Y-%m-%d %H:%M:%S"
_default_formatter = None


class LogRecord:
Expand All @@ -43,25 +44,40 @@ def __init__(self, level=NOTSET):
self.level = level
self.formatter = None

@staticmethod
def _default_formatter():
global _default_formatter
if _default_formatter is None:
_default_formatter = Formatter()
return _default_formatter

def close(self):
pass

def flush(self):
pass

def setLevel(self, level):
self.level = level

def setFormatter(self, formatter):
self.formatter = formatter

def format(self, record):
return self.formatter.format(record)
if self.formatter:
fmt = self.formatter
else:
fmt = self._default_formatter()
return fmt.format(record)


class StreamHandler(Handler):
def __init__(self, stream=None):
super().__init__()
self.stream = _stream if stream is None else stream
self.terminator = "\n"

def close(self):
def flush(self):
Copy link
Member

Choose a reason for hiding this comment

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

Should there still be a close() method which just calls self.flush()?

Copy link
Author

@ned-pcs ned-pcs Mar 19, 2024

Choose a reason for hiding this comment

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

Good question. According to the Cpython docs, Cpython does not have a StreamHandler.close() method, and so the inherited close() method doesn't do any output. I originally had a close() method that called flush() but removed it after looking at the Cpython documentation.

if hasattr(self.stream, "flush"):
self.stream.flush()

Expand Down Expand Up @@ -128,7 +144,7 @@ def log(self, level, msg, *args):
msg = msg % args
self.record.set(self.name, level, msg)
handlers = self.handlers
if not handlers:
if not self.hasHandlers():
handlers = getLogger().handlers
for h in handlers:
h.emit(self.record)
Expand Down Expand Up @@ -161,7 +177,13 @@ def exception(self, msg, *args, exc_info=True):
self.log(ERROR, buf.getvalue())

def addHandler(self, handler):
self.handlers.append(handler)
if handler not in self.handlers:
self.handlers.append(handler)

def removeHandler(self, handler):
if handler in self.handlers:
handler.close()
self.handlers.remove(handler)

def hasHandlers(self):
return len(self.handlers) > 0
Expand Down Expand Up @@ -225,17 +247,28 @@ def basicConfig(
stream=None,
encoding="UTF-8",
force=False,
handlers=None,
):
if "root" not in _loggers:
_loggers["root"] = Logger("root")

logger = _loggers["root"]

if force or not logger.handlers:
if force:
for h in logger.handlers:
h.close()
logger.handlers = []

if len([arg for arg in (filename, stream, handlers) if arg is not None]) > 1:
raise ValueError("can only set one of 'filename', 'stream' or 'handlers'")

if handlers is not None:
for h in handlers:
if h.formatter is None:
h.setFormatter(Formatter(format, datefmt))
logger.addHandler(h)

if not logger.hasHandlers():
if filename is None:
handler = StreamHandler(stream)
else:
Expand All @@ -244,9 +277,10 @@ def basicConfig(
handler.setLevel(level)
handler.setFormatter(Formatter(format, datefmt))

logger.setLevel(level)
logger.addHandler(handler)

logger.setLevel(level)


if hasattr(sys, "atexit"):
sys.atexit(shutdown)
Loading