Pythonの基礎知識(基礎編)

【Pythonの基礎知識】ログを記録して仕組みの信頼性を高める

システムが安定して動くためには、単にプログラムが動作するだけでは不十分です。

重要なのは「何が、いつ、どのように動いたのか」を後から追える状態にしておくことです。

これを実現するのがログの仕組みです。ログはエラーの原因を特定したり、予期せぬ動作の兆候を早期に発見するための“証拠”です。

小規模なスクリプトでも、記録を残すことで再現性と信頼性が飛躍的に向上します。

この記事では、Pythonの標準モジュール「logging」を用いて、開発・運用の両面から仕組みを支えるログ設計の基本を整理します。

Pythonの基礎知識(基礎編)


🟣 Pythonの基礎知識(基礎編)
📌基本文法から実用テクニックまで、Pythonの土台を固めるステップアップ講座
└─ 【Pythonの基礎知識(基礎編)】仕組みから学ぶ思考と自動化のプログラミング講座
  ├─ STEP 0:Pythonを動かす“仕組み”を理解する
  | ├─【Pythonの基礎知識】Pythonを動かす環境とは何か? “自分専用の環境”を作る
  | ├─【Pythonの基礎知識】Hello Worldの裏側にある実行の仕組み
  | └─【Pythonの基礎知識】Pythonのファイル構造と実行パスを理解する
  |
  ├─STEP 1:Pythonで“考える仕組み”を作る(思考編)
  | ├─【Pythonの基礎知識】データ型で世界を定義する|数・文字・真偽の正体
  | ├─【Pythonの基礎知識】変数と値の動きを通して仕組みを理解しよう
  | ├─【Pythonの基礎知識】条件分岐で“判断を任せる”仕組みを作る
  | ├─【Pythonの基礎知識】for文で“人の手”を離す仕組みを作る
  | └─【Pythonの基礎知識】while文で“継続する仕組み”を作る
  |
  ├─STEP 2:Pythonで“情報を扱う仕組み”を作る(構造編)
  | ├─【Pythonの基礎知識】コレクション型の正しい選び方(list, tuple, dict, set)
  | ├─【Pythonの基礎知識】リストで情報を整理し、仕組みに流れを持たせる
  | ├─【Pythonの基礎知識】辞書型でデータを“意味”で管理する
  | └─【Pythonの基礎知識】集合型で重複を排除し、無駄をなくす仕組みを作る
  |
  ├─STEP 3:Pythonで“動きを再利用する仕組み”を作る(関数・モジュール編)
  | ├─【Pythonの基礎知識】関数で処理を再利用する|“人間の手順”を仕組みに変える
  | ├─【Pythonの基礎知識】引数と戻り値で“情報のやりとり”を自動化する
  | ├─【Pythonの基礎知識】モジュールとパッケージで“仕組みを部品化”する
  | └─【Pythonの基礎知識】importの裏側を理解し、コードを分離する設計思考
  |
  ├─STEP 4:Pythonで“データを扱う仕組み”を作る(入出力・永続化編)
  | ├─【Pythonの基礎知識】ファイル操作でデータを読み書きする仕組みを作る
  | ├─【Pythonの基礎知識】CSVを自在に扱う仕組みを作る
  | ├─【Pythonの基礎知識】JSONで構造化データを操る
  | └─【Pythonの基礎知識】例外処理で“壊れない仕組み”を設計する
  |
  └─STEP 5:Pythonで“自動化する仕組み”を作る(応用実践編)
    ├─【Pythonの基礎知識】スクリプトを自動実行させる仕組みを作る
    ├─【Pythonの基礎知識】日次タスクを自動化して人の時間を解放する
    ├─【Pythonの基礎知識】外部APIを活用して作業を外部化する
    └─【Pythonの基礎知識】ログを記録して仕組みの信頼性を高める

ログを記録しないと起こる信頼性の問題

運用中のPythonスクリプトが突然動かなくなったとき、原因を特定できないまま時間だけが過ぎていく。

そんな経験をしたことはありませんか。

ログを記録していないと、まるで真っ暗な部屋で探し物をしているようなものです。

プログラムが「何をして」「どこで止まったか」がわからなければ、再現も修正もできません。

信頼性とは、ただ動くことではなく、問題が起きたときに“正確に振り返れること”です。

ログはそのための記録装置であり、開発の保険とも言えます。

動かなくなったスクリプトを復旧するのに3時間もかかった…

