Skip to content
Snippets Groups Projects
Commit bd18b7c6 authored by Piotr Maślanka's avatar Piotr Maślanka
Browse files

add logging to DumpToFileHandler

parent 2e8ca3d9
No related branches found
No related tags found
No related merge requests found
# v2.14.25 # v2.14.25
* moved `distutils` to [snakehouse](https://pypi.org/project/snakehouse/) * moved `distutils` to [snakehouse](https://pypi.org/project/snakehouse/)
* added an option to write to logs in `DumpToFileHandler`
__version__ = '2.14.25a2' __version__ = '2.14.25a3'
from __future__ import print_function, absolute_import, division from __future__ import print_function, absolute_import, division
import enum import enum
import logging
import os import os
import typing as tp import typing as tp
import uuid import uuid
from logging import Logger
from satella.coding import silence_excs from satella.coding import silence_excs
from satella.files import DevNullFilelikeObject from satella.files import DevNullFilelikeObject
from satella.instrumentation import Traceback from satella.instrumentation import Traceback
from .exception_handlers import BaseExceptionHandler from .exception_handlers import BaseExceptionHandler
AsStreamTypeAccept = tp.Union[str, tp.IO, None] AsStreamTypeAccept = tp.Union[str, tp.IO, None, Logger, tp.Tuple[Logger, int]]
AsStreamTypeAcceptHR = tp.Union[str, tp.TextIO] AsStreamTypeAcceptHR = tp.Union[str, tp.TextIO, Logger, tp.Tuple[Logger, int]]
AsStreamTypeAcceptIN = tp.Union[str, tp.BinaryIO] AsStreamTypeAcceptIN = tp.Union[str, tp.BinaryIO]
...@@ -19,10 +21,11 @@ class StreamType(enum.IntEnum): ...@@ -19,10 +21,11 @@ class StreamType(enum.IntEnum):
MODE_FILE = 0 # write to file MODE_FILE = 0 # write to file
MODE_STREAM = 1 # a file-like object was provided MODE_STREAM = 1 # a file-like object was provided
MODE_DEVNULL = 2 # just redirect to /dev/null MODE_DEVNULL = 2 # just redirect to /dev/null
MODE_LOGGER = 3 # just a logger
class AsStream: class AsStream:
__slots__ = ('o', 'human_readable', 'mode', 'file') __slots__ = ('o', 'human_readable', 'mode', 'file', 'level', 'logger')
def __init__(self, o: AsStreamTypeAccept, human_readable: bool): def __init__(self, o: AsStreamTypeAccept, human_readable: bool):
""" """
...@@ -40,7 +43,14 @@ class AsStream: ...@@ -40,7 +43,14 @@ class AsStream:
self.o = os.path.join(o, uuid.uuid4().hex) self.o = os.path.join(o, uuid.uuid4().hex)
self.mode = StreamType.MODE_FILE self.mode = StreamType.MODE_FILE
elif isinstance(o, tuple) and isinstance(o[0], Logger):
self.mode = StreamType.MODE_LOGGER
self.level = o[1]
self.logger = o[0]
elif isinstance(o, Logger):
self.mode = StreamType.MODE_LOGGER
self.logger = o
self.level = logging.ERROR
elif hasattr(o, 'write'): elif hasattr(o, 'write'):
self.mode = StreamType.MODE_STREAM self.mode = StreamType.MODE_STREAM
...@@ -78,7 +88,8 @@ class DumpToFileHandler(BaseExceptionHandler): ...@@ -78,7 +88,8 @@ class DumpToFileHandler(BaseExceptionHandler):
.flush() .flush()
:param human_readables: iterable of either a file-like objects, or paths where :param human_readables: iterable of either a file-like objects, or paths where
human-readable files will be output human-readable files will be output. Also a logger can be put here, or a tuple
of logger, logging level. Default logging level will be ERROR.
:param trace_pickles: iterable of either a file-like objects, or paths where pickles with :param trace_pickles: iterable of either a file-like objects, or paths where pickles with
stack status will be output stack status will be output
:raises TypeError: invalid stream :raises TypeError: invalid stream
...@@ -102,9 +113,12 @@ class DumpToFileHandler(BaseExceptionHandler): ...@@ -102,9 +113,12 @@ class DumpToFileHandler(BaseExceptionHandler):
# continue with it # continue with it
for q in self.hr: for q in self.hr:
with q as f: if q.mode == StreamType.MODE_LOGGER:
f.write('Unhandled exception caught: \n') q.logger.log(q.level, str(value), exc_info=value, stack_info=tb.pretty_format())
tb.pretty_print(output=f) else:
with q as f:
f.write('Unhandled exception caught: \n')
tb.pretty_print(output=f)
for q in self.tb: for q in self.tb:
with q as f: with q as f:
......
...@@ -2,6 +2,7 @@ import io ...@@ -2,6 +2,7 @@ import io
import os import os
import pickle import pickle
import tempfile import tempfile
import logging
import threading import threading
from satella.coding import silence_excs from satella.coding import silence_excs
...@@ -10,6 +11,9 @@ from satella.instrumentation import Traceback ...@@ -10,6 +11,9 @@ from satella.instrumentation import Traceback
from . import ExceptionHandlingTestCase from . import ExceptionHandlingTestCase
logger = logging.getLogger(__name__)
class TestDumpToFile(ExceptionHandlingTestCase): class TestDumpToFile(ExceptionHandlingTestCase):
def test_exception_handler(self): def test_exception_handler(self):
...@@ -40,7 +44,7 @@ class TestDumpToFile(ExceptionHandlingTestCase): ...@@ -40,7 +44,7 @@ class TestDumpToFile(ExceptionHandlingTestCase):
self.sq, self.sa, self.tf = io.StringIO(), io.StringIO(), tempfile.mktemp() self.sq, self.sa, self.tf = io.StringIO(), io.StringIO(), tempfile.mktemp()
self.op = io.BytesIO() self.op = io.BytesIO()
self.exception_handler = DumpToFileHandler( self.exception_handler = DumpToFileHandler(
human_readables=[self.sq, self.sa, self.tf, None], human_readables=[self.sq, self.sa, self.tf, None, logger, (logger, logging.WARNING)],
trace_pickles=[self.op]) trace_pickles=[self.op])
self.exception_handler.install() self.exception_handler.install()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment