Python 如何在较长的非json文本中检测和缩进json子字符串?
我有一个现有的Python应用程序,其日志如下:Python 如何在较长的非json文本中检测和缩进json子字符串?,python,json,indentation,pretty-print,Python,Json,Indentation,Pretty Print,我有一个现有的Python应用程序,其日志如下: import logging import json logger = logging.getLogger() some_var = 'abc' data = { 1: 2, 'blah': { ['hello'] } } logger.info(f"The value of some_var is {some_var} and data is {json.dumps(data)}") 因此给出了logger.
import logging
import json
logger = logging.getLogger()
some_var = 'abc'
data = {
1: 2,
'blah': {
['hello']
}
}
logger.info(f"The value of some_var is {some_var} and data is {json.dumps(data)}")
因此给出了logger.info
函数:
The value of some_var is abc and data is {1: 2,"blah": {["hello"]}}
目前,我的日志转到AWS CloudWatch,它有一些魔力,并以缩进的方式呈现如下:
The value of some_var is abc and data is {
1: 2,
"blah": {
["hello"]
}
}
这使得日志非常清晰易读
现在,我想对我的日志进行一些更改,用另一个python脚本自己处理它,该脚本围绕我的代码,并在出现故障时通过电子邮件发送日志
我想要的是以某种方式获取每个日志条目(或条目流/列表),并应用此缩进
所以我想要一个函数,它接收一个字符串,并检测该字符串的哪些子集是json,然后插入\n
和
以漂亮地打印该json
输入示例:
您好,{“a”:{“b”:“c”}是一些json数据,但{“c”:[1,2,3]}也是
示例输出
Hello,
{
"a": {
"b": "c"
}
}
is some json data, but also
{
"c": [
1,
2,
3
]
}
is too
我已经考虑过将每个条目分成第一个{
前后的所有内容。左半部分保持原样,右半部分传递给json.dumps(json.loads(x),indent=4)
但是如果日志文件中json对象后面有东西呢?
好的,我们可以选择第一个{
之后和最后一个}
之前的所有内容。
然后将中间的位传递给JSON库
但是,如果此日志条目中有两个JSON对象(如上面的示例中),我们将必须使用堆栈来确定在所有先前的{
都用相应的}
关闭之后是否会出现任何{
但是如果有类似于{“a”:“\}”}
.Hmm的东西,我们需要处理转义。
现在我发现自己必须从头开始编写一个完整的json解析器
有什么简单的方法可以做到这一点吗
我想我可以使用正则表达式将整个repo中的json.dumps(x)
的每个实例替换为json.dumps(x,indent=4)
。但是json.dumps
有时在日志语句之外使用,它只会使我所有的日志行都额外长一点。有一个简洁优雅的解决方案吗
(如果它能够解析和缩进python中
str(x)
生成的类似json的输出,则会获得额外的积分。这基本上是带有单引号而不是双引号的json。)要从字符串中提取json对象,请参阅该答案中的函数将处理JSON对象和嵌套的JSON对象,但不处理其他对象。如果您的日志中有JSON对象之外的列表,则不会获取该列表
在您的情况下,修改函数以同时返回所有JSON对象周围的字符串/文本,以便您可以将它们一起放入日志(或替换日志行):
使用该函数处理日志行,将它们添加到字符串列表中,然后将这些字符串组合在一起,为输出、记录器等生成单个字符串:
def jsonify_logline(line):
line_parts = []
for result in extract_json_objects(line):
if isinstance(result, dict): # got a JSON obj
line_parts.append(json.dumps(result, indent=4))
else: # got text/non-JSON-obj
line_parts.append(result)
# (don't make that a list comprehension, quite un-readable)
return ''.join(line_parts)
例如:
>>> demo_text = """Hello, {"a": {"b": "c"}} is some json data, but also {"c": [1,2,3]} is too"""
>>> print(jsonify_logline(demo_text))
Hello, {
"a": {
"b": "c"
}
} is some json data, but also {
"c": [
1,
2,
3
]
} is too
>>>
其他与本会有所帮助的非直接相关事项:
- 不要对所有日志行使用
,而是按照创建一个类似json.dumps(x)
的函数,该函数可以执行您想要执行的任何操作,如logdump(x)
,或json.dumps(x)
,或json.dumps(x,indent=4)
。这样,如果需要更改所有日志的JSON格式,只需更改一个函数即可;无需大量“搜索和替换”,这会带来自身的问题和边缘情况。jsonify\u日志行(x)
- 您甚至可以向它添加一个可选参数
,以决定是否要缩进pretty=True
- 您甚至可以向它添加一个可选参数
- 您可以批量搜索并替换所有现有的日志行来执行
logger.blah(jsonify_logline())
- 如果您是JSON转储自定义对象/类实例,那么请使用它们的方法始终输出打印精美的JSON,并且输出的是非精美/紧凑的。
- 然后您就不需要修改日志行了。执行
将直接调用logger.info(f'hereismyobject{x}')
obj.\uuu str\uuu
- 然后您就不需要修改日志行了。执行
logdump
函数会很好。特别是我有一个函数,有时我想将包含日期时间的dict转储到json(这会导致json.dumps
崩溃)jsonify_logline
是您的新logdump
。它不应该为datetimes提供错误,因为它不是dict/json对象。但也可以将其包装在try else块中。更新:修复了一个错误,即最后一个json对象之后的尾随文本不会返回。
>>> demo_text = """Hello, {"a": {"b": "c"}} is some json data, but also {"c": [1,2,3]} is too"""
>>> print(jsonify_logline(demo_text))
Hello, {
"a": {
"b": "c"
}
} is some json data, but also {
"c": [
1,
2,
3
]
} is too
>>>