Forward file object to :class:`logging.Logger` instance. Arguments: logger (~logging.Logger): Logger instance to forward to. loglevel (int, str): Log level to use when logging messages.
| 176 | |
| 177 | |
| 178 | class LoggingProxy: |
| 179 | """Forward file object to :class:`logging.Logger` instance. |
| 180 | |
| 181 | Arguments: |
| 182 | logger (~logging.Logger): Logger instance to forward to. |
| 183 | loglevel (int, str): Log level to use when logging messages. |
| 184 | """ |
| 185 | |
| 186 | mode = 'w' |
| 187 | name = None |
| 188 | closed = False |
| 189 | loglevel = logging.ERROR |
| 190 | _thread = threading.local() |
| 191 | |
| 192 | def __init__(self, logger, loglevel=None): |
| 193 | # pylint: disable=redefined-outer-name |
| 194 | # Note that the logger global is redefined here, be careful changing. |
| 195 | self.logger = logger |
| 196 | self.loglevel = mlevel(loglevel or self.logger.level or self.loglevel) |
| 197 | self._safewrap_handlers() |
| 198 | |
| 199 | def _safewrap_handlers(self): |
| 200 | # Make the logger handlers dump internal errors to |
| 201 | # :data:`sys.__stderr__` instead of :data:`sys.stderr` to circumvent |
| 202 | # infinite loops. |
| 203 | |
| 204 | def wrap_handler(handler): # pragma: no cover |
| 205 | |
| 206 | class WithSafeHandleError(logging.Handler): |
| 207 | |
| 208 | def handleError(self, record): |
| 209 | try: |
| 210 | traceback.print_exc(None, sys.__stderr__) |
| 211 | except OSError: |
| 212 | pass # see python issue 5971 |
| 213 | |
| 214 | handler.handleError = WithSafeHandleError().handleError |
| 215 | return [wrap_handler(h) for h in self.logger.handlers] |
| 216 | |
| 217 | def write(self, data): |
| 218 | # type: (AnyStr) -> int |
| 219 | """Write message to logging object.""" |
| 220 | if _in_sighandler: |
| 221 | safe_data = safe_str(data) |
| 222 | print(safe_data, file=sys.__stderr__) |
| 223 | return len(safe_data) |
| 224 | if getattr(self._thread, 'recurse_protection', False): |
| 225 | # Logger is logging back to this file, so stop recursing. |
| 226 | return 0 |
| 227 | if data and not self.closed: |
| 228 | self._thread.recurse_protection = True |
| 229 | try: |
| 230 | safe_data = safe_str(data).rstrip('\n') |
| 231 | if safe_data: |
| 232 | self.logger.log(self.loglevel, safe_data) |
| 233 | return len(safe_data) |
| 234 | finally: |
| 235 | self._thread.recurse_protection = False |