原因が見えなかったんです。

それはログがなかったからです。記録があれば、どこで異常が発生したか一目でわかります。

ログなし運用の実際の障害経験

ある小規模な自動バックアップスクリプトで、ファイルが保存されなくなる障害が発生しました。

しかし、ログを出力していなかったため、原因が特定できず再現テストを何度も繰り返す羽目になりました。

結局、ファイルパスの一部に特殊文字が含まれていたことが原因でしたが、もしその時点でログを出力していれば、1行の記録で即座に問題箇所がわかっていたのです。

たった1行のprintを追加しておけば防げたかもしれませんね。
ええ。ですがprintでは限界があります。正式なログ機構を導入して、後から参照できる形にしておくことが重要です。

特にファイル操作を行う処理では、shutil(後述)のようなモジュールでコピーや移動を自動化しつつ、その実行結果をloggingで記録しておくと、トラブル時にも原因をすぐに追跡できる堅牢な仕組みになります。

# ログを残さずに実行した例
import shutil
src = '/backup/source/file.txt'
dst = '/backup/target/file.txt'
shutil.copy(src, dst)

このコードは正常に動作しているように見えますが、もしファイルが存在しない場合、例外が発生しても原因は出力されません。

どの行で止まったのか、何が失敗したのかを後から調べる手段がないのです。

【出力例:】

FileNotFoundError: [Errno 2] No such file or directory: '/backup/source/file.txt'

ログがあれば、同じエラーがいつ・どの環境で起きたのかも記録され、運用担当が即座に行動できます。

shutilモジュールとは

shutil(シュータイル)は、Python標準ライブラリの中でもファイルやディレクトリ操作を「高レベル」で扱うためのモジュールです。

osモジュールが提供する基本的な処理(パス取得・削除・属性変更など)をさらに使いやすく拡張したもので、バックアップやログ保存、テンポラリ作業などに役立ちます。

特に、コピー・移動・圧縮・展開といった「実務で頻出する操作」を安全かつ簡潔に記述できる点が特長です。

shutilを使うと、わずか数行のコードでフォルダ構造を丸ごとコピーしたり、ZIPファイルにまとめて保存したりといった処理を自動化できます。

システム運用やファイル整理のような日常業務でも活躍する、まさに「Pythonの便利屋」といえるモジュールです。

機能関数名説明
ファイルのコピーshutil.copy(src, dst)ファイル内容とパーミッション情報をコピーします。メタ情報(作成日時など)は含まれません。
ファイルの完全コピーshutil.copy2(src, dst)内容に加えてメタデータ(更新日時・アクセス権など)もコピーします。
ディレクトリのコピーshutil.copytree(src, dst)ディレクトリ内の全ファイル・サブディレクトリを再帰的にコピーします。
ファイル・ディレクトリの移動shutil.move(src, dst)ファイルまたはディレクトリを指定先に移動します。リネーム操作としても使用できます。
ディレクトリの削除shutil.rmtree(path)指定したディレクトリを中身ごと再帰的に削除します。
一時ディレクトリの作成shutil.mkdtemp()ユニークな一時ディレクトリを生成します。テストや一時的な作業領域に便利です。
ファイルシステムの使用状況確認shutil.disk_usage(path)指定パスの合計容量・使用容量・空き容量を取得します(単位はバイト)。
アーカイブの作成shutil.make_archive(base_name, format, root_dir)指定ディレクトリを ZIP や TAR 形式でまとめて圧縮します。
アーカイブの展開shutil.unpack_archive(filename, extract_dir)ZIP/TAR などのアーカイブファイルを指定先ディレクトリに展開します。

なぜログがないと検知・分析が困難になるのか

ログは単なる記録ではなく、システムの「健康診断書」のようなものです。

特にPythonのように動的に動作するスクリプトでは、実行環境によって挙動が変わる場合も多く、ログがなければ症状の再現が難しくなります。

開発者と運用者の間で「動いた」「動かない」といった曖昧なやり取りが発生し、調査時間が膨れ上がるのです。

動かないと言われても、こっちの環境では動くんですよね。
それは典型的なケースです。ログがあれば、環境の違いも含めて正確に状況を再現できます。

# loggingモジュールで記録する例
import logging
logging.basicConfig(filename='system.log', level=logging.INFO)
logging.info('バックアップ処理を開始しました')

【出力例:】

INFO:root:バックアップ処理を開始しました

ログがあれば、スクリプトの流れ・異常発生箇所・実行時間などをすべて時系列で追跡できます。

これにより、トラブル対応の再現性と速度が劇的に向上します。

信頼性とは、完璧に動くことではなく、異常時に「何が起きたか」を正確に掴めることです。

loggingモジュールによるログ記録の実装

Pythonのloggingモジュールは、開発から運用まで一貫して活用できる強力な仕組みです。

print文のように簡単に使えますが、ログの重要性を理解して設計すると、トラブル時の調査効率や再現性が飛躍的に向上します。

特に業務スクリプトや自動化タスクでは、どの処理が成功したのか、どの時点で異常が発生したのかを明確に記録できるかどうかが信頼性を左右します。

printで出力していたけど、ログとして残す必要あるんですか?
printは一時的な確認用です。loggingを使えば、記録を残しながら実行結果を整理できます。

基本的な設定とログレベルの使い分け

loggingモジュールでは、処理内容を「どの重要度で記録するか」を明確に区別できます。

これにより、単なる動作確認だけでなく、運用監視にも応用可能です。代表的なログレベルは以下の5種類です。

ログレベル用途
DEBUG詳細な動作確認(開発時に使用)
INFO通常の動作や進行状況を記録
WARNING問題の予兆を記録(処理は継続)
ERROR異常発生を記録(処理は停止または制限)
CRITICAL致命的なエラー(即時対応が必要)

import logging
logging.basicConfig(level=logging.INFO)
logging.debug('デバッグ情報')
logging.info('処理を開始します')
logging.warning('設定ファイルが見つかりません')
logging.error('接続に失敗しました')
logging.critical('システム停止')

【出力例:】

INFO:root:処理を開始します
WARNING:root:設定ファイルが見つかりません
ERROR:root:接続に失敗しました
CRITICAL:root:システム停止

このようにログレベルを明確に設定することで、後から特定のレベルだけを抽出して分析できます。

運用フェーズでは、INFO以上を出力する設定にすることで、必要な情報だけを残しノイズを減らせます。

本番環境ではどのレベルまで記録するのが良いですか?
INFO以上に絞るのが一般的です。DEBUGは開発専用にしておくと、ログが肥大化しません。

ファイル出力・コンソール・ハンドラ設定のポイント

loggingの魅力は「複数の出力先を同時に制御できる」点にあります。

たとえば、開発中はコンソールへ、運用時はログファイルへ出力するように切り替えることができます。

これを実現するのが「ハンドラ(Handler)」という仕組みです。

# ------------------------------------------------------------------
# loggingモジュールによるログ出力の実装例(詳細コメント付き)
# ------------------------------------------------------------------
# Python標準ライブラリ「logging」は、システム動作の記録(ログ)を
# 開発・運用の両段階で一元的に扱える強力な仕組みです。
# ここでは「ファイル」と「コンソール(標準出力)」の両方へ同時出力する構成を作ります。

import logging

------------------------------------------------------------------
【ロガー(Logger)オブジェクトの生成】
------------------------------------------------------------------
logging.getLogger(name) は “ログを管理する本体” を生成します。
name は任意の識別名で、複数モジュール間で共有する際のグループ名になります。
ここでは "sample" という名前でロガーを作成します。
logger = logging.getLogger('sample')

------------------------------------------------------------------
【ログレベルの設定】
------------------------------------------------------------------
出力対象となる最小レベルを設定します。
既定の優先度:DEBUG < INFO < WARNING < ERROR < CRITICAL
ここでは INFO 以上を出力対象とするため、DEBUGは除外されます。
logger.setLevel(logging.INFO)

------------------------------------------------------------------
【ハンドラ(Handler)の設定】
------------------------------------------------------------------
ログの出力先を定義します。
FileHandler:ログファイルに出力。ファイル名を指定する必要があります。
StreamHandler:標準出力(コンソール)へ出力。
※複数のハンドラを追加すれば、1回のlogger呼び出しで複数箇所に同時出力できます。
file_handler = logging.FileHandler('app.log')
console_handler = logging.StreamHandler()

------------------------------------------------------------------
【フォーマッタ(Formatter)の設定】
------------------------------------------------------------------
ログメッセージの構成を定義します。
%(asctime)s :ログ出力時刻(自動生成)
%(levelname)s :ログレベル(INFO, ERRORなど)
%(message)s :実際のログメッセージ本文
※formatの構成を変更することで、出力形式を自由にカスタマイズできます。
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

フォーマッタをハンドラに適用。これを行わないと日時などが出力されません。
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

------------------------------------------------------------------
【ハンドラをロガーに登録】
------------------------------------------------------------------
addHandler() により、ロガーが複数の出力先を持てるようになります。
この設定により、INFOやERRORのログが同時にファイルとコンソールに出力されます。
logger.addHandler(file_handler)
logger.addHandler(console_handler)

------------------------------------------------------------------
【ログの出力】
------------------------------------------------------------------
実際にメッセージを出力します。
logger.info() :通常処理の記録や進捗状況などに使用。
logger.error() :例外発生時や異常終了など、即対応が必要な状態を記録。
logger.info('処理を開始しました')
logger.error('ファイル読み込みエラー')

【出力例:】

2025-11-04 14:12:30,124 - INFO - 処理を開始しました
2025-11-04 14:12:30,125 - ERROR - ファイル読み込みエラー

このようにloggingを使えば、コードの中で発生した出来事を「いつ・何が・どのレベルで」起きたのかを明確に記録できます。

print文では流れてしまう実行履歴を、永続的な“証跡”として残せることが最大の利点です。

特に運用スクリプトでは、shutilなどのファイル操作と組み合わせて処理結果を追跡できるようにしておくと、原因特定と復旧が圧倒的に早くなります。

コンソールとファイルの両方に出すと、確認しやすいですね。
そうです。さらにFormatterを使えば、時刻やメッセージ形式を統一できるので、後で分析が楽になります。

ログのフォーマットはチーム全体で統一しておくと、異なるスクリプト間でも共通ルールで運用でき、トラブル発生時の連携がスムーズになります。

つまり、loggingモジュールの導入は単なる技術的改善ではなく、「見える化による運用の最適化」という実務的なメリットをもたらすのです。

現場で使えるログ設計の「気づき」

開発中はスクリプトが動けば満足してしまいがちですが、実際の現場では「動いた」よりも「なぜ動いたか」「なぜ止まったか」を追える仕組みこそが信頼性につながります。

loggingモジュールを使えば、ただ記録するだけでなく“見える形で仕組みを育てる”ことができます。

現場で繰り返されるトラブル対応の中から、設計段階で意識しておくべきポイントを整理します。

実体験から学んだログ設計の落とし穴

以前、shutilを使って大量ファイルを一括コピーする自動化スクリプトを運用していたときのことです。

初期テストでは問題なかったのに、実運用で「一部のファイルだけコピーされていない」という報告が入りました。

ログ出力を怠っていたため、どのファイルで失敗したのかを突き止めるのに数時間を要しました。

後から考えれば、処理の流れごとにINFOレベルで記録し、エラー発生時にはERRORレベルで詳細を残しておけば、わずか数分で復旧できた案件でした。

ファイルが途中で止まったのに、どこまで処理が進んだかわからなかったんです。
それは典型的な“ログ設計の盲点”です。shutilの処理とloggingを組み合わせておけば、進行状況もエラー箇所も一目でわかります。

# ------------------------------------------------------------------
# loggingモジュールの基本設定例(詳細コメント付き)
# ------------------------------------------------------------------
import logging

# ロガーを取得(名前を付けておくと複数モジュールで扱いやすい)
logger = logging.getLogger('sample')

# 出力レベルを設定
# DEBUG, INFO, WARNING, ERROR, CRITICAL の5段階があり、
# ここではINFO以上(INFO, WARNING, ERROR, CRITICAL)を出力対象とする
logger.setLevel(logging.INFO)

# ------------------------------------------------------------------
# 出力先の設定
# ------------------------------------------------------------------
# ファイル出力用ハンドラ(ログファイルに書き込む)
file_handler = logging.FileHandler('app.log')
# コンソール出力用ハンドラ(ターミナルにも同時出力)
console_handler = logging.StreamHandler()

# ------------------------------------------------------------------
# 出力フォーマットの定義
# ------------------------------------------------------------------
# %(asctime)s : 日時
# %(levelname)s : ログレベル(INFO, ERRORなど)
# %(message)s : 出力メッセージ本体
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')

# フォーマットを各ハンドラに適用
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# ------------------------------------------------------------------
# ハンドラをロガーに登録
# ------------------------------------------------------------------
# これで「logger.info」や「logger.error」呼び出し時に
# ファイルとコンソール両方へ同時出力されるようになる
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# ------------------------------------------------------------------
# ログ出力(実行例)
# ------------------------------------------------------------------
logger.info('処理を開始しました') # 通常処理の開始を記録
logger.error('ファイル読み込みエラー') # 例外や異常発生時の記録

【出力例:】

2025-11-04 13:45:01,203 - INFO - 処理を開始しました
2025-11-04 13:45:01,204 - ERROR - ファイル読み込みエラー

各ブロックの目的

  • 他の開発者がlogger設定の再利用を判断しやすい
  • 本番環境でのログ収集範囲を即座に変更できる
  • 障害対応時に「どの段階で何を出力しているか」が一目でわかる

特にチーム開発では、コメントで“意図”を共有することが最も重要なドキュメント化になります。

ログの有無で対応速度がまったく違います。

単なるテキスト出力ではなく、「時系列で再現できる記録」としてログを扱うことが、開発者の生産性を左右する重要な要素になります。

信頼性を高めるログ運用体制の構築

ログ設計を「一度書いたら終わり」にせず、運用しながら改善していくことが本当の意味での仕組み化です。

重要なのは、「誰が見てもすぐ理解できる書式」と「必要なときにすぐ参照できる構造」を作ることです。

ログファイルって、増え続けると探すのも大変ですよね。
だからこそ、日付や処理単位で分ける設計が必要です。ファイルを分けるのもshutilで自動化できます。

import logging
from datetime import datetime

logfile = f"logs/app_{datetime.now().strftime('%Y%m%d')}.log"
logging.basicConfig(filename=logfile, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.info('1日の処理を開始しました')

【出力例:】

2025-11-04 09:00:00,011 - INFO - 1日の処理を開始しました

このように日次単位でログを自動生成すれば、蓄積しても見通しが保てます。

また、定期的に古いログをアーカイブ化してバックアップする運用もshutilで簡単に実現できます。

import shutil
shutil.make_archive('log_archive', 'zip', 'logs')

【出力例:】

log_archive.zip が作成されました

この仕組みを導入すると、障害時に“探す時間”がほぼゼロになります。

ログを資産として扱い、構造化・自動化まで設計できるエンジニアこそ、長期的に信頼される存在です。

まとめ

ログは単なる「動作記録」ではなく、仕組みを信頼できる形で維持するための“証拠”であり、“再現の鍵”でもあります。

どんなに小さなPythonスクリプトでも、loggingモジュールを活用して流れを残すことで、障害対応のスピードと品質は格段に向上します。

shutilのようなファイル操作を含む処理では特に、記録の有無が復旧までの時間を左右します。

動いているときは気づかないけど、止まったときに初めてログのありがたさがわかりますね。
そうです。記録があることで、問題が「いつ・どこで・なぜ」起きたのかが正確にたどれます。それが仕組みの信頼性そのものになります。

ログ設計は特別なスキルではなく、「残す意識」と「読み返せる構造」を意識するだけで始められます。

日々のスクリプトにloggingを組み込み、必要に応じてshutilでアーカイブ化する仕組みを導入すれば、運用も振り返りも格段に楽になります。

これこそが、動くコードから“生きている仕組み”へと進化させる第一歩です。

よく読まれている記事

1

「私たちが日々利用しているスマートフォンやインターネット、そしてスーパーコンピュータやクラウドサービス――これらの多くがLinuxの力で動いていることをご存じですか? 無料で使えるだけでなく、高い柔軟 ...

2

Linux環境でよく目にする「Vim」という名前。サーバーにログインしたら突然Vimが開いてしまい、「どうやって入力するの?」「保存や終了ができない!」と困った経験をした人も多いのではないでしょうか。 ...

3

ネットワーク技術は現代のITインフラにおいて不可欠な要素となっています。しかし、ネットワークを深く理解するためには、その基本となる「プロトコル」と「レイヤ」の概念をしっかり把握することが重要です。 こ ...

4

この記事は、Linuxについて勉強している初心者の方向けに「Shellスクリプト」について解説します。最後まで読んで頂けましたら、Shellスクリプトはどのような役割を担っているのか?を理解出来るよう ...

5

Javaは世界中で広く使われているプログラミング言語であり、特に業務システムやWebアプリケーションの開発において欠かせない存在です。本記事では、初心者向けにJavaの基礎知識を網羅し、環境構築から基 ...

-Pythonの基礎知識(基礎編)