loggingの簡単な使い方

# はじめに
こんにちは、[@nano_sudo](https://twitter.com/nano_sudo)です!
今回は、ライブラリ紹介シリーズ第3弾として、`logging`を紹介します！
`logging`は、Pythonの標準ライブラリでありながら、とても強力な機能を持っています。
今回は、初心者の方でも簡単に理解できるように、`logging`の基本的な使い方を紹介します。

# loggingとprintの違い

- **`print`**
  - 主にデバッグ用
  - ログレベルを指定できない

- **`logging`**
  - ログレベルを指定できる
  - ログをファイルに出力できる
  - ログのフォーマットを指定できる
  - ログの出力先を複数指定できる
  - かっこいいログを出力できる(外部ライブラリ使用)

# インストール
`logging`は、Pythonの標準ライブラリなので、インストールは不要です。

# loggingの基本的な使い方

## 各種ログレベルの出力
`logging`には、以下のようなログレベルがあります。(下に行くほどレベルが高い)
- `DEBUG`
問題の診断のときに興味のある詳細情報を記録するために使用します。
- `INFO`
正常な動作を示す情報を記録するために使用します。
- `WARNING`
問題が発生したことを示す警告を記録するために使用します。(例:ディスク空き容量が少ない)
- `ERROR`
重大な問題によって、ある機能を実行できないときに使用します。
- `CRITICAL`
プログラム自体が実行を続行できない重大な問題が発生したときに使用します。

### 使い方
```python
import logging

# ログレベルを設定
logging.basicConfig(level=logging.DEBUG)　# これは後で説明します

# 各種ログレベルの出力
# debug
logging.debug("debug")

# info
logging.info("info")

# warning
logging.warning("warning")

# error
logging.error("error")

# critical
logging.critical("critical")

# f-stringを使うこともできる
name = "Alice"
logging.info(f"Hello, {name}!")
```

## ロガーの作成・取得
`logging`には、`getLogger()`という関数があります。
この関数を使うと、ロガーを作成・取得することができます。
getLogger()の引数には、ロガーの名前を指定します。名前が存在しない場合は、新しくロガーが作成されます。
ロガーの名前は、`__name__`(現在のモジュール名)を指定するのが一般的です。

これを利用して、複数のファイルで同じロガーを使うことができます。

### 使い方
```python
import logging

# ロガーの作成・取得
logger = logging.getLogger(__name__)

# 出力
logger.info("Hello, World!")

# ログレベルの変更もできる
logger.setLevel(logging.DEBUG)

```

## ロガーを設定する
`logging`には、`basicConfig()`という関数があります。
この関数を使うと、ロガーの設定を行うことができます。

### 引数
- **`level`** [`int`] [`logging.<level>`]
    ログレベルを指定します。
    ログレベルには、以下のようなものがあります。
    - `logging.DEBUG`
    - `logging.INFO`
    - `logging.WARNING`
    - `logging.ERROR`
    - `logging.CRITICAL`
    指定したログレベル以上のログが出力されます。
    (例:ログレベルを`INFO`に設定した場合、`INFO`、`WARNING`、`ERROR`、`CRITICAL`のログが出力されます。)

- **`format`** [`str`]
    ログのフォーマットを指定します。
    ログのフォーマットには、以下のようなプレースホルダーを指定することができます。
    - `%(asctime)s`
    ログを出力した日時を指定します。
    - `%(levelname)s`
    ログレベルを指定します。
    - `%(name)s`
    ロガーの名前を指定します。
    - `%(message)s`
    ログのメッセージを指定します。

- **`datefmt`**
    ログの日時のフォーマットを指定します。
    ログの日時のフォーマットには、`strftime()`と同じフォーマットを指定することができます。
    くわしくは、[こちら](https://docs.python.org/ja/3/library/datetime.html#strftime-and-strptime-format-codes)をご覧ください。

- **handler** , **formatter**
    発展的な内容になるので、ここでは紹介しません。

### 使い方
```python
import logging

# ロガーの設定
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)s %(name)s %(message)s"
    datefmt="[%X]"
)
```
# 発展的な使い方
## 色付きのログを出力する
個人的に、`rich`を使うのがおすすめです。
`rich`を使えば、簡単に色付きのログを出力することができます。
また、右端にどこからログが出力されたかが表示されるので、どこからログが出力されたかわかりやすくなります。

### インストール

```bash
pip install rich
```
or 
```bash
poetry add rich
```
### 引数
**`RichHandler`**
- **`markup`** [`bool`]
    マークアップを有効にするかどうかを指定します。
    マークアップを有効にすると、色付きのログを出力することができます。
    数字や真偽値に色が付きます。
    例えば、`[red]hello[/red]`のようにすると、色付きのログを出力することができます。
    ログレベルはFalseでも色がつきます。
- **`rich_tracebacks`** [`bool`]
    トレースバックをかっこよく表示するかどうかを指定します。
    トレースバックをかっこよく表示すると、トレースバックが見やすくなります。

### 使い方
```python
import logging
from rich.logging import RichHandler

# ロガーの設定
logging.basicConfig(
    level=logging.DEBUG,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[RichHandler(markup=True,rich_tracebacks=True)]
)
```
### 使ってみたの図

![rich.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535890/e15fc06c-a197-89d9-a561-2852fd80734f.png)

※トレースバックは面倒なので省略しました(殴

Richについて詳しく知りたい方は、以下の記事をご覧ください。

https://zenn.dev/nano_sudo/articles/8a0e60cc24648a

## ログをファイルに出力する
`logging`には、`FileHandler`というクラスがあります。
このクラスを使うと、ログをファイルに出力することができます。

### 引数
**`FileHandler`**
- **`filename`** [`str`]
    ログを出力するファイル名を指定します。
    ファイル名を指定しない場合は、`sys.stderr`に出力されます。
- **`mode`** [`str`]
    ファイルを開くモードを指定します。
    デフォルトは`a`(追記)です。
    `w`(上書き)にすると、ログが上書きされます。

### 使い方
```python
import logging
from logging import FileHandler

# ロガーの設定
logging.basicConfig(
    level=logging.DEBUG,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[FileHandler(filename="log.txt")]
)
```

## ログを複数のファイルに出力する
`logging`には、`handlers`という引数があります。
この引数を使うと、ログを複数のファイルに出力することができます。

### 使い方
```python
import logging
from logging import FileHandler

# ロガーの設定
logging.basicConfig(
    level=logging.DEBUG,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[
        FileHandler(filename="log.txt"),
        FileHandler(filename="log2.txt")
    ]
)
```
レベルによって、出力先を変えることもできます。
```python
import logging
from logging import FileHandler

# ロガーの設定

# ログレベルがDEBUGのときは、 debug.log に出力する
# ログレベルがINFOのときは、 info.log に出力する

logging.basicConfig(
    level=logging.DEBUG,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[
        FileHandler(filename="debug.log",level=logging.DEBUG),
        FileHandler(filename="info.log",level=logging.INFO)
    ]
)
```
もちろん、`RichHandler`と組み合わせることもできます。
```python
import logging
from logging import FileHandler
from rich.logging import RichHandler

# ロガーの設定
logging.basicConfig(
    level=logging.DEBUG,
    format="%(message)s",
    datefmt="[%X]",
    handlers=[
        FileHandler(filename="log.txt"),
        RichHandler(markup=True,rich_tracebacks=True)
    ]
)
```

# 参考にしたページ
### logging --- Python公式ドキュメント

https://docs.python.org/ja/3/library/logging.html

### logging howto --- Python公式ドキュメント

https://docs.python.org/ja/3/howto/logging.html

# まとめ
お疲れ様でした！
`logging`は、Pythonの標準ライブラリでありながら、とても強力な機能を持っています。
`logging`を使って、良きPythonライフを送りましょう！
質問やご意見などは、[X](https://twitter.com/nano_sudo) or コメント欄にてお願いします！