X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=logging_utils.py;h=25919a765ef2430283cb0e67572d326ca62507f0;hb=b10d30a46e601c9ee1f843241f2d69a1f90f7a94;hp=b7fd11fd8168cfbc985fa1fa60e28704b86075bd;hpb=1574e8a3a8982fab9278ad534f9427d464e4bffb;p=python_utils.git diff --git a/logging_utils.py b/logging_utils.py index b7fd11f..25919a7 100644 --- a/logging_utils.py +++ b/logging_utils.py @@ -5,11 +5,13 @@ import contextlib import datetime import enum +import io import logging from logging.handlers import RotatingFileHandler, SysLogHandler import os import pytz import sys +from typing import Iterable, Optional # This module is commonly used by others in here and should avoid # taking any unnecessary dependencies back on them. @@ -93,7 +95,7 @@ cfg.add_argument( help='logging.info also prints to stdout.' ) -# See also: OutputMultiplexer/OutputContext +# See also: OutputMultiplexer cfg.add_argument( '--logging_captures_prints', action=argparse_utils.ActionNoYes, @@ -239,46 +241,46 @@ class OutputMultiplexer(object): class Destination(enum.IntEnum): """Bits in the destination_bitv bitvector. Used to indicate the output destination.""" - STDOUT = 0x1 - STDERR = 0x2 - LOG_DEBUG = 0x4 # -\ - LOG_INFO = 0x8 # | - LOG_WARNING = 0x10 # > Should provide logger to the c'tor. - LOG_ERROR = 0x20 # | - LOG_CRITICAL = 0x40 # _/ - FILENAME = 0x80 # Must provide a filename to the c'tor. - FILEHANDLE = 0x100 # Must provide a handle to the c'tor. - HLOG = 0x200 + LOG_DEBUG = 0x01 # -\ + LOG_INFO = 0x02 # | + LOG_WARNING = 0x04 # > Should provide logger to the c'tor. + LOG_ERROR = 0x08 # | + LOG_CRITICAL = 0x10 # _/ + FILENAMES = 0x20 # Must provide a filename to the c'tor. + FILEHANDLES = 0x40 # Must provide a handle to the c'tor. + HLOG = 0x80 ALL_LOG_DESTINATIONS = ( LOG_DEBUG | LOG_INFO | LOG_WARNING | LOG_ERROR | LOG_CRITICAL ) - ALL_OUTPUT_DESTINATIONS = 0x2FF + ALL_OUTPUT_DESTINATIONS = 0x8F def __init__(self, destination_bitv: int, *, logger=None, - filename=None, - handle=None): + filenames: Optional[Iterable[str]] = None, + handles: Optional[Iterable[io.TextIOWrapper]] = None): if logger is None: logger = logging.getLogger(None) self.logger = logger - if filename is not None: - self.f = open(filename, "wb", buffering=0) + if filenames is not None: + self.f = [ + open(filename, 'wb', buffering=0) for filename in filenames + ] else: - if self.destination_bitv & OutputMultiplexer.FILENAME: + if destination_bitv & OutputMultiplexer.FILENAMES: raise ValueError( - "Filename argument is required if bitv & FILENAME" + "Filenames argument is required if bitv & FILENAMES" ) self.f = None - if handle is not None: - self.h = handle + if handles is not None: + self.h = [handle for handle in handles] else: - if self.destination_bitv & OutputMultiplexer.FILEHANDLE: + if destination_bitv & OutputMultiplexer.Destination.FILEHANDLES: raise ValueError( - "Handle argument is required if bitv & FILEHANDLE" + "Handle argument is required if bitv & FILEHANDLES" ) self.h = None @@ -288,13 +290,13 @@ class OutputMultiplexer(object): return self.destination_bitv def set_destination_bitv(self, destination_bitv: int): - if destination_bitv & self.Destination.FILENAME and self.f is None: + if destination_bitv & self.Destination.FILENAMES and self.f is None: raise ValueError( - "Filename argument is required if bitv & FILENAME" + "Filename argument is required if bitv & FILENAMES" ) - if destination_bitv & self.Destination.FILEHANDLE and self.h is None: + if destination_bitv & self.Destination.FILEHANDLES and self.h is None: raise ValueError( - "Handle argument is required if bitv & FILEHANDLE" + "Handle argument is required if bitv & FILEHANDLES" ) self.destination_bitv = destination_bitv @@ -315,25 +317,23 @@ class OutputMultiplexer(object): sep = " " if end is None: end = "\n" - if self.destination_bitv & self.Destination.STDOUT: - print(buf, file=sys.stdout, sep=sep, end=end) - if self.destination_bitv & self.Destination.STDERR: - print(buf, file=sys.stderr, sep=sep, end=end) if end == '\n': buf += '\n' if ( - self.destination_bitv & self.Destination.FILENAME and + self.destination_bitv & self.Destination.FILENAMES and self.f is not None ): - self.f.write(buf.encode('utf-8')) - self.f.flush() + for _ in self.f: + _.write(buf.encode('utf-8')) + _.flush() if ( - self.destination_bitv & self.Destination.FILEHANDLE and + self.destination_bitv & self.Destination.FILEHANDLES and self.h is not None ): - self.h.write(buf) - self.h.flush() + for _ in self.h: + _.write(buf) + _.flush() buf = strip_escape_sequences(buf) if self.logger is not None: @@ -352,21 +352,22 @@ class OutputMultiplexer(object): def close(self): if self.f is not None: - self.f.close() + for _ in self.f: + _.close() -class OutputContext(OutputMultiplexer, contextlib.ContextDecorator): +class OutputMultiplexerContext(OutputMultiplexer, contextlib.ContextDecorator): def __init__(self, destination_bitv: OutputMultiplexer.Destination, *, - logger=None, - filename=None, - handle=None): + logger = None, + filenames = None, + handles = None): super().__init__( destination_bitv, logger=logger, - filename=filename, - handle=handle) + filenames=filenames, + handles=handles) def __enter__(self): return self