使用python作为JSON行记录

使用python作为JSON行记录,python,python-3.x,logging,Python,Python 3.x,Logging,我开发了一个函数,可以使用python将日志文件创建为JSON行文件: import logging import sys from datetime import datetime def log_start(log_prefix): now = datetime.now() log_id = str(now).replace(':', '').replace(' ', '').replace('.', '').replace('-', '')[:14] log_n

我开发了一个函数,可以使用python将日志文件创建为JSON行文件:

import logging
import sys
from datetime import datetime


def log_start(log_prefix):
    now = datetime.now()
    log_id = str(now).replace(':', '').replace(' ', '').replace('.', '').replace('-', '')[:14]
    log_name = '/mnt/jarvis/logs/{}_{}.txt'.format(log_prefix, log_id)

    root = logging.getLogger()
    if root.handlers:
        root.handlers = []

    logging.basicConfig(level=logging.INFO, filename=log_name, filemode='a+',
                        format='''{{"log_id":"{}", "created_date":"%(asctime)s.%(msecs)03d", "action_text":"%(message)s"}}'''.format(
                            log_id),
                        datefmt="%Y-%m-%dT%H:%M:%S")
    root = logging.getLogger()
    root.setLevel(logging.INFO)

    handler = logging.StreamHandler(sys.stdout)
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter(
        '''{{"log_id":"{}", "created_date":"%(asctime)s.%(msecs)03d", "action_text":"%(message)s"}}'''.format(
            log_id),
        datefmt="%Y-%m-%dT%H:%M:%S")
    handler.setFormatter(formatter)
    root.addHandler(handler)

    return log_name, log_id
而且效果很好。但是,如果日志消息中有新行字符或双引号之类的内容,我就会遇到问题,因为它不再是有效的JSON。有没有一种方法可以使
%(message)
成为一个“有效的JSON字符串”,而无需我每次都对其进行更正

编辑

此问题的一个示例是,我希望在日志中看到回溯,因此这样的回溯会由于引号和\n字符而导致问题:

Traceback (most recent call last):
  File "/var/task/lego/bricks/tableau/workbook.py", line 65, in refresh_extracts
    output = subprocess.check_output(command, shell=True)
  File "/var/lang/lib/python3.6/subprocess.py", line 356, in check_output
    **kwargs).stdout
  File "/var/lang/lib/python3.6/subprocess.py", line 438, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '***REDACTED***' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/var/task/jarvis/event_triggered/refresh_dashboard.py", line 21, in refresh_dashboard
    workbook.refresh_extracts()
  File "/var/task/lego/bricks/tableau/workbook.py", line 73, in refresh_extracts
    traceback.format_exc()))
  File "/var/task/lego/power_functions/error_handling/graceful_fail.py", line 16, in graceful_fail
    raise RuntimeError('This is a graceful fail, notifications sent based on attributes.')
RuntimeError: This is a graceful fail, notifications sent based on attributes.

您可以根据需要在JSON中有条件地测试和格式化字符串。在这里,我检查在本例中经常抛出的特定的
JSONDecodeError
,但是您可以捕获任何类型的异常,或者许多异常。考虑使用这样的检查来构建消息字符串:

import json

bad_json = '''
Traceback (most recent call last):
  File "/var/task/lego/bricks/tableau/workbook.py", line 65, in refresh_extracts
    output = subprocess.check_output(command, shell=True)
  File "/var/lang/lib/python3.6/subprocess.py", line 356, in check_output
    **kwargs).stdout
  File "/var/lang/lib/python3.6/subprocess.py", line 438, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '***REDACTED***' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/var/task/jarvis/event_triggered/refresh_dashboard.py", line 21, in refresh_dashboard
    workbook.refresh_extracts()
  File "/var/task/lego/bricks/tableau/workbook.py", line 73, in refresh_extracts
    traceback.format_exc()))
  File "/var/task/lego/power_functions/error_handling/graceful_fail.py", line 16, in graceful_fail
    raise RuntimeError('This is a graceful fail, notifications sent based on attributes.')
RuntimeError: This is a graceful fail, notifications sent based on attributes.
'''
try:
    test_message = json.loads(bad_json) # this fails in the above case
except json.decoder.JSONDecodeError:
    good_json = json.dumps({"message": bad_json})
    test_message = json.loads(good_json)

print(test_message)
结果(如果愿意,可以使用
json.dumps(您的消息\u字符串)
将其转储到更可读的文本中):


这可能是通过日志格式化程序传递的函数、lambda等。

您可以根据需要有条件地在JSON中测试和格式化字符串。在这里,我检查在本例中经常抛出的特定的
JSONDecodeError
,但是您可以捕获任何类型的异常,或者许多异常。考虑使用这样的检查来构建消息字符串:

import json

bad_json = '''
Traceback (most recent call last):
  File "/var/task/lego/bricks/tableau/workbook.py", line 65, in refresh_extracts
    output = subprocess.check_output(command, shell=True)
  File "/var/lang/lib/python3.6/subprocess.py", line 356, in check_output
    **kwargs).stdout
  File "/var/lang/lib/python3.6/subprocess.py", line 438, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '***REDACTED***' returned non-zero exit status 1.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/var/task/jarvis/event_triggered/refresh_dashboard.py", line 21, in refresh_dashboard
    workbook.refresh_extracts()
  File "/var/task/lego/bricks/tableau/workbook.py", line 73, in refresh_extracts
    traceback.format_exc()))
  File "/var/task/lego/power_functions/error_handling/graceful_fail.py", line 16, in graceful_fail
    raise RuntimeError('This is a graceful fail, notifications sent based on attributes.')
RuntimeError: This is a graceful fail, notifications sent based on attributes.
'''
try:
    test_message = json.loads(bad_json) # this fails in the above case
except json.decoder.JSONDecodeError:
    good_json = json.dumps({"message": bad_json})
    test_message = json.loads(good_json)

print(test_message)
结果(如果愿意,可以使用
json.dumps(您的消息\u字符串)
将其转储到更可读的文本中):


这可能是通过日志格式化程序传递的函数、lambda等。

我可以看到一个包含您描述的换行符/引号的无效JSON示例吗?我很好奇特定字符串发生了什么。@JacobIRR请看我的编辑,好的观点,应该在开始时添加它。我可以看到一个包含如您所描述的换行符/引号的无效JSON示例吗?我很好奇特定字符串发生了什么。@JacobIRR请看我的编辑,好的观点,应该在开始时添加这一点。我考虑过这样做(不过你的更好),虽然这样做会起作用,但我如何将其传递给
日志记录.Formatter
?这就是让我迷路的原因每当你打电话给你的记录者,你都会把你想要记录的信息传递给它。因此,无论代码位于何处,添加上述检查/转换以修改消息字符串,然后再将其转换为内部格式代码。你有没有代码来告诉我们你是如何调用日志函数的?那么你可以这样做:logging.info(correct_text('my_message'))?是的,没错。让纠错函数在潜在的坏字符串进入日志函数之前运行。我考虑过这样做(你的更好),虽然它可以工作,但如何将其传递给
日志记录.Formatter
?这就是让我迷路的原因每当你打电话给你的记录者,你都会把你想要记录的信息传递给它。因此,无论代码位于何处,添加上述检查/转换以修改消息字符串,然后再将其转换为内部格式代码。你有没有代码来告诉我们你是如何调用日志函数的?那么你可以这样做:logging.info(correct_text('my_message'))?是的,没错。让纠错函数在潜在错误字符串进入日志函数之前运行。