ログメッセージを操作の対象にしたい場合は、ログをインメモリのテキストバッファに出力させます。
このテキストバッファの内容を任意のタイミングで取得し処理し、ファイルに保存します。
保存後はテキストバッファを空にし、次のログ出力に備えます。
以下がログをインメモリのテキストバッファに出力させるためのログ設定の例です。
現在のコンソールへのログ出力はそのままに、新たな出力設定を定義して追加しています(コンソールへは出力させないように変更することも可能)。新たに標準ライブラリの io モジュールが必要になります。
ファイルに保存するログについては、ログレベルやロガー名よりも、トランザクションの実行された日時情報の方が重要ではないかと考え、ログのフォーマットをそのように変更しています。何かログに追加したい情報があれば、フォーマット定義に追加することにより可能です。
コンソールに出力されるログと同じフォーマットがよければ、
IN_MEMORY_STREAM_FORMAT = ('%(levelname)s:%(name)s:%(message)s')
です。
python
1import io
2import logging
3
4logging.basicConfig()
5log = logging.getLogger()
6log.setLevel(logging.DEBUG)
7
8log_stream = io.StringIO()
9in_memory_stream_handler = logging.StreamHandler(stream=log_stream)
10in_memory_stream_handler.setLevel(logging.DEBUG)
11IN_MEMORY_STREAM_FORMAT = ('%(asctime)s %(message)s')
12in_memory_stream_formatter = logging.Formatter(IN_MEMORY_STREAM_FORMAT, datefmt='%Y-%m-%d %H:%M:%S')
13in_memory_stream_handler.setFormatter(in_memory_stream_formatter)
14in_memory_stream_filter = logging.Filter(name='pymodbus.transaction')
15in_memory_stream_handler.addFilter(in_memory_stream_filter)
16log.addHandler(in_memory_stream_handler)
この結果、インメモリのテキストバッファに次のようなログが出力されます。
text
12021-09-03 01:08:12 Current transaction state - IDLE
22021-09-03 01:08:12 Running transaction 1
32021-09-03 01:08:12 SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x1 0x0 0x1 0x0 0x1
42021-09-03 01:08:12 Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
52021-09-03 01:08:12 Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
62021-09-03 01:08:12 RECV: 0x0 0x1 0x0 0x0 0x0 0x4 0x1 0x1 0x1 0x0
72021-09-03 01:08:12 Adding transaction 1
82021-09-03 01:08:12 Getting transaction 1
92021-09-03 01:08:12 Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
102021-09-03 01:08:12 Current transaction state - TRANSACTION_COMPLETE
112021-09-03 01:08:12 Running transaction 2
122021-09-03 01:08:12 SEND: 0x0 0x2 0x0 0x0 0x0 0x6 0x1 0x5 0x0 0x0 0xff 0x0
132021-09-03 01:08:12 Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
142021-09-03 01:08:12 Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
152021-09-03 01:08:12 RECV: 0x0 0x2 0x0 0x0 0x0 0x6 0x1 0x5 0x0 0x0 0xff 0x0
162021-09-03 01:08:12 Adding transaction 2
172021-09-03 01:08:12 Getting transaction 2
182021-09-03 01:08:12 Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
192021-09-03 01:08:12 Current transaction state - TRANSACTION_COMPLETE
202021-09-03 01:08:12 Running transaction 3
212021-09-03 01:08:12 SEND: 0x0 0x3 0x0 0x0 0x0 0x6 0x1 0x1 0x0 0x0 0x0 0x1
222021-09-03 01:08:12 Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
232021-09-03 01:08:12 Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
242021-09-03 01:08:12 RECV: 0x0 0x3 0x0 0x0 0x0 0x4 0x1 0x1 0x1 0x1
252021-09-03 01:08:12 Adding transaction 3
262021-09-03 01:08:12 Getting transaction 3
272021-09-03 01:08:12 Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
282021-09-03 01:08:12 Current transaction state - TRANSACTION_COMPLETE
このログを任意のタイミングで取得し、処理し、ファイルに保存します。
インメモリのテキストバッファにはlog_stream = io.StringIO()で log_stream という名前をつけていますので、log_stream.getvalue()
でその内容をまとめて取得できます。
以下の例では、「SEND:」と「RECV:」が含まれる行のみを抜き出して、各行を「日付」「時刻」「ログメッセージ」に分割しています(この3つを列とするcsvとして保存すると仮定)。
またこの分割を容易にするために、ログ定義にさかのぼって、ログのフォーマットを変更しています(「日付」「時刻」「ログメッセージ」の間に@を挿入)。
python
1(前略)
2IN_MEMORY_STREAM_FORMAT = ('%(asctime)s@%(message)s')
3in_memory_stream_formatter = logging.Formatter(IN_MEMORY_STREAM_FORMAT, datefmt='%Y-%m-%d@%H:%M:%S')
4(中略)
5
6raw_log = log_stream.getvalue()
7pckt_log = [msg for msg in raw_log.split("\n") if "SEND:" in msg or "RECV:" in msg]
8pckt_log_for_csv = []
9for msg in pckt_log:
10 pckt_log_for_csv.append(msg.split("@"))
11print(pckt_log_for_csv)
この出力結果は以下のようになっています。
text
1[['2021-09-03', '09:04:29', 'SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x1 0x0 0x1 0x0 0x1'], ['2021-09-03', '09:04:29', 'RECV: 0x0 0x1 0x0 0x0 0x0 0x4 0x1 0x1 0x1 0x0'], ['2021-09-03', '09:04:29', 'SEND: 0x0 0x2 0x0 0x0 0x0 0x6 0x1 0x5 0x0 0x0 0xff 0x0'], ['2021-09-03', '09:04:29', 'RECV: 0x0 0x2 0x0 0x0 0x0 0x6 0x1 0x5 0x0 0x0 0xff 0x0'], ['2021-09-03', '09:04:29', 'SEND: 0x0 0x3 0x0 0x0 0x0 0x6 0x1 0x1 0x0 0x0 0x0 0x1'], ['2021-09-03', '09:04:29', 'RECV: 0x0 0x3 0x0 0x0 0x0 0x4 0x1 0x1 0x1 0x1']]
ログの保存が終了したら、テキストバッファのサイズを0に切り詰めて空にし、次のログ出力に備えます。これをしないと同じログが何度も保存されてしまいます。もちろん、保存と共にプログラムを終了する場合は、これは不要です。
python
1log_stream.truncate(0)
(なお、質問文中の「所得する」は「取得する」の間違いでしょうか。)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/03 07:19