Below references to questions that have helped me get this far:
- How to print out a dictionary nicely in Python?
- how to indent multiline message printed by python logger?
- Python requests - print entire http request (raw)?
- Log all requests from the python-requests module
I currently have this:
# got from second reference link
class MultiLineFormatter(logging.Formatter):
def get_header_length(self, record):
# Get the header length of a given record
return len(super().format(logging.LogRecord(name=record.name,
level=record.levelno,
pathname=record.pathname,
lineno=record.lineno,
msg='',
args=(),
exc_info=None)))
def format(self, record):
# Format a record with added indentation
indent = ' ' * self.get_header_length(record)
head, *trailing = super().format(record).splitlines(True)
# return
return head + ''.join(indent + line for line in trailing)
def report_logger(log_level: logging.INFO):
# set format for logging style
formatter = MultiLineFormatter(fmt='%(asctime)-8s - %(levelname)-8s - %(name)-30s : %(message)s',
datefmt='%y/%b/%Y %H:%M:%S', )
# create console logger
console = logging.StreamHandler()
console.setLevel(log_level)
# apply formatter to console logger
console.setFormatter(formatter)
# request logger
final_logger = logging.getLogger(__name__)
final_logger.setLevel(log_level)
# prevent double logs in console
final_logger.propagate = False
# add handler
final_logger.addHandler(console)
# return
return final_logger
def print_request(request_data):
format_headers = lambda d: '\n '.join(f'{k}: {v}' for k, v in d.items())
request_body = json.dumps(request_data.req_body, indent=20, sort_keys=True, default=str)
response_text = json.dumps(request_data.resp_text, indent=20, sort_keys=True, default=str)
response_body = json.dumps(request_data.resp_as_dict, indent=20, sort_keys=True, default=str)
msg_print = f'---------------- Request ----------------\n' \
f'Headers : {format_headers(request_data.req_headers)}\n' \
f'URL : {request_data.req_url}\n' \
f'Method : {request_data.req_method}\n' \
f'Body : {request_body}\n' \
f'\n' \
f'---------------- Response ----------------\n' \
f'Headers : {format_headers(request_data.resp_headers)}\n' \
f'Status Code : {request_data.resp_status_code}\n' \
f'Text : {response_text}\n' \
f'Response : {response_body}\n'
logger.info(msg_print)
At the moment, it's pretty much on par for what I'm trying to achieve, however, I'm just trying to get the output of the response bodies a little more "nice".
In the last line above logger.info(msg_print)
I get this output:
22/Feb/2022 16:11:09 - INFO - logger_function : ---------------- Request ----------------
Headers : User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
authorization: AuthToken
URL : my_url
Method : GET
Body : null
---------------- Response ----------------
Headers : content-type: application/json
Content-Length: 119
x-envoy-upstream-service-time: 187
date: today
server: server
Via: 1.1 service
Alt-Svc: alt_service
Status Code : 401
Text : {
"code": 111111,
"component": "ABC",
"errorType": "DEF",
"message": "",
"traceId": UUID4
}
Response : {
"code": 111111,
"component": "ABC",
"errorType": "DEF",
"message": "",
"traceId": UUID4
}
But I'd really like to get those dictionaries to be like this:
22/Feb/2022 16:11:09 - INFO - logger_function : ---------------- Response ----------------
Text : {"code": 111111,
"component": "ABC",
"errorType": "DEF",
"message": "",
"traceId": UUID4}
Response : {"code": 111111,
"component": "ABC",
"errorType": "DEF",
"message": "",
"traceId": UUID4}
Edit:
Sample dict
with nested values:
{
"level1": {
"myInt": "Original",
"level2": {
"myInt": "Original",
"myBool": "Original",
"level3": {
"myBool": "Original"
}
}
},
"level4": [
{
"myList": "Original"
},
{
"myList": "Original"
}
,
{
"myList": "Original"
}
]
}