Merge branch 'logging'
This commit is contained in:
commit
bf46bcf376
|
@ -16,4 +16,5 @@ dependencies:
|
||||||
- ujson>=1.35
|
- ujson>=1.35
|
||||||
- aiofiles>=0.3.0
|
- aiofiles>=0.3.0
|
||||||
- websockets>=3.2
|
- websockets>=3.2
|
||||||
|
- pyyaml>=3.12
|
||||||
- https://github.com/channelcat/docutils-fork/zipball/master
|
- https://github.com/channelcat/docutils-fork/zipball/master
|
|
@ -8,3 +8,4 @@ pytest
|
||||||
tox
|
tox
|
||||||
ujson
|
ujson
|
||||||
uvloop
|
uvloop
|
||||||
|
pyyaml
|
||||||
|
|
|
@ -3,3 +3,4 @@ httptools
|
||||||
ujson
|
ujson
|
||||||
uvloop
|
uvloop
|
||||||
websockets
|
websockets
|
||||||
|
pyyaml
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import os
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
|
from sanic import __path__ as lib_path
|
||||||
from sanic.log import log
|
from sanic.log import log
|
||||||
from sanic.app import Sanic
|
from sanic.app import Sanic
|
||||||
|
|
||||||
|
@ -14,6 +17,8 @@ if __name__ == "__main__":
|
||||||
help='location of keyfile for SSL.')
|
help='location of keyfile for SSL.')
|
||||||
parser.add_argument('--workers', dest='workers', type=int, default=1, )
|
parser.add_argument('--workers', dest='workers', type=int, default=1, )
|
||||||
parser.add_argument('--debug', dest='debug', action="store_true")
|
parser.add_argument('--debug', dest='debug', action="store_true")
|
||||||
|
parser.add_argument('--log', dest='log_config_path', type=str,
|
||||||
|
default=os.path.join(lib_path[0], 'default.conf'))
|
||||||
parser.add_argument('module')
|
parser.add_argument('module')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -34,7 +39,8 @@ if __name__ == "__main__":
|
||||||
ssl = None
|
ssl = None
|
||||||
|
|
||||||
app.run(host=args.host, port=args.port,
|
app.run(host=args.host, port=args.port,
|
||||||
workers=args.workers, debug=args.debug, ssl=ssl)
|
workers=args.workers, debug=args.debug, ssl=ssl,
|
||||||
|
log_config_path=args.log_config_path)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
log.error("No module named {} found.\n"
|
log.error("No module named {} found.\n"
|
||||||
" Example File: project/sanic_server.py -> app\n"
|
" Example File: project/sanic_server.py -> app\n"
|
||||||
|
|
43
sanic/app.py
43
sanic/app.py
|
@ -1,6 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
|
import logging.config
|
||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
from asyncio import get_event_loop, ensure_future, CancelledError
|
from asyncio import get_event_loop, ensure_future, CancelledError
|
||||||
from collections import deque, defaultdict
|
from collections import deque, defaultdict
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
@ -9,11 +12,12 @@ from traceback import format_exc
|
||||||
from urllib.parse import urlencode, urlunparse
|
from urllib.parse import urlencode, urlunparse
|
||||||
from ssl import create_default_context, Purpose
|
from ssl import create_default_context, Purpose
|
||||||
|
|
||||||
|
from sanic import __path__ as lib_path
|
||||||
from sanic.config import Config
|
from sanic.config import Config
|
||||||
from sanic.constants import HTTP_METHODS
|
from sanic.constants import HTTP_METHODS
|
||||||
from sanic.exceptions import ServerError, URLBuildError, SanicException
|
from sanic.exceptions import ServerError, URLBuildError, SanicException
|
||||||
from sanic.handlers import ErrorHandler
|
from sanic.handlers import ErrorHandler
|
||||||
from sanic.log import log
|
from sanic.log import log, netlog
|
||||||
from sanic.response import HTTPResponse, StreamingHTTPResponse
|
from sanic.response import HTTPResponse, StreamingHTTPResponse
|
||||||
from sanic.router import Router
|
from sanic.router import Router
|
||||||
from sanic.server import serve, serve_multiple, HttpProtocol
|
from sanic.server import serve, serve_multiple, HttpProtocol
|
||||||
|
@ -26,10 +30,17 @@ from sanic.websocket import WebSocketProtocol, ConnectionClosed
|
||||||
class Sanic:
|
class Sanic:
|
||||||
|
|
||||||
def __init__(self, name=None, router=None, error_handler=None,
|
def __init__(self, name=None, router=None, error_handler=None,
|
||||||
load_env=True):
|
load_env=True,
|
||||||
|
log_config_path=os.path.join(lib_path[0], "default.conf")):
|
||||||
|
conf = None
|
||||||
|
if log_config_path and os.path.exists(log_config_path):
|
||||||
|
with open(log_config_path) as f:
|
||||||
|
conf = yaml.load(f)
|
||||||
|
conf.setdefault('version', 1)
|
||||||
|
logging.config.dictConfig(conf)
|
||||||
# Only set up a default log handler if the
|
# Only set up a default log handler if the
|
||||||
# end-user application didn't set anything up.
|
# end-user application didn't set anything up.
|
||||||
if not logging.root.handlers and log.level == logging.NOTSET:
|
if not conf and log.level == logging.NOTSET:
|
||||||
formatter = logging.Formatter(
|
formatter = logging.Formatter(
|
||||||
"%(asctime)s: %(levelname)s: %(message)s")
|
"%(asctime)s: %(levelname)s: %(message)s")
|
||||||
handler = logging.StreamHandler()
|
handler = logging.StreamHandler()
|
||||||
|
@ -46,6 +57,7 @@ class Sanic:
|
||||||
self.router = router or Router()
|
self.router = router or Router()
|
||||||
self.error_handler = error_handler or ErrorHandler()
|
self.error_handler = error_handler or ErrorHandler()
|
||||||
self.config = Config(load_env=load_env)
|
self.config = Config(load_env=load_env)
|
||||||
|
self.log_config_path = log_config_path
|
||||||
self.request_middleware = deque()
|
self.request_middleware = deque()
|
||||||
self.response_middleware = deque()
|
self.response_middleware = deque()
|
||||||
self.blueprints = {}
|
self.blueprints = {}
|
||||||
|
@ -442,7 +454,6 @@ class Sanic:
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
# Request Middleware
|
# Request Middleware
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
|
|
||||||
request.app = self
|
request.app = self
|
||||||
response = await self._run_request_middleware(request)
|
response = await self._run_request_middleware(request)
|
||||||
# No middleware results
|
# No middleware results
|
||||||
|
@ -490,6 +501,13 @@ class Sanic:
|
||||||
log.exception(
|
log.exception(
|
||||||
'Exception occured in one of response middleware handlers'
|
'Exception occured in one of response middleware handlers'
|
||||||
)
|
)
|
||||||
|
if self.log_config_path:
|
||||||
|
netlog.info('', extra={
|
||||||
|
"host": "%s:%d" % request.ip,
|
||||||
|
"request": "%s %s" % (request.method, request.query_string),
|
||||||
|
"status": response.status,
|
||||||
|
"byte": len(response.body)
|
||||||
|
})
|
||||||
|
|
||||||
# pass the response to the correct callback
|
# pass the response to the correct callback
|
||||||
if isinstance(response, StreamingHTTPResponse):
|
if isinstance(response, StreamingHTTPResponse):
|
||||||
|
@ -512,7 +530,8 @@ class Sanic:
|
||||||
def run(self, host="127.0.0.1", port=8000, debug=False, before_start=None,
|
def run(self, host="127.0.0.1", port=8000, debug=False, before_start=None,
|
||||||
after_start=None, before_stop=None, after_stop=None, ssl=None,
|
after_start=None, before_stop=None, after_stop=None, ssl=None,
|
||||||
sock=None, workers=1, loop=None, protocol=None,
|
sock=None, workers=1, loop=None, protocol=None,
|
||||||
backlog=100, stop_event=None, register_sys_signals=True):
|
backlog=100, stop_event=None, register_sys_signals=True,
|
||||||
|
log_config_path=os.path.join(lib_path[0], "default.yml")):
|
||||||
"""Run the HTTP Server and listen until keyboard interrupt or term
|
"""Run the HTTP Server and listen until keyboard interrupt or term
|
||||||
signal. On termination, drain connections before closing.
|
signal. On termination, drain connections before closing.
|
||||||
|
|
||||||
|
@ -539,6 +558,11 @@ class Sanic:
|
||||||
:param protocol: Subclass of asyncio protocol class
|
:param protocol: Subclass of asyncio protocol class
|
||||||
:return: Nothing
|
:return: Nothing
|
||||||
"""
|
"""
|
||||||
|
if log_config_path and os.path.exists(log_config_path):
|
||||||
|
with open(log_config_path) as f:
|
||||||
|
conf = yaml.load(f)
|
||||||
|
conf.setdefault('version', 1)
|
||||||
|
logging.config.dictConfig(conf)
|
||||||
if protocol is None:
|
if protocol is None:
|
||||||
protocol = (WebSocketProtocol if self.websocket_enabled
|
protocol = (WebSocketProtocol if self.websocket_enabled
|
||||||
else HttpProtocol)
|
else HttpProtocol)
|
||||||
|
@ -579,12 +603,19 @@ class Sanic:
|
||||||
before_start=None, after_start=None,
|
before_start=None, after_start=None,
|
||||||
before_stop=None, after_stop=None, ssl=None,
|
before_stop=None, after_stop=None, ssl=None,
|
||||||
sock=None, loop=None, protocol=None,
|
sock=None, loop=None, protocol=None,
|
||||||
backlog=100, stop_event=None):
|
backlog=100, stop_event=None,
|
||||||
|
log_config_path=os.path.join(lib_path[0],
|
||||||
|
"default.yml")):
|
||||||
"""Asynchronous version of `run`.
|
"""Asynchronous version of `run`.
|
||||||
|
|
||||||
NOTE: This does not support multiprocessing and is not the preferred
|
NOTE: This does not support multiprocessing and is not the preferred
|
||||||
way to run a Sanic application.
|
way to run a Sanic application.
|
||||||
"""
|
"""
|
||||||
|
if log_config_path and os.path.exists(log_config_path):
|
||||||
|
with open(log_config_path) as f:
|
||||||
|
conf = yaml.load(f)
|
||||||
|
conf.setdefault('version', 1)
|
||||||
|
logging.config.dictConfig(conf)
|
||||||
if protocol is None:
|
if protocol is None:
|
||||||
protocol = (WebSocketProtocol if self.websocket_enabled
|
protocol = (WebSocketProtocol if self.websocket_enabled
|
||||||
else HttpProtocol)
|
else HttpProtocol)
|
||||||
|
|
52
sanic/default.yml
Normal file
52
sanic/default.yml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
version: 1
|
||||||
|
filters:
|
||||||
|
access_filter:
|
||||||
|
(): sanic.defaultFilter.DefaultFilter
|
||||||
|
param: [0, 10, 20]
|
||||||
|
error_filter:
|
||||||
|
(): sanic.defaultFilter.DefaultFilter
|
||||||
|
param: [30, 40, 50]
|
||||||
|
|
||||||
|
formatters:
|
||||||
|
simple:
|
||||||
|
format: '%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s'
|
||||||
|
datefmt: '%Y-%m-%d %H:%M:%S'
|
||||||
|
access:
|
||||||
|
format: '%(asctime)s - [%(levelname)s][%(host)s]: %(request)s %(message)s %(status)s %(byte)d'
|
||||||
|
datefmt: '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
internal:
|
||||||
|
class: logging.handlers.TimedRotatingFileHandler
|
||||||
|
filters: [access_filter]
|
||||||
|
formatter: simple
|
||||||
|
when: 'D'
|
||||||
|
interval: 1
|
||||||
|
backupCount: 7
|
||||||
|
filename: 'access.log'
|
||||||
|
|
||||||
|
access:
|
||||||
|
class: logging.handlers.TimedRotatingFileHandler
|
||||||
|
filters: [access_filter]
|
||||||
|
formatter: access
|
||||||
|
when: 'D'
|
||||||
|
interval: 1
|
||||||
|
backupCount: 7
|
||||||
|
filename: 'access.log'
|
||||||
|
|
||||||
|
error:
|
||||||
|
class: logging.handlers.TimedRotatingFileHandler
|
||||||
|
filters: [error_filter]
|
||||||
|
filename: 'error.log'
|
||||||
|
when: 'D'
|
||||||
|
interval: 1
|
||||||
|
backupCount: 7
|
||||||
|
formatter: simple
|
||||||
|
|
||||||
|
loggers:
|
||||||
|
sanic:
|
||||||
|
level: DEBUG
|
||||||
|
handlers: [internal, error]
|
||||||
|
network:
|
||||||
|
level: DEBUG
|
||||||
|
handlers: [access, error]
|
13
sanic/defaultFilter.py
Normal file
13
sanic/defaultFilter.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultFilter(logging.Filter):
|
||||||
|
def __init__(self, param=None):
|
||||||
|
self.param = param
|
||||||
|
|
||||||
|
def filter(self, record):
|
||||||
|
if self.param is None:
|
||||||
|
return True
|
||||||
|
if record.levelno in self.param:
|
||||||
|
return True
|
||||||
|
return False
|
|
@ -1,3 +1,4 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
log = logging.getLogger('sanic')
|
log = logging.getLogger('sanic')
|
||||||
|
netlog = logging.getLogger('network')
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -27,6 +27,7 @@ setup_kwargs = {
|
||||||
'description': (
|
'description': (
|
||||||
'A microframework based on uvloop, httptools, and learnings of flask'),
|
'A microframework based on uvloop, httptools, and learnings of flask'),
|
||||||
'packages': ['sanic'],
|
'packages': ['sanic'],
|
||||||
|
'package_data': {'':['default.yml']},
|
||||||
'platforms': 'any',
|
'platforms': 'any',
|
||||||
'classifiers': [
|
'classifiers': [
|
||||||
'Development Status :: 2 - Pre-Alpha',
|
'Development Status :: 2 - Pre-Alpha',
|
||||||
|
@ -46,6 +47,7 @@ requirements = [
|
||||||
ujson,
|
ujson,
|
||||||
'aiofiles>=0.3.0',
|
'aiofiles>=0.3.0',
|
||||||
'websockets>=3.2',
|
'websockets>=3.2',
|
||||||
|
'pyyaml>=3.12'
|
||||||
]
|
]
|
||||||
if strtobool(os.environ.get("SANIC_NO_UJSON", "no")):
|
if strtobool(os.environ.get("SANIC_NO_UJSON", "no")):
|
||||||
print("Installing without uJSON")
|
print("Installing without uJSON")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user