在csv文件中记录的正确方法是什么?

use*_*548 10 python csv logging python-3.x

我想记录每个请求的一些信息以格式化的形式发送到繁忙的http服务器,使用日志模块会创建一些我不想要的东西:

[I 131104 15:31:29 Sys:34]
Run Code Online (Sandbox Code Playgroud)

我想到csv格式,但我不知道如何自定义它,而python有csv模块,但阅读手册

import csv
with open('some.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerows(someiterable)
Run Code Online (Sandbox Code Playgroud)

因为它每次都会打开和关闭一个文件,我担心这样会降低整个服务器的性能,我该怎么办?

slo*_*oth 10

只需使用python的logging模块.

您可以按照自己的方式调整输出; 看一下更改显示消息的格式:

要更改用于显示消息的格式,您需要指定要使用的格式:

import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
Run Code Online (Sandbox Code Playgroud)

格式化程序:

Formatter对象配置日志消息的最终顺序,结构和内容.

您可以在此处找到可以使用的attribtus列表:LogRecord属性.


如果要生成有效的csv文件,也可以使用python的csv模块.

这是一个简单的例子:

import logging
import csv
import io

class CsvFormatter(logging.Formatter):
    def __init__(self):
        super().__init__()
        self.output = io.StringIO()
        self.writer = csv.writer(self.output, quoting=csv.QUOTE_ALL)

    def format(self, record):
        self.writer.writerow([record.levelname, record.msg])
        data = self.output.getvalue()
        self.output.truncate(0)
        self.output.seek(0)
        return data.strip()

logging.basicConfig(level=logging.DEBUG)

logger = logging.getLogger(__name__)
logging.root.handlers[0].setFormatter(CsvFormatter())

logger.debug('This message should appear on the console')
logger.info('So should "this", and it\'s using quoting...')
logger.warning('And this, too')
Run Code Online (Sandbox Code Playgroud)

输出:

"DEBUG","此消息应出现在控制台上"
"INFO","所以应该""这个"",它正在使用引用......"
"警告","这也是"


eco*_*coe 7

正如 sloth 所建议的,您可以轻松地将日志分隔符编辑为逗号,从而生成 CSV 文件。

工作示例:

import logging

# create logger
lgr = logging.getLogger('logger name')
lgr.setLevel(logging.DEBUG) # log all escalated at and above DEBUG
# add a file handler
fh = logging.FileHandler('path_of_your_log.csv')
fh.setLevel(logging.DEBUG) # ensure all messages are logged to file

# create a formatter and set the formatter for the handler.
frmt = logging.Formatter('%(asctime)s,%(name)s,%(levelname)s,%(message)s')
fh.setFormatter(frmt)

# add the Handler to the logger
lgr.addHandler(fh)

# You can now start issuing logging statements in your code
lgr.debug('a debug message')
lgr.info('an info message')
lgr.warn('A Checkout this warning.')
lgr.error('An error writen here.')
lgr.critical('Something very critical happened.')
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案不够稳健——当‘asctime’中输出逗号时会发生什么?如果消息本身包含逗号或换行符怎么办?然后 CSV 文件就会损坏。任何写入 CSV 数据的操作都应该通过“csv.writer”实例进行,如其他一些答案所示。 (4认同)
  • 有没有办法添加 CSV 标题行?(即 CSV 文本文件中的第一行包含列名称?) (3认同)

Wil*_*ill 6

我同意您应该使用日志记录模块,但是您不能像其他一些答案所示那样仅使用格式字符串来正确地完成此操作,因为它们没有解决您记录包含逗号的消息的情况。

如果您需要一个能够正确转义消息(或其他字段,我想)中的任何特殊字符的解决方案,您将必须编写一个自定义格式化程序并设置它。

logger = logging.getLogger()

formatter = MyCsvFormatter()

handler = logging.FileHandler(filename, "w")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(level)
Run Code Online (Sandbox Code Playgroud)

显然,您必须实现 MyCsvFormatter 类,该类应该继承自logging.Formatter并重写format()方法

class MyCsvFormatter(logging.Formatter):
    def __init__(self):
        fmt = "%(levelname)s,%(message)s" # Set a format that uses commas, like the other answers
        super(MyCsvFormatter, self).__init__(fmt=fmt)

    def format(self, record):
        msg = record.getMessage()
        # convert msg to a csv compatible string using your method of choice
        record.msg = msg
        return super(MyCsvFormatter, self).format(self, record)
Run Code Online (Sandbox Code Playgroud)

注意:我以前做过类似的事情,但还没有测试过这个特定的代码示例

至于实际转义消息,这是一种可能的方法: Python - 将数据作为字符串(而不是文件)写入 csv 格式