Skip to content

Commit a28bc6d

Browse files
committed
Add shutdown method
1 parent 783acf1 commit a28bc6d

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

src/picologging/__init__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import atexit
12
import io
3+
import itertools
24
import os
35
import sys
46
import warnings
@@ -503,3 +505,42 @@ def makeLogRecord(dict):
503505
for k, v in dict.items():
504506
setattr(rv, k, v)
505507
return rv
508+
509+
510+
def shutdown(handlerList=None):
511+
"""
512+
Perform any cleanup actions in the logging system (e.g. flushing
513+
buffers).
514+
Should be called at application exit.
515+
"""
516+
handlers = [logger.handlers for logger in root.manager.loggerDict.values()] + [
517+
root.handlers
518+
]
519+
handlerList = list(itertools.chain(*handlers))
520+
521+
for h in reversed(handlerList):
522+
# errors might occur, for example, if files are locked
523+
# we just ignore them if raiseExceptions is not set
524+
try:
525+
if h:
526+
try:
527+
h.acquire()
528+
# MemoryHandlers might not want to be flushed on close,
529+
# but circular imports prevent us scoping this to just
530+
# those handlers. hence the default to True.
531+
if getattr(h, "flushOnClose", True):
532+
h.flush()
533+
h.close()
534+
except (OSError, ValueError):
535+
# Ignore errors which might be caused
536+
# because handlers have been closed but
537+
# references to them are still around at
538+
# application exit.
539+
pass
540+
finally:
541+
h.release()
542+
except: # ignore everything, as we're shutting down
543+
raise
544+
545+
546+
atexit.register(shutdown)

src/picologging/__init__.pyi

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,17 @@ from io import TextIOWrapper
33
from multiprocessing import Manager
44
from string import Template
55
from types import TracebackType
6-
from typing import Any, Generic, Optional, Pattern, TextIO, TypeVar, Union, overload
6+
from typing import (
7+
Any,
8+
Generic,
9+
Optional,
10+
Pattern,
11+
TextIO,
12+
TypeVar,
13+
Union,
14+
overload,
15+
Sequence,
16+
)
717

818
from _typeshed import StrPath, SupportsWrite
919
from typing_extensions import Literal, TypeAlias
@@ -362,3 +372,6 @@ BASIC_FORMAT: str
362372

363373
def getLevelName(level: _Level) -> Any: ...
364374
def makeLogRecord(dict: Mapping[str, object]) -> LogRecord: ...
375+
def shutdown(
376+
handlerList: Sequence[Any] = ...,
377+
) -> None: ... # handlerList is undocumented

tests/unit/test_picologging.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import logging
21
import sys
32

43
import pytest
54

65
import picologging
6+
from picologging.handlers import BufferingHandler
77

88
levels = [
99
(picologging.DEBUG, "DEBUG"),
@@ -146,3 +146,15 @@ def test_make_log_record():
146146
log_record = picologging.makeLogRecord({"levelno": picologging.WARNING})
147147

148148
assert log_record.levelno == picologging.WARNING
149+
150+
151+
def test_shutdown():
152+
handler = BufferingHandler(capacity=1)
153+
logger = picologging.getLogger("test")
154+
logger.setLevel(picologging.DEBUG)
155+
logger.addHandler(handler)
156+
logger.debug("test")
157+
158+
picologging.shutdown()
159+
160+
assert handler.buffer == []

0 commit comments

Comments
 (0)