はじめに
Python でターミナルに出力するログに色を付けて見やすくできる。
↓こんな感じ

補足:
こういったログに色を付ける便利なサードパーティー製ライブラリがいくつも公開されているので、ただ色を付けたいだけならそれらのライブラリを使用することをオススメします。
環境
Python 3.14.0
VSCode 1.106.2
結論
- 「ANSI エスケープコード」を使う
- logging モジュールでカスタムしたログを出力する時は、フォーマット文字列に「ANSI エスケープコード」を含め、アンエスケープ処理を行う
色を付ける方法
「ANSI エスケープコード」 というものを文字列中に含めることで色や書式などを指定できるようです。
ANSI はAmerican National Standards Instituteの略で、この組織はさまざまな標準を制定しています。その中にはコンピュータの文字コードも含まれています。
ANSI エスケープコードは、見るからに乱雑な文字列のように見える制御コードのシーケンスです。これらのシーケンスは、\033[または\x1b[で始まり、その後にさまざまな制御コードが続きます。
例えば:
print("\033[1;31mHello World\033[0m")上記のコードは、赤い太字の「Hello World」を出力します。最後の\033[0mはリセットコードで、後続の出力が赤くならないようにします。
ターミナルが対応している場合のみ文字色などが変わります。
logging モジュールの場合
基本的には print() と同じです。
logger.debug("\033[1;31mHello World\033[0m")
ただ、ログの内容を カスタムする場合 少し対応が必要になります。
カスタムの仕方については以下などを参照してください。
対応内容
- フォーマット文字列に 「ANSI エスケープコード」を追加
- Formatter インスタンスにセットされるフォーマット文字列にアンエスケープ処理を行う
1. フォーマット文字列に 「ANSI エスケープコード」を追加
まず、そのままログの内容をカスタムすると...

と色が変わるのはメッセージ部分のみです。
他のデータ部分も色を変える場合には、フォーマット文字列に 「ANSI エスケープコード」を追加します。
{
"version": 1,
"formatters": {
"debug": {
"()": "logging.Formatter",
"format": "[\\x1b[0;38;5;4m{asctime}\\x1b[0m] \\x1b[0;38;5;4m{levelname:<7s}\\x1b[0m {name:<10s} \\x1b[0;38;5;5m{pathname}\\x1b[0m, line \\x1b[0;38;5;5m{lineno}\\x1b[0m {message}",
"style": "{"
}
},
# 省略
}
↑ "format" の文字列に適宜「ANSI エスケープコード」を追加
json ではエスケープ文字はそのままでは不正な値となってしまうので、エスケープ処理(「\」の前にもう1つ「\」を追加)が必要です。
試しにこの状態でログを出力してみると...

と色は変わりません。
色が変わるようにするには次の 2. の対応が必要です。
2. Formatter インスタンスにセットされるフォーマット文字列にアンエスケープ処理を行う
上のように色が変わらず「ANSI エスケープコード」が文字列として出力されてしまう原因は、 フォーマット文字列がエスケープ処理されているから です。
なので、logging モジュールがログの処理をする前にフォーマット文字列をアンエスケープ処理してあげましょう。
処理の場所は自由ですが、例として Formatter クラスを作成しその初期化時にアンエスケープ処理を行う方法を紹介します。
from logging import Formatter
class CustomFormatter(Formatter):
def __init__(self, fmt = None, datefmt = None, style = "%", validate = True, *, defaults = None):
if fmt is not None:
# フォーマット文字列はエスケープ処理されているので、アンエスケープ処理を行う
fmt = fmt.encode("utf-8").decode("unicode-escape")
super().__init__(fmt, datefmt, style, validate, defaults=defaults)
{
"version": 1,
"formatters": {
"debug": {
"()": "debug.CustomFormatter",
"format": "[\\x1b[0;38;5;4m{asctime}\\x1b[0m] \\x1b[0;38;5;4m{levelname:<7s}\\x1b[0m {name:<10s} \\x1b[0;38;5;5m{pathname}\\x1b[0m, line \\x1b[0;38;5;5m{lineno}\\x1b[0m {message}",
"style": "{"
}
},
# 省略
}
↑ "()" の部分に新しい Formatter クラスを指定
結果:

余談
logging のログのカスタムを最初 json ではなく yaml で定義していたのですが、yaml ではエスケープ処理を行なわず文字列を定義でき 読み込み時にエスケープ処理される という挙動だったので、「あれ、色変わらないな...」としばらく悩みました...
