'Python - Log dictionary to console with correct indentation
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"
}
]
}
Solution 1:[1]
Though it seems a bit fragile, it looks like you can slightly adjust the indentation then use the re package to strip out the unwanted spacing between the leading and closing curly braces.
import json
import re
req_body = {"code": 111111, "component": "ABC", "errorType": "DEF", "message": "", "traceId": "UUID4"}
resp_text = {"code": 111111, "component": "ABC", "errorType": "DEF", "message": "", "traceId": "UUID4"}
request_body = json.dumps(req_body, indent=20, sort_keys=True, default=str)
response_text = json.dumps(resp_text, indent=17, sort_keys=True, default=str)
response_text = re.sub(r"^{\s*", "{", response_text)
response_text = re.sub(r"\s*}$", "}", response_text)
msg_print = f'---------------- Response ----------------\n' \
f'Request : {request_body}\n' \
f'Response : {response_text}\n'
print(msg_print)
That looks like it might give you what you are after:
---------------- Response ----------------
Request : {
"code": 111111,
"component": "ABC",
"errorType": "DEF",
"message": "",
"traceId": "UUID4"
}
Response : {"code": 111111,
"component": "ABC",
"errorType": "DEF",
"message": "",
"traceId": "UUID4"}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
