Logging¶
API calls (including request and response payloads) can be logged by passing log_api_calls=True
when instantiating a service. The following data is logged at the 'INFO'
level
"request_id"
: A unique ID for the request."request_data"
: The request’s JSON payload."response_data"
: The response’s JSON payload."service_class"
: The name of the service class that served the request, e.g.PredictionService
."event"
: The type of event being logged, e.g. “request” or “response”.
By default, the porter
logger sends logs to a null handler. To actually obtain the logs you must add
a handler to the porter
logger and formatter with the desired logging attributes.
For example
from logging import getLogger, Formatter, StreamHandler
logger = getLogger('porter')
logger.setLevel('INFO')
logger.setFormatter(Formatter('%(asctime)-15s %(request_id)s %(event)-8s %(message)s')
logger.addHandler(StreamHandler())
Notice that in the example above the formatter uses default Python log attributes as well as
custom values available from porter
such as “request_id”.
JSON Formatter¶
For convenience porter
includes a log formatter that converts log records to JSON.
This is particularly useful for allowing users to programmatically query logs emitted
from porter
.
The JSON log formatter can be set as follows:
from porter.utils import JSONLogFormatter
logger = getLogger('porter')
formatter = JSONLogFormatter(
'asctime', 'levelname', 'module', 'name', 'message',
'request_id', 'service_class', 'event')
logger.setFormatter(formatter)
which generates logs (pretty printed for this example only) such as:
{
"levelname": "INFO",
"service_class": "PredictionService",
"request_id": "6c26423fe85445948071d01283aaf58e",
"event": "api_call",
"message": "api logging",
"asctime": "2020-04-21 07:02:05,569",
"module": "services",
"name": "porter.services"
}
A full working example can be found in the example script examples/api_logging.py.
User Logging¶
In some cases users may want to add the porter
request_id
to their logs
to associate their application logs with porter
’s default logs. This can
be accomplished with porter.api.request_id()
. Note that this function should
only be called while an active request is being handled.
from porter.api import request_id
# code called while a request is being processed
logger.info('the first message', extra={'request_id': request_id())
logger.info('the second message', extra={'request_id': request_id())
In the example above, if a log formatter
using the format '[request_id %(request_id)] %(msg)s]'
was added to logger
,
the code above would generate the following logs for a single request.
[request_id 6c26423fe85445948071d01283aaf58e] the first message
[request_id 6c26423fe85445948071d01283aaf58e] the second message