-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
aiohttp.wep.Application.make_handler access_log_class support #2316
Conversation
Here is example of class AccessLogger(AbstractAccessLogger):
def log(self, request, response, time):
msg = '{request.remote} - - {t} "{r}" {response.status} {response.body_length} "{referrer}" "{user_agent}"'
r = '%s %s HTTP/%s.%s' % tuple((request.method,
request.path_qs) + request.version)
t = datetime.datetime.utcnow().strftime('[%d/%b/%Y:%H:%M:%S +0000]')
self.logger.info(msg.format(
t=t,
r=r,
referrer=request.headers.get('Referrer', '-'),
user_agent=request.headers.get('User-Agent', '-'),
request=request,
response=response,
time=time,
)) I've played a bit with this Most useful example is something like: class AccessLogger(AbstractAccessLogger):
def log(self, request, response, time):
self.logger.info(f'{request.remote} "{request.method}" -> {response.status}') If proposal at least makes some sense, I'll do full test coverage/docs/etc |
Codecov Report
@@ Coverage Diff @@
## master #2316 +/- ##
==========================================
+ Coverage 97.24% 97.24% +<.01%
==========================================
Files 39 39
Lines 8195 8204 +9
Branches 1435 1436 +1
==========================================
+ Hits 7969 7978 +9
Misses 98 98
Partials 128 128
Continue to review full report at Codecov.
|
Please make the feature well documented |
aiohttp/web_protocol.py
Outdated
@@ -83,6 +83,7 @@ def __init__(self, manager, *, loop=None, | |||
tcp_keepalive=True, | |||
slow_request_timeout=None, | |||
logger=server_logger, | |||
access_log_factory=helpers.AccessLogger, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a factory, but a class. Otherwise need to document what factory should return - I think, that's abstraction level is redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about access_log_cls
or access_log_class
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
access_log_class
is good one.
class AbstractAccessLogger(ABC): | ||
|
||
def __init__(self, logger, log_format): | ||
self.logger = logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log_format
seems to be lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but it is exactly how current AccessLogger
works, as well default log_format
is AccessLogger.LOG_FORMAT
not sure is it needs to be stored as self.log_format
. My idea was that, logger
itself is only one required attribute, log_format
is actually optional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, if I'm making own AccessLogger
I should keep in mind, that super requires two arguments, one of which it will set to attributes and one that it will ignore? A bit not friendly behavior. The AccessLogger
may have overloaded __init__
to accept log_format
, but if the AbstractAccessLogger
doesn't uses it in anyway there is no point to keep it there.
aiohttp/abc.py
Outdated
self.logger = logger | ||
|
||
@abstractmethod | ||
def log(self, request, response, time): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to document which objects and types that method accepts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, it will be documented
@kxepal What do You think to make def log(self, request, response, time):
try:
self._log(request, response, time)
except Exception as e:
self.logger.exception("Error in logging", exc_info=e) |
@hellysmile |
There is one more question, it will be nice to place somewhere assert issubclass(access_log_class, AbstractAccessLogger), access_log_class but where to place is, actually |
@hellysmile push the check into |
aiohttp/web.py
Outdated
@@ -231,6 +231,14 @@ def middlewares(self): | |||
return self._middlewares | |||
|
|||
def make_handler(self, *, loop=None, **kwargs): | |||
if 'access_log_class' in kwargs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just add access_log_class=helpers.AccessLogger
into method signature.
aiohttp/web.py
Outdated
if 'access_log_class' in kwargs: | ||
access_log_class = kwargs['access_log_class'] | ||
|
||
assert issubclass(access_log_class, AbstractAccessLogger), ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be TypeError
, not AssertionError
.
aiohttp/abc.py
Outdated
"""Emit log to logger""" | ||
|
||
try: | ||
self._log(request, response, time) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's drop _log()
and make log()
abstract method.
On one hand formatting logic always should be wrapped by catching exception obviously.
On other -- let's not make any decision about implementation details.
Implementor might want to do other things than just registering caught exception.
Let's keep ABC very abstract, my guts feel that there are many contradictory might occur if we will bake a code in abstract class.
aiohttp/abc.py
Outdated
def _log(self, request, response, time): | ||
""" | ||
|
||
:param request: Request object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use sphinx formatting in docstrings -- it is a text for readers.
I'd like to rip it out everywhere and use only hand written documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@kxepal ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One little bit about error message. The rest looks fine.
aiohttp/web.py
Outdated
|
||
if not issubclass(access_log_class, AbstractAccessLogger): | ||
raise TypeError('access_log_class must be subclass of ' | ||
'aiohttp.abc.AbstractAccessLogger') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to add got {}
to error message to simplify understanding what's wrong with the logger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, thanks!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a [new issue] for related bugs. |
What do these changes do?
Adds support pluggable
aiohttp.helpers.AccessLogger
foraiohttp.wep.Application.make_handler
Are there changes in behavior for the user?
No breaking changes.
Related issue number
#2315
Checklist
CONTRIBUTORS.txt
changes
folder<issue_id>.<type>
for example (588.bug)issue_id
change it to the pr id after creating the pr.feature
: Signifying a new feature..bugfix
: Signifying a bug fix..doc
: Signifying a documentation improvement..removal
: Signifying a deprecation or removal of public API..misc
: A ticket has been closed, but it is not of interest to users.