ビジーなhttpサーバーに送信されたすべてのリクエストの情報をフォーマットされた形式でログに記録したいのですが、ログモジュールを使用すると、作成したくないものが作成されます。
[I 131104 15:31:29 Sys:34]
私はcsv形式を考えていますが、それをカスタマイズする方法がわかりません。python csvモジュールを取得しましたが、マニュアルを読んでください。
import csv
with open('some.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerows(someiterable)
毎回ファイルを開いたり閉じたりするので、この方法でサーバー全体のパフォーマンスが低下するのではないかと心配しています。どうすればよいですか?
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')
および フォーマッター :
フォーマッタオブジェクトは、ログメッセージの最終的な順序、構造、および内容を構成します。
使用できる属性のリストはここにあります: LogRecord属性 。
有効なcsvファイルを作成する場合は、Pythonの csv
module も使用してください。
簡単な例を次に示します。
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')
出力:
"DEBUG"、 "このメッセージはコンソールに表示されます"
"INFO"、 "" "this" "である必要があり、引用符を使用しています..."
「警告」、「そしてこれも」
ナマケモノが示唆しているように、ログの区切り文字をカンマに簡単に編集して、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.')
ロギングモジュールを使用する必要があることに同意しますが、他のいくつかの回答が示すようなフォーマット文字列だけでは、カンマを含むメッセージをログに記録する状況に対応していないため、実際には正しく実行できません。
メッセージ内の特殊文字(または他のフィールド)を適切にエスケープするソリューションが必要な場合は、カスタムフォーマッターを作成して設定する必要があります。
logger = logging.getLogger()
formatter = MyCsvFormatter()
handler = logging.FileHandler(filename, "w")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(level)
明らかに、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)
注:私は以前にこのようなことをしましたが、この特定のコードサンプルをテストしていません
メッセージの実際のエスケープを行う限り、1つの可能なアプローチがあります: Python-データを文字列(ファイルではなく)としてcsv形式で書き込みます
それが最善のアイデアではないと思いますが、実行可能で、非常に単純です。ログを手動でバッファリングします。ログエントリをどこかに保存し、時々ファイルに書き込みます。サーバーが常にビジー状態になることがわかっている場合は、あるサイズに達したときにバッファーをフラッシュします。使用法に大きなギャップがある可能性がある場合は、スリープ/フラッシュの無限の(理論的にはもちろん)ループを伴う新しいスレッド(またはより良いプロセス、スレッドがアプリを吸って遅くする理由を自分で確認してください)を呼び出す方が良いと思います。また、サーバーが中断または失敗したときにバッファーをフラッシュする何らかのフックを作成することを忘れないでください(おそらくシグナルですか?またはメイン関数を試して/除外します-それを行う方法はさらにあります)、フラッシュされていないバッファーを失うことはありません予期しない終了に関するデータ。
繰り返しますが、これは最善のアイデアではありません。最初に頭に浮かんだのはそれです。 Flaskまたは他のWebアプリケーションフレームワーク(AFAIR FlaskにもCSVロギングがあります))からロギングの実装を参照することをお勧めします。