第3回 | Pythonアプリを実行してログを確認する | 画面、終了状態、ログの3か所を見る|UNIX Cafe

* 当サイトでは、コンテンツの一部に広告を掲載しています。

System Note $ cat /proc/ai-disclosure

本記事の構成および論理分析にはAI(人工知能)を使用しています。情報の正確性は、システム管理者(UNIXユーザー)による手動検証済みです。

CLIで開発する | 第3回

コードを直す前に、まず現在の状態を自分で再現します。正常に動くのか、どんな表示が出るのか、エラーが起きると何が残るのか。修正前の状態を確認すると、その後の調査が進めやすくなります。

今回は、Pythonアプリを実行し、画面の表示、終了状態、ログの3か所を見ます。

この記事で学べること

  • python3 src/app.py でアプリを実行する方法
  • echo $? で終了状態を見る方法
  • tail で直近のログを見る方法
  • エラーを調査の手がかりとして使う考え方
目次

練習を始める前の準備

第2回から続けて読む場合は、前回作成した unix_cafe_order ディレクトリへ移動します。

cd unix_cafe_order
pwd
ls

pwd で表示された場所の末尾が unix_cafe_order になっていて、次のファイルがあれば準備を進められます。

data      logs      README.md      src       tests

ディレクトリがない場合は、第2回の記事に戻り、練習用ファイルを作成してください。

前回はファイル構成を見ることを優先したため、アプリは固定された3件の金額を合計する形でした。今回からは、CSVファイルの読み込み、ログの記録、エラーの終了状態を確認できる形へ拡張します。第2回と同じように、vi で次のファイルを順番に開き、表示された内容へ置き換えてください。

vi で内容をすべて置き換えるときは、ファイルを開いた後に :%d と入力して Enter キーを押します。既存の内容が消えたら、i キーで入力モードに入り、新しい内容を入力します。最後に Esc:wqEnter の順で保存して終了します。

app.pyを準備する

vi src/app.py
import 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.py
def calculate_total(orders):
    total = 0
    for order in orders:
        total += int(order["price"]) * int(order["quantity"])
    return total

message.pyを準備する

vi src/message.py
def format_total(total):
    return f"Order total: {total} yen"

orders.csvを準備する

vi data/orders.csv
item,price,quantity
coffee,450,2
toast,380,1
cake,520,1

test_calculator.pyを準備する

vi tests/test_calculator.py
import 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 init

Gitの名前とメールアドレスを確認する

この練習用リポジトリで、コミットに使う名前とメールアドレスが設定されているかを確認します。--local を付けると、このリポジトリ専用の設定だけを表示できます。

git config --local user.name
git config --local user.email

何も表示されなくても問題ありません。パソコン全体の設定(global)を済ませている場合でも、--local はこのリポジトリ専用の設定だけを見るため、表示は空のままになります。続けて、この練習用リポジトリで使う名前とメールアドレスを設定します。

ここでは例として Your Nameyou@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.csv

echo $? で終了状態を見る

直前に実行したコマンドの終了状態は、次のコマンドで確認できます。

echo $?

正常に終了した場合は通常 0、エラーがある場合は 0 以外が表示されます。今回の例では 1 です。

ログも確認してみましょう。

tail -n 5 logs/app.log

ログの最後には、次のような行が残ります。

ERROR orders file not found: data/missing.csv

確認する場所を整理する

見る場所分かること
画面の表示利用者に見えている結果
echo $?直前のコマンドが正常終了したか
logs/app.logアプリが記録した情報やエラー

手を動かすミニ練習

  1. 正常実行後に echo $? を入力し、0 になることを確認する
  2. 存在しないファイルを指定し、画面のエラーを見る
  3. tail -n 5 logs/app.log でログに残ったエラーを確認する

練習を終えた後の片付け

この回ではコードを書き換えていないため、そのまま次回へ進めます。次回も使うため、unix_cafe_order ディレクトリは残しておいてください。

次回予告

次回は、画面に出た orders file not found という文字列を手がかりに、関係するコードを探します。

さらに学びたいあなたへ

用途ごとに選ぶ Linux のおすすめ本

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

のいのアバター のい UNIX Cafe マスター

Macintosh Color Classicから始まった旅は、長いWindows時代を経て、Windows10のサポート終了をきっかけにUNIXの世界へ戻ってきました。UNIX Cafeでは、UNIX・Linux・そしてMacな世界を、むずかしい言葉を使わず、物語のように書いています。プログラミングは、アイデアをコンピューターに伝えるための言葉です。簡単な単語と文法を覚えれば、誰でもコマンドを使えます。ぜひ一度、やさしいプログラミングの世界をのぞいてみてください。

Created by UNIX Cafe

目次