diff --git a/docs/sanic/deploying.md b/docs/sanic/deploying.md index d3652d0d..b6f84001 100644 --- a/docs/sanic/deploying.md +++ b/docs/sanic/deploying.md @@ -15,6 +15,7 @@ keyword arguments: - `protocol` *(default `HttpProtocol`)*: Subclass of [asyncio.protocol](https://docs.python.org/3/library/asyncio-protocol.html#protocol-classes). +- `access_log` *(default `True`)*: Enables log on handling requests (significantly slows server). ## Workers @@ -63,6 +64,20 @@ of the memory leak. See the [Gunicorn Docs](http://docs.gunicorn.org/en/latest/settings.html#max-requests) for more information. +## Disable debug logging + +To improve the performance add `debug=False` and `access_log=False` in the `run` arguments. + +```python +app.run(host='0.0.0.0', port=1337, workers=4, debug=False, access_log=False) +``` + +Running via Gunicorn you can set `--log-level` higher than `info` to not get any access logs anymore. + +``` +gunicorn myapp:app --bind 0.0.0.0:1337 --worker-class sanic.worker.GunicornWorker --log-level warning +``` + ## Asynchronous support This is suitable if you *need* to share the sanic process with other applications, in particular the `loop`. However be advised that this method does not support using multiple processes, and is not the preferred way diff --git a/sanic/worker.py b/sanic/worker.py index e6b4f315..474ed0a3 100644 --- a/sanic/worker.py +++ b/sanic/worker.py @@ -57,6 +57,10 @@ class GunicornWorker(base.Worker): if self.app.callable.websocket_enabled else self.http_protocol ) + + # set ACCESS_LOG on base of logging level + self.app.callable.config.ACCESS_LOG = self.log.loglevel <= logging.INFO + self._server_settings = self.app.callable._helper( loop=self.loop, debug=is_debug, diff --git a/tests/test_worker.py b/tests/test_worker.py index 1fad4f28..04596d77 100644 --- a/tests/test_worker.py +++ b/tests/test_worker.py @@ -4,6 +4,7 @@ import shlex import subprocess import urllib.request from unittest import mock +from urllib.error import HTTPError from sanic.worker import GunicornWorker from sanic.app import Sanic import asyncio @@ -24,12 +25,89 @@ def gunicorn_worker(): worker.kill() +@pytest.fixture(scope='module') +def gunicorn_worker_log_level_info(): + command = ( + 'gunicorn ' + '--bind 127.0.0.1:1338 ' + '--worker-class sanic.worker.GunicornWorker ' + '--log-level info ' + 'examples.simple_server:app' + ) + worker = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) + time.sleep(2) + return worker + + +@pytest.fixture(scope='module') +def gunicorn_worker_log_level_warning(): + command = ( + 'gunicorn ' + '--bind 127.0.0.1:1339 ' + '--worker-class sanic.worker.GunicornWorker ' + '--log-level warning ' + 'examples.simple_server:app' + ) + worker = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) + time.sleep(2) + return worker + + +@pytest.fixture(scope='module') +def gunicorn_worker_log_level_warning2(): + command = ( + 'gunicorn ' + '--bind 127.0.0.1:1340 ' + '--worker-class sanic.worker.GunicornWorker ' + '--log-level warning ' + 'examples.exception_monitoring:app' + ) + worker = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) + time.sleep(2) + return worker + + def test_gunicorn_worker(gunicorn_worker): with urllib.request.urlopen("http://localhost:1337/") as f: res = json.loads(f.read(100).decode()) assert res["test"] +def test_gunicorn_worker_logs_info(gunicorn_worker_log_level_info): + """ + on base of our log-level we get an access message + """ + with urllib.request.urlopen('http://localhost:1338/') as _: + gunicorn_worker_log_level_info.kill() + assert b"(sanic.access)[INFO][127.0.0.1" in gunicorn_worker_log_level_info.stdout.read() + + +def test_gunicorn_worker_logs_warning(gunicorn_worker_log_level_warning): + """ + with log-level warning we are not getting an access messages anymore + """ + with urllib.request.urlopen('http://localhost:1339/') as _: + gunicorn_worker_log_level_warning.kill() + assert not gunicorn_worker_log_level_warning.stdout.read() + + +def test_gunicorn_worker_logs_warning_on_error(gunicorn_worker_log_level_warning2): + """ + with log-level warning we get an error log but don't get an access log + """ + try: + url = urllib.request.urlopen('http://localhost:1340/') + except HTTPError: + pass + else: + url.close() + + gunicorn_worker_log_level_warning2.kill() + log_message = gunicorn_worker_log_level_warning2.stdout.read() + assert b"(sanic.access)[INFO][127.0.0.1" not in log_message + assert b"[ERROR] Exception occurred while handling uri" in log_message + + class GunicornTestWorker(GunicornWorker): def __init__(self): self.app = mock.Mock()