mirror of https://github.com/zulip/zulip.git
tornado: Remove instrument_tornado_ioloop.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
bded7180f7
commit
e4bf7066f3
|
@ -9,15 +9,7 @@ from django.core.management.base import BaseCommand, CommandError, CommandParser
|
||||||
from tornado import autoreload, ioloop
|
from tornado import autoreload, ioloop
|
||||||
from tornado.log import app_log
|
from tornado.log import app_log
|
||||||
|
|
||||||
# We must call zerver.tornado.ioloop_logging.instrument_tornado_ioloop
|
|
||||||
# before we import anything else from our project in order for our
|
|
||||||
# Tornado load logging to work; otherwise we might accidentally import
|
|
||||||
# zerver.lib.queue (which will instantiate the Tornado ioloop) before
|
|
||||||
# this.
|
|
||||||
from zerver.tornado.ioloop_logging import instrument_tornado_ioloop
|
|
||||||
|
|
||||||
settings.RUNNING_INSIDE_TORNADO = True
|
settings.RUNNING_INSIDE_TORNADO = True
|
||||||
instrument_tornado_ioloop()
|
|
||||||
|
|
||||||
from zerver.lib.debug import interactive_debug_listen
|
from zerver.lib.debug import interactive_debug_listen
|
||||||
from zerver.tornado.application import create_tornado_application, setup_tornado_rabbitmq
|
from zerver.tornado.application import create_tornado_application, setup_tornado_rabbitmq
|
||||||
|
|
|
@ -1,83 +1,5 @@
|
||||||
import logging
|
from typing import Dict
|
||||||
import select
|
|
||||||
import time
|
|
||||||
from typing import Any, Dict, List, Tuple
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from tornado.ioloop import IOLoop, PollIOLoop
|
|
||||||
|
|
||||||
# There isn't a good way to get at what the underlying poll implementation
|
|
||||||
# will be without actually constructing an IOLoop, so we just assume it will
|
|
||||||
# be epoll.
|
|
||||||
orig_poll_impl = select.epoll
|
|
||||||
|
|
||||||
# This is used for a somewhat hacky way of passing the port number
|
# This is used for a somewhat hacky way of passing the port number
|
||||||
# into this early-initialized module.
|
# into this early-initialized module.
|
||||||
logging_data: Dict[str, str] = {}
|
logging_data: Dict[str, str] = {}
|
||||||
|
|
||||||
|
|
||||||
class InstrumentedPollIOLoop(PollIOLoop):
|
|
||||||
def initialize(self, **kwargs): # type: ignore[no-untyped-def] # TODO investigate likely buggy monkey patching here
|
|
||||||
super().initialize(impl=InstrumentedPoll(), **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def instrument_tornado_ioloop() -> None:
|
|
||||||
IOLoop.configure(InstrumentedPollIOLoop)
|
|
||||||
|
|
||||||
|
|
||||||
# A hack to keep track of how much time we spend working, versus sleeping in
|
|
||||||
# the event loop.
|
|
||||||
#
|
|
||||||
# Creating a new event loop instance with a custom impl object fails (events
|
|
||||||
# don't get processed), so instead we modify the ioloop module variable holding
|
|
||||||
# the default poll implementation. We need to do this before any Tornado code
|
|
||||||
# runs that might instantiate the default event loop.
|
|
||||||
|
|
||||||
|
|
||||||
class InstrumentedPoll:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self._underlying = orig_poll_impl()
|
|
||||||
self._times: List[Tuple[float, float]] = []
|
|
||||||
self._last_print = 0.0
|
|
||||||
|
|
||||||
# Python won't let us subclass e.g. select.epoll, so instead
|
|
||||||
# we proxy every method. __getattr__ handles anything we
|
|
||||||
# don't define elsewhere.
|
|
||||||
def __getattr__(self, name: str) -> Any:
|
|
||||||
return getattr(self._underlying, name)
|
|
||||||
|
|
||||||
# Call the underlying poll method, and report timing data.
|
|
||||||
def poll(self, timeout: float) -> Any:
|
|
||||||
|
|
||||||
# Avoid accumulating a bunch of insignificant data points
|
|
||||||
# from short timeouts.
|
|
||||||
if timeout < 1e-3:
|
|
||||||
return self._underlying.poll(timeout)
|
|
||||||
|
|
||||||
# Record start and end times for the underlying poll
|
|
||||||
t0 = time.time()
|
|
||||||
result = self._underlying.poll(timeout)
|
|
||||||
t1 = time.time()
|
|
||||||
|
|
||||||
# Log this data point and restrict our log to the past minute
|
|
||||||
self._times.append((t0, t1))
|
|
||||||
while self._times and self._times[0][0] < t1 - 60:
|
|
||||||
self._times.pop(0)
|
|
||||||
|
|
||||||
# Report (at most once every 5s) the percentage of time spent
|
|
||||||
# outside poll
|
|
||||||
if self._times and t1 - self._last_print >= 5:
|
|
||||||
total = t1 - self._times[0][0]
|
|
||||||
in_poll = sum(b - a for a, b in self._times)
|
|
||||||
if total > 0:
|
|
||||||
percent_busy = 100 * (1 - in_poll / total)
|
|
||||||
if settings.PRODUCTION:
|
|
||||||
logging.info(
|
|
||||||
"Tornado %s %5.1f%% busy over the past %4.1f seconds",
|
|
||||||
logging_data.get("port", "unknown"),
|
|
||||||
percent_busy,
|
|
||||||
total,
|
|
||||||
)
|
|
||||||
self._last_print = t1
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
Loading…
Reference in New Issue