質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1417閲覧

pythonでLOG情報を所得する方法を教えてください

NKJSM

総合スコア58

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/09/02 04:14

編集2021/09/03 07:18

前提・実現したいこと

現在pymodbusのパッケージを使ってMODBUS通信を試みているのですが、通信メッセージの履歴をCSVに残したいためlogのデバッグメッセージの中でも
DEBUG:pymodbus.transaction:SEND: 0x1 0x6 0x0 0x7d 0x0 0x38 0x18 0x0

DEBUG:pymodbus.transaction:RECV: 0x1 0x6 0x0 0x7d 0x0 0x38 0x18 0x0
の情報を文字列として所得したいと考えています。何を使い、どのように宣言すれば取得できるのでしょうか?

一応ですが、現在
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
で宣言して
client.write_register
で書き込みをした時に出力されるものが以下となります
DEBUG:pymodbus.transaction:Current transaction state - IDLE
DEBUG:pymodbus.transaction:Running transaction 1
DEBUG:pymodbus.transaction:SEND: 0x1 0x6 0x0 0x7d 0x0 0x38 0x18 0x0
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x1 0x6 0x0 0x7d 0x0 0x38 0x18 0x0
DEBUG:pymodbus.framer.rtu_framer:Getting Frame - 0x6 0x0 0x7d 0x0 0x38
DEBUG:pymodbus.factory:Factory Response[WriteSingleRegisterResponse: 6]
DEBUG:pymodbus.framer.rtu_framer:Frame advanced, resetting header!!
DEBUG:pymodbus.transaction:Adding transaction 1
DEBUG:pymodbus.transaction:Getting transaction 1
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ログメッセージを操作の対象にしたい場合は、ログをインメモリのテキストバッファに出力させます。
このテキストバッファの内容を任意のタイミングで取得し処理し、ファイルに保存します。
保存後はテキストバッファを空にし、次のログ出力に備えます。

以下がログをインメモリのテキストバッファに出力させるためのログ設定の例です。
現在のコンソールへのログ出力はそのままに、新たな出力設定を定義して追加しています(コンソールへは出力させないように変更することも可能)。新たに標準ライブラリの 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 01:22

etherbeg

総合スコア1195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

NKJSM

2021/09/03 07:19

わかりやすい説明のうえ、実装例も提示していただき本当にありがとうございました。 (所得は誤字でございます)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問