-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
python: allow to override the UvicornServer's default log config #2782
Conversation
Hi folks! Still need to figure out how to test this change, but early feedback is really good :) |
396970e
to
e0e7b31
Compare
Added a simple test case to the PR's description, should be ready for a review :) |
4685e4d
to
3044b05
Compare
lovely, |
73cd31e
to
8c8a8f9
Compare
Some tests are still failing, IIUC due to the aix360 package that depends on tensorflow==1.14 that in turn is not compatible with Python 3.8 afaics.. |
Summary for the reviewers (based on my understanding of the code):
If you want I can try to split the pull request into two steps:
Lemme know :) |
Created Trusted-AI/AIX360#172 to see if we can get a bump in the aix360's version. |
@elukey : What about model_server logging_format ? Can you include changes to allow formatting that as well ? This PR has no changes #2762 and has been closed. If, we do not see the traction on this one, it would be great to get the changes corresponding to influence the logger format too via this PR itself. |
Hi! I think that we should keep the two things separated, my PR is related to Uvicorn's logging, meanwhile what you point out is related to the model server's logging. It is equally important but my PR is already big and I'd like to avoid adding things, unless the upstream devs suggests so. Could you open a PR like #2762 with the required changes? |
Thanks a lot for the feedback, I have pushed another version of the pull request, but the |
536fa3e
to
7f7f28c
Compare
Added the |
@yuzisun should be ready for a review :) |
Forgot to run
|
9810d8f
to
ef9d13b
Compare
Found a workaround and re-tested everything, lemme know your thoughts :) |
@yuzisun Hi! Do you think that the PR could be reviewed? Let me know if it is missing anything major, it would be great if it was included in 0.11 (to get access log working again asap :). |
@@ -76,6 +80,7 @@ class ModelServer: | |||
enable_grpc (bool): Whether to turn on grpc server. Default: ``True`` | |||
enable_docs_url (bool): Whether to turn on ``/docs`` Swagger UI. Default: ``False``. | |||
enable_latency_logging (bool): Whether to log latency metric. Default: ``True``. | |||
log_config_file (dict): File path containing UvicornServer's log config. Default: ``None``. |
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.
missing access_log_format
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.
Added :)
if access_log_format: | ||
from asgi_logger import AccessLoggerMiddleware | ||
logging.getLogger("uvicorn.access").handlers = [] | ||
app.add_middleware( |
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.
How this is different from the uvicorn.logging.AccessFormatter
config?
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.
My understanding from
- https://github.com/encode/uvicorn/blob/master/uvicorn/logging.py#L102
- Implement gunicorn access log format encode/uvicorn#947 (comment)
is that the access log formatter provided by uvicorn is not as powerful as other ones (like Gunicorn's). For example, in my use case I'd need to log request headers like User Agent to then be able to collect them in logstash and have a nice aggregation in Kibana, but other people may have different use cases. With the default access log formatter we get a limited format to use, meanwhile withasgi-logger
we have way more possibilities available. It is sad that uvicorn didn't really decide what to do yet, but I suppose this is due to ASGI specs (see what's written in the github issue above). Note that if one wants to use and overrideuvicorn.logging.AccessFormatter
they can vialog_config_file
.
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.
The idea of the patch is to have several type of access logs:
- By default, the one provided by the hardcoded config in the
UvicornServer
class, currently broken due to the missinghandlers
key in the python log config (so we don't have any log). - A custom, Uvicorn based config provided via external yaml/json file, to customize the Uvicorn's
AccessFormatter
and the other ones (for example, emitting Json etc..). - A custom,
asgi-logger
based logging format only for stdout (so limited but effective for the k8s use case imho) to get all the configs offered by Gunicorn (see https://docs.gunicorn.org/en/stable/settings.html#access-log-format).
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.
@elukey thanks for the explanation. We also have starlette metrics logging for printing the time spent on the endpoints, do you think we still need it with the uvicorn access logging?
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.
@yuzisun I'd keep it for the moment, so we can figure out with the community what's needed and what not. I didn't check but starlette shouldn't have its own access log right? Everything should go through uvicorn, but the precise relationship between the two is not 100% clear to me (if you want to shed some clarity I'd be very happy). If you want we can create a documentation page somewhere with all the details discussed in here, so folks in the community can refer to it and report use cases etc..
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.
And also third option, custom config file (note the Custom-cfg-file
prefix in the access log formatter):
version: 1
disable_existing_loggers: False
formatters:
default:
(): 'uvicorn.logging.DefaultFormatter'
fmt: '%(asctime)s %(levelprefix)-9s %(name)s -: %(message)s'
access:
(): 'uvicorn.logging.AccessFormatter'
fmt: 'Custom-cfg-file - %(asctime)s %(levelprefix)-9s %(name)s -: %(client_addr)s - "%(request_line)s" %(status_code)s'
handlers:
default:
class: logging.StreamHandler
formatter: default
stream: ext://sys.stderr
access:
class: logging.StreamHandler
formatter: access
stream: ext://sys.stdout
loggers:
uvicorn:
level: INFO
handlers:
- default
uvicorn.error:
level: INFO
uvicorn.access:
level: INFO
propagate: False
handlers:
- access
and logs:
2023-04-25 16:55:54.004 5476 root INFO [__call__():128] requestId: N.A., preprocess_ms: 0.015735626, explain_ms: 0, predict_ms: 0.00667572,
postprocess_ms: 0.003099442
Custom-cfg-file - 2023-04-25 16:55:54,005 INFO: uvicorn.access -: 127.0.0.1:35892 - "POST /v1/models/test%3Apredict HTTP/1.1" 200 OK
2023-04-25 16:55:54.005 5476 root INFO [timing():48] kserve.io.kserve.protocol.rest.v1_endpoints.predict 0.0012352466583251953, ['http_statu
s:200', 'http_method:POST', 'time:wall']
2023-04-25 16:55:54.005 5476 root INFO [timing():48] kserve.io.kserve.protocol.rest.v1_endpoints.predict 0.0012319999999998998, ['http_statu
s:200', 'http_method:POST', 'time:cpu']
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.
Almost! Sigh :(
When using asgi-logger I still see a little duplication:
127.0.0.1:41344 - - [25/Apr/2023:16:46:57 +0000] "POST /v1/models/test:predict HTTP/1.1" 200 - "-" "curl/7.74.0"
2023-04-25 16:46:57.906 5395 access INFO [log():67] 127.0.0.1:41344 - - [25/Apr/2023:16:46:57 +0000] "POST /v1/models/test:predict HTTP/1.1" 200 - "-" "curl/7.74.0"
In theory it shouldn't happen, maybe it is due how to asgi-logger sets the logger + propagation. Will investigate :)
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.
Ok should be fixed now, I added an extra setting for asgi-logger (to avoid propagation).
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.
Asked in Kludex/asgi-logger#6 some guidance about what I have written, maybe there is another/better way.
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.
@yuzisun the change should be ready for a review, I checked and the output looks good now (no more repetitions).
It is useful to be able to change Uvicorn's log settings, for example to be able to change the access log's format. The Uvicorn's Config class provides a "configure_logging" function that is smart about the log_config parameter - if it is a string, and not a dictionary, it is interpreted as a file containing logging directives and that needs to be loaded from disk. This is very convenient for the KServe use case: one can either use the default config, hardcoded in a dictionary, or anything provided as yaml or json file. This change fixes also the default UvicornServer's config. Sadly the current Uvicorn implementation doesn't support changing the access log format, but they suggest to use asgi-logger: encode/uvicorn#947 (comment) It seems the only way forward to allow a decent customization of a vital sign like the access log. The main downside is that asgi-logger requires python3.8+, so to a temporary workaround could be to add the package as extra in poetry's config and import the AccessLoggerMiddleware only if the user sets the access log format. Fixes: kserve#2778 Signed-off-by: Luca Toscano <[email protected]>
@@ -55,6 +55,10 @@ | |||
help="Enable docs url '/docs' to display Swagger UI.") | |||
parser.add_argument("--enable_latency_logging", default=True, type=lambda x: bool(strtobool(x)), | |||
help="Output a log per request with latency metrics.") | |||
parser.add_argument("--log_config_file", default=None, type=str, |
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.
@elukey Do you have an example how to pass this on the inference service yaml? I guess you need to mount this log file as ConfigMap
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.
@yuzisun Yes exactly something similar, it just need a file to be present on the pod, it shouldn't be too difficult. I can try to come up with an example, lemme know if it is needed :)
Looks goods! Thanks @elukey ! /lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: elukey, yuzisun The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
…rve#2782) It is useful to be able to change Uvicorn's log settings, for example to be able to change the access log's format. The Uvicorn's Config class provides a "configure_logging" function that is smart about the log_config parameter - if it is a string, and not a dictionary, it is interpreted as a file containing logging directives and that needs to be loaded from disk. This is very convenient for the KServe use case: one can either use the default config, hardcoded in a dictionary, or anything provided as yaml or json file. This change fixes also the default UvicornServer's config. Sadly the current Uvicorn implementation doesn't support changing the access log format, but they suggest to use asgi-logger: encode/uvicorn#947 (comment) It seems the only way forward to allow a decent customization of a vital sign like the access log. The main downside is that asgi-logger requires python3.8+, so to a temporary workaround could be to add the package as extra in poetry's config and import the AccessLoggerMiddleware only if the user sets the access log format. Fixes: kserve#2778 Signed-off-by: Luca Toscano <[email protected]> Signed-off-by: iamlovingit <[email protected]>
What this PR does / why we need it:
It is useful to be able to change Uvicorn's log settings, for example to be able to change the access log's format.
The Uvicorn's Config class provides a "configure_logging" function that is smart about the log_config parameter - if it is a string, and not a dictionary, it is interpreted as a file containing logging directives and that needs to be loaded from disk. This is very convenient for the KServe use case: one can either use the default config, hardcoded in a dictionary, or anything provided as yaml or json file.
This change fixes also the default UvicornServer's config.
Sadly the current Uvicorn implementation doesn't support
changing the access log format, but they suggest to use
asgi-logger:
encode/uvicorn#947 (comment)
It seems the only way forward to allow a decent customization
of a vital sign like the access log.
The main issue is that
asgi-logger
requires Python 3.8, so the dependency is addedas extra to Poetry's config.
Which issue(s) this PR fixes (optional, in
fixes #<issue number>(, fixes #<issue_number>, ...)
format, will close the issue(s) when PR gets merged):Fixes: #2778
Type of changes
Please delete options that are not relevant.
Feature/Issue validation/testing:
Please describe the tests that you ran to verify your changes and relevent result summary. Provide instructions so it can be reproduced.
Please also list any relevant details for your test configuration.
I tried to use the following snippet:
I saved in
/tmp/test1.yaml
a logging config, and ran the above script. I was able to observe access logs following the configuration that I passed in the file.Moreover, if I run the
ModelServer
class withoutlog_config_file
, I see access logs as expected (as opposed to now that I don't see them, IIUC due to the wrong default config hardcoded in theUvicornServer
's class).I also tried the new
access_log_format
parameter, that works as expected (namely I am able to use something like'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
to customize the access logs:For the moment the support is only for the asgi-logger's default, namely stdout, but we can surely add an option to log to disk or similar (but not sure if KServe users really need it).
Special notes for your reviewer:
Checklist:
No idea if unit tests are needed in this case, lemme know if you fell differently.
Not sure if any are needed.
Release note: