本記事の構成および論理分析にはAI(人工知能)を使用しています。情報の正確性は、システム管理者(UNIXユーザー)による手動検証済みです。
第3回 | Pythonアプリを実行してログを確認する | 画面、終了状態、ログの3か所を見る|UNIX Cafe

CLIで開発する | 第3回
コードを直す前に、まず現在の状態を自分で再現します。正常に動くのか、どんな表示が出るのか、エラーが起きると何が残るのか。修正前の状態を確認すると、その後の調査が進めやすくなります。
今回は、Pythonアプリを実行し、画面の表示、終了状態、ログの3か所を見ます。
この記事で学べること
python3 src/app.pyでアプリを実行する方法echo $?で終了状態を見る方法tailで直近のログを見る方法- エラーを調査の手がかりとして使う考え方
練習を始める前の準備
第2回から続けて読む場合は、前回作成した unix_cafe_order ディレクトリへ移動します。
cd unix_cafe_order
pwd
lspwd で表示された場所の末尾が unix_cafe_order になっていて、次のファイルがあれば準備を進められます。
data logs README.md src testsディレクトリがない場合は、第2回の記事に戻り、練習用ファイルを作成してください。
前回はファイル構成を見ることを優先したため、アプリは固定された3件の金額を合計する形でした。今回からは、CSVファイルの読み込み、ログの記録、エラーの終了状態を確認できる形へ拡張します。第2回と同じように、vi で次のファイルを順番に開き、表示された内容へ置き換えてください。
vi で内容をすべて置き換えるときは、ファイルを開いた後に :%d と入力して Enter キーを押します。既存の内容が消えたら、i キーで入力モードに入り、新しい内容を入力します。最後に Esc、:wq、Enter の順で保存して終了します。
app.pyを準備する
vi src/app.pyimport csv
import logging
import sys
from pathlib import Path
from calculator import calculate_total
from message import format_total
ROOT_DIR = Path(__file__).resolve().parent.parent
DEFAULT_CSV = ROOT_DIR / "data" / "orders.csv"
LOG_FILE = ROOT_DIR / "logs" / "app.log"
def load_orders(csv_path):
with csv_path.open(newline="", encoding="utf-8") as file:
return list(csv.DictReader(file))
def main():
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format="%(levelname)s %(message)s",
)
csv_path = Path(sys.argv[1]) if len(sys.argv) > 1 else DEFAULT_CSV
try:
orders = load_orders(csv_path)
except FileNotFoundError:
logging.error("orders file not found: %s", csv_path)
print(f"orders file not found: {csv_path}", file=sys.stderr)
return 1
total = calculate_total(orders)
logging.info("calculated total: %s", total)
print(format_total(total))
return 0
if __name__ == "__main__":
raise SystemExit(main())calculator.pyを準備する
vi src/calculator.pydef calculate_total(orders):
total = 0
for order in orders:
total += int(order["price"]) * int(order["quantity"])
return totalmessage.pyを準備する
vi src/message.pydef format_total(total):
return f"Order total: {total} yen"orders.csvを準備する
vi data/orders.csvitem,price,quantity
coffee,450,2
toast,380,1
cake,520,1test_calculator.pyを準備する
vi tests/test_calculator.pyimport sys
import unittest
from pathlib import Path
SRC_DIR = Path(__file__).resolve().parent.parent / "src"
sys.path.insert(0, str(SRC_DIR))
from calculator import calculate_total
class CalculateTotalTest(unittest.TestCase):
def test_quantity_is_included(self):
orders = [{"price": "450", "quantity": "2"}]
self.assertEqual(calculate_total(orders), 900)
if __name__ == "__main__":
unittest.main().gitignore を作成する
実行するたびに増えるログやPythonの一時ファイルは、Gitの記録対象から外します。
vi .gitignore.gitignore に次のように書くと、Gitで記録しないファイルやディレクトリを指定できます。
logs/app.log
__pycache__/logs/app.log は、実行するたびに増えるログファイルです。__pycache__/ は、Pythonが自動で作る一時ファイル用のディレクトリです。どちらも人が直接編集するものではないため、Gitでは記録しないようにします。
差分をGitへ記録する
第5回以降で差分を確認できるように、現在の状態をGitへ記録しておきます。
すでにGit管理されている場合は、この手順は飛ばしてください。
まだGit管理していない場合は、作業用のディレクトリで、1度だけgit init を実行してください。
git initGitの名前とメールアドレスを確認する
この練習用リポジトリで、コミットに使う名前とメールアドレスが設定されているかを確認します。--local を付けると、このリポジトリ専用の設定だけを表示できます。
git config --local user.name
git config --local user.email何も表示されなくても問題ありません。パソコン全体の設定(global)を済ませている場合でも、--local はこのリポジトリ専用の設定だけを見るため、表示は空のままになります。続けて、この練習用リポジトリで使う名前とメールアドレスを設定します。
ここでは例として Your Name と you@example.com を使っています。実際に入力するときは、自分の名前とメールアドレスに置き換えてください。
git config user.name "Your Name"
git config user.email "you@example.com"この設定は、このGitリポジトリの中だけで使われます。練習用なので、実在のメールアドレスでなくてもかまいません。
Gitへ記録する
最後に、現在のファイルの状態をGitへ記録します。記録の前後で状態を確認しながら進めると、何を記録しようとしているのかを目で確かめられて安心です。
まず git status で現在の状態を確認します。
git statusまだ記録していないファイルは Untracked files として表示されます。ここで、これから記録する対象を把握できます。
次に git add . で、表示されたファイルを記録候補(ステージング)に追加します。
git add .もう一度 git status を実行すると、追加したファイルが Changes to be committed として表示され、記録候補に入ったことを確認できます。
git status実行結果は次のようになります。
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: README.md
new file: data/orders.csv
new file: src/app.py
new file: src/calculator.py
new file: src/message.py
new file: tests/test_calculator.py各行の意味はこうです。
| 表示 | 意味 |
|---|---|
On branch main | 今いるブランチ |
No commits yet | まだ一度も記録(コミット)していない状態 |
Changes to be committed: | 次の commit に含まれる予定の変更 |
new file: .gitignore | このファイルが新規追加として add 済みの状態 |
Changes to be committed: の欄にファイルが表示されていれば、add は正しく通っています。new file: は今回が初めての記録、modified: は以前の記録から変更があった場合に表示されます。
git diff --staged でファイルの中身を確認する
記録される中身まで確認したいときは git diff --staged を使います。今回は新しく作ったファイルばかりなので、すべてが追加分として表示されます。
git diff --staged内容に問題がなければ git commit で記録します。
git commit -m "Prepare sample project"git add . は、今いるディレクトリ以下のファイルを記録候補に追加するコマンドです。git commit は、その状態をひとつの記録として保存するコマンドです。記録の前後で git status を確認する習慣をつけておくと、意図しないファイルを記録してしまう事故を防げます。
まず正常な状態を動かす
Python で書かれたアプリ、app.py を実行します。
python3 src/app.py正常に動くと、注文データを読み込み、合計金額を表示します。
Order total: 1800 yenこの結果が変更前の基準になります。修正後にも同じコマンドを実行すれば、結果がどう変わったかを比べられます。
tail で直近のログを見る
このアプリapp.py は、実行結果を logs/app.log に残します。最後の数行を見るには tail を使います。
tail -n 5 logs/app.logログには、次のような行が残ります。
INFO calculated total: 1800画面に出た情報だけでなく、ログにも調査の手がかりがあります。特に、処理の途中経過やエラーを確認したい場面で役立ちます。
存在しないファイルを指定する
今度は、存在しないCSVファイルを指定してみます。
python3 src/app.py data/missing.csvファイルが見つからないため、次のようなエラーが表示されます。
orders file not found: data/missing.csvecho $? で終了状態を見る
直前に実行したコマンドの終了状態は、次のコマンドで確認できます。
echo $?正常に終了した場合は通常 0、エラーがある場合は 0 以外が表示されます。今回の例では 1 です。
ログも確認してみましょう。
tail -n 5 logs/app.logログの最後には、次のような行が残ります。
ERROR orders file not found: data/missing.csv確認する場所を整理する
| 見る場所 | 分かること |
|---|---|
| 画面の表示 | 利用者に見えている結果 |
echo $? | 直前のコマンドが正常終了したか |
logs/app.log | アプリが記録した情報やエラー |
手を動かすミニ練習
- 正常実行後に
echo $?を入力し、0になることを確認する - 存在しないファイルを指定し、画面のエラーを見る
tail -n 5 logs/app.logでログに残ったエラーを確認する
練習を終えた後の片付け
この回ではコードを書き換えていないため、そのまま次回へ進めます。次回も使うため、unix_cafe_order ディレクトリは残しておいてください。
次回予告
次回は、画面に出た orders file not found という文字列を手がかりに、関係するコードを探します。




