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

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

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

Unicodeはエンコーディングの標準規格です。1つの文字コード体系で多国語の表現を可能にすることを目指して作られています。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

例外

例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。

Python

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

Q&A

解決済

2回答

4086閲覧

Python3 loggingで発生した--- Logging error --- の例外キャッチ方法

tomy-c

総合スコア179

Unicode

Unicodeはエンコーディングの標準規格です。1つの文字コード体系で多国語の表現を可能にすることを目指して作られています。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

例外

例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。

Python

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

0グッド

1クリップ

投稿2019/11/19 04:44

前提・実現したいこと

現在様々な国の言葉を取得し、扱う機能を実装しているのですが、
その過程でPythonのlogging機能に出力した際、以下のエラーメッセージが
[コンソール]にのみ出てきており、例外にキャッチできず、logが出力できない問題が発生しております。

発生している問題・エラーメッセージ

--- Logging error --- Traceback (most recent call last): File "C:\Program Files\Python37\lib\logging\__init__.py", line 1028, in emit stream.write(msg + self.terminator) UnicodeEncodeError: 'cp932' codec can't encode character '\xa0' in position 35: illegal multibyte sequence ~(略) Message: '\xa0$ {ミ侑シム殉'

ログに出そうとしている文字列がUnicodeに変換できないと出ているため、
loggingでその例外を取得し、exceptで別の処理を行いたいのに、例外処理に飛びません。

該当のソースコード

※オリジナルのソースを上げられないため、再現するソースを作成しました。

python3

1import logging 2import os 3import sys 4import datetime 5 6 7 8# ログに時間を表記するためのフォーマット 9fmt = "%(asctime)s %(levelname)s %(name)s :%(message)s" 10# ログ設定 11logging.basicConfig(filename = 'C:\Users\****\Desktop\新しいフォルダー\log-'+ 12 datetime.datetime.today().strftime("%Y-%m-%d") + 13 '.log',level = logging.DEBUG, format=fmt) 14 15# ※文字列の頭に[ノンブレークスペース]が含まれている 16a = ' $ {Имя}' 17logging.info("--------------------------------------") 18try: 19 #コンソールにのみエラーが出てそのまま例外に飛ばない 20 logging.info(a) 21except UnicodeEncodeError as ex: 22 #拾わねぇ・・・ 23 print(ex) 24 logging.critical(ex) 25 logging.info(a.encode('cp932', "ignore")) 26

試したこと

Exceptionでキャッチを試みてみましたが、変わりませんでした。
また、ノンブレークスペース以外にUnicodeに変換できない文字列も含まれる可能性があるため、
一つのデータだけに対応する様な修正方法は使えません。
(最初はノンブレークスペースだけ置換する処理を検討していました。)
また、

python3

1a.encode('cp932', "ignore")

で、エンコードする方法も検討したのですが、うん十万件あるデータの全てをエンコードはしたくなく、
Unicodeに変換できない文字列に対してのみエンコードをしたいため、例外を取得できないとだめでした。

エンコードをかけた場合のログ出力

b'$ {\x84I\x84}\x84\x91}'

エンコードをかけずノンブレークスペースのみ削除した出力

${Имя}

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

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

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

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

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

guest

回答2

0

--- Logging error --- をキーにして調べれば見つかるんじゃないかな、と思って調べてみました。コードは logging/__init__.py#L999-L1014 にありました。

結論としては、logging内で発生した例外を拾うには、HandlerのhandleErrorメソッドをオーバーライドします。
Python 用ロギング機能 — Python 3.8.6rc1 ドキュメント の handleError の説明

渡されたデータ(record)をHandlerの対象(コンソールとかファイルとか)に保存する形式にシリアライズできない場合、このメソッドでエラーを処理する実装になっています。(出力先によってはエンコーディング形式に関係なく保存できるかもしれないし、特定の出力先でだけUnicodeEncodeErrorになるかもしれないので、Handler毎に調整できるようになっているのは妥当そうです)。

Handler.handlerError で、発生したUnicodeEncodeErrorを強制的にログ出力可能にするには、この handleError メソッドで例外を捕まえて、例外が起きないようにrecordに処理を加えてから self.emit(record) を呼び直せば期待する動作が実現できそうです。

以下の様なコードで(試してませんが)うまくいくかと思います。

def handleError(self, record): t, v, tb = sys.exc_info() if isinstance(t, UnicodeEncodeError): # fallback処理としてrecordを修正する self.emit(record) else: super().handleError(record)

投稿2020/09/19 22:07

shimizukawa

総合スコア1847

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

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

0

自己解決

本来の問題である
logging内で例外が発生した場合どうやってexcept(他言語でいうcatch)をするか
に対する問題の解決策ではありませんが、
以下の方法で例外そのものを起こさないようにすることで応急処置的な対応を行いました。
ログの出力をUTF-8で出力するように明記

python

1import logging 2import os 3import sys 4import datetime 5 6 7 8# ログに時間を表記するためのフォーマット 9fmt = "%(asctime)s %(levelname)s %(name)s :%(message)s" 10fname = 'ファイルパス'+ datetime.datetime.today().strftime("%Y-%m-%d") + 'ログファイル名.log' 11 12logger = logging.getLogger(__name__) 13logger.setLevel(logging.DEBUG) 14handler = logging.FileHandler(filename=fname, encoding='utf-8') 15handler.setFormatter(logging.Formatter(fmt)) 16 17logger.addHandler(handler) 18a = ' $ {Имя}' 19logger.info("--------------------------------------") 20try: 21 logger.debug("debug あいうえお") 22 logger.info(a) 23except UnicodeEncodeError as ex: 24 # そもそもこの例外を起こさないように対応 25 # 拾わねぇ・・・ 26 print(ex) 27 logger.critical(ex)

結局の所logging内で例外が発生した場合、拾う手段が存在しないように感じます。(証明できる資料を探したのですが、探し方が悪いのか見つかりませんでした・・・)

投稿2019/12/09 02:10

tomy-c

総合スコア179

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問