|
41 | 41 | from twisted.logger import FileLogObserver, Logger, LogLevel, globalLogPublisher |
42 | 42 | from twisted.internet import defer |
43 | 43 | from twisted.logger import formatEvent |
| 44 | +from twisted.logger import FilteringLogObserver, ILogFilterPredicate, PredicateResult |
44 | 45 | from twisted.web.wsgi import WSGIResource |
45 | 46 | from twisted.web.server import Site |
46 | 47 | from twisted.web.static import File |
47 | 48 | from twisted.web.resource import Resource, NoResource |
48 | 49 | from twisted.internet.endpoints import serverFromString |
49 | 50 | from twisted.python.filepath import FilePath |
| 51 | +from zope.interface import implementer |
50 | 52 |
|
51 | 53 | from . import __version__ |
52 | 54 | from .signals import schedule_changed |
@@ -349,6 +351,32 @@ def formatForSystemd(event): |
349 | 351 | return prefix + s.replace("\n", "\n" + prefix + " ") + "\n" |
350 | 352 |
|
351 | 353 |
|
| 354 | +@implementer(ILogFilterPredicate) |
| 355 | +def dropUnhandledHTTP2Shutdown(event): |
| 356 | + """ |
| 357 | + Suppress the log messages which result from an unhandled error in HTTP/2 |
| 358 | + connection shutdown. See #282 and Twisted #9462. |
| 359 | +
|
| 360 | + This log message is relayed from the :mod:`twisted.python.log` so the |
| 361 | + fields are a little odd: |
| 362 | +
|
| 363 | + * ``'log_namespace'`` is ``'log_legacy'``, and there is a ``'system'`` |
| 364 | + field with a value of ``'-'``. |
| 365 | + * ``'log_text'`` contains the actual log text, including a pre-formatted |
| 366 | + traceback. |
| 367 | + * ``'failure'`` used instead of ``'log_failure'``. |
| 368 | + """ |
| 369 | + if event.get('log_namespace') != 'log_legacy': |
| 370 | + return PredicateResult.maybe |
| 371 | + if event.get('log_level') != LogLevel.critical: |
| 372 | + return PredicateResult.maybe |
| 373 | + if 'failure' not in event or not event['failure'].check(AttributeError): |
| 374 | + return PredicateResult.maybe |
| 375 | + if event['log_text'].startswith('Unhandled Error') and "no attribute 'shutdown'" in event['log_text']: |
| 376 | + return PredicateResult.no |
| 377 | + return PredicateResult.maybe |
| 378 | + |
| 379 | + |
352 | 380 | class TwistedLoggerLogHandler(logging.Handler): |
353 | 381 | publisher = globalLogPublisher |
354 | 382 |
|
@@ -479,8 +507,11 @@ def run(): |
479 | 507 | logging._srcfile = None # Disable expensive collection of location information. |
480 | 508 | root.setLevel(logging.DEBUG if settings.DEBUG else logging.INFO) |
481 | 509 | root.addHandler(TwistedLoggerLogHandler()) |
482 | | - globalLogBeginner.beginLoggingTo([FileLogObserver(sys.stdout, formatForSystemd)], |
483 | | - redirectStandardIO=False) |
| 510 | + observer = FilteringLogObserver( |
| 511 | + FileLogObserver(sys.stdout, formatForSystemd), |
| 512 | + [dropUnhandledHTTP2Shutdown], |
| 513 | + ) |
| 514 | + globalLogBeginner.beginLoggingTo([observer], redirectStandardIO=False) |
484 | 515 |
|
485 | 516 | log.info("Yarrharr {version} starting", version=__version__) |
486 | 517 |
|
|
0 commit comments