Python loggingの基本的な使い方を抑える

この記事で説明すること

Pythonのloggingを使ったログ処理について、業務上扱うのに先に抑えておくべきだったなと思ったことを紹介します。

先に結論的な

  • loggerにはsetLevelがあり、logger毎に扱うログのレベルを設定可能
  • 各loggerにはhandlerがありhandlerごとにログの出力先の設定や、handler自体にもsetLevelを設定可能
  • ルートロガーは特別なloggerで、デフォルトで使用すると以下の設定となる
    • loggerのsetLevel:WARNING
    • handler:lastResort(実質のところStreamHandler)
    • handlerの出力先:標準エラー出力
    • handlerのsetLevel:WARNING

loggerについて

Pythonのloggingモジュールでは、以下のようにしてlogger(ロガー、ログを出力してくれるもの)インスタンスを生成します。
生成したインスタンスを利用し、infoやerrorなどのログを出力することができます。

import logging
logger = logging.getLogger()
logger.info("infomation message")
logger.error("error message")

上記のような使い方でも、個人開発でローカル環境ならそこまで問題ないかもしれません。
ただ、上記例だとinfo()でログが表示されない状態となっています。

なぜそのようになっているかというと、
上記ではルートロガーを生成しており、ルートロガーのデフォルトのsetLevelがWARNINGだからです。

logger自体のLevel

loggerにはLevelという、インスタンス変数があります。
インスタンス変数なので、logger毎に設定が可能です。 先ほどの例でいうと

import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)

とすることでそのloggerが扱うLevelを設定することができます。
ここでいうLevelとは、そのloggerが扱うログの重要度のことであり、設定したLevel未満のログはloggerによって無視されます。
Levelは以下があります(公式より画像引用)。
たとえば、

logger.setLevel(logging.INFO)
logger.debug("debug message")

の場合には、loggerのLevel(INFO)よりも、DEBUGのLevelが低いため、上記の"debug message"はloggerが無視し、処理しないことになります。

NOT SETだったら全部のLevelが処理されるはず

先述の

import logging
logger = logging.getLogger()
logger.info("infomation message")
logger.error("error message")

ではinfo()でログが表示されない状態と記載しました。
上記のコードであればLevelを指定していないので、NOT SETとして設定されていそうな気がしますよね。 しかし、例によってルートロガーは特別にLevelのデフォルト値がWARNINGになっているために、loggerがINFOレベルのログを無視していたのでした。

loggerには名前空間があり、名前空間ごとにLevelを設定できる

loggerには名前空間があります。 名前空間はある範囲での名前が重複せずに、一意の名前であるように識別するものです。
例えば以下の場合だと、各々3つの名前空間に対してlogger自身のLevelも設定できますし、logger毎にhandlerとhandleのLevelも設定可能です。

  • sample
  • sample.child
  • sample.child.grandchild

名前空間では . (ドット)で親子関係を表現できます。上記の例であればsampleが親、childが子、grandchildが孫となります。
子ロガーでログ出力の際、handlerが設定されていなかった場合には親ロガーへログ処理が委譲されます(デフォルト設定のままなら)。
例ではgrandchildロガーがhandlerを持っていなければ、childに委譲され、さらになければsampleでログ処理が行わます。
さらにsampleにもhandlerがなければ、最終的にルートロガーに委譲され処理が行われます。
ただし明確な理由がなければ、基本的にルートロガーのみににLevelやhandlerを設定を設定し、子ロガーでは処理をルートロガーに委譲する使い方でも良いと思います。

handlerとは

handler(ハンドラ、ハンドラー)とは、実際のログ処理を

  • どこに出力するか
  • handler自身ではどのLevelを扱うか

などについて設定できます。

handlerの種類

handlerにはいくつかの種類があり、それによってログの出力先を変更できます。 いくつか例を挙げると

  • StreamHandle
  • FileHandler
    • ディスク上のファイルへ出力
  • HTTPHandler
    • URLを指定したWebサーバー上でPOSTなどで出力

などがあります(記事を書くにあたって調べたら、他にもたくさんあって面白かったです)。

handlerにもLevelがある

loggerのLevel同様、handlerにもLevelを設定できます。
考え方的にはlogger自体に設定するものと一緒です。

各loggerとhandlerの処理順序

loggerとhandlerのそれぞれにLevelを設定できます。
しかしそれぞれのLevelが一致していない場合、どちらが優先されるのでしょうか。
答えはloggerが先に判定し、そのあとにhandlerが最終的に処理するかどうかを決めます。
例えば以下の場合、loggerのLevelよりもhandlerのLevelが高いため、結果的にDEBUGログを出力できません。

また、loggerのレベル未満のログはhandlerに届くことすらありません。

handlerは複数設定することもできるため、loggerが扱うLevelの範囲であれば、
以下のようなこともできます。

他にもFormatterとかあるけど

ここまでの内容ですでに3200文字を超えているため、この記事は一旦ここまでにします。
logger自体のLevelとhandlerの使い方がわかれば、まずは最低限意図したログを出せるようになるかなと思います。

余談(ほんとは一番言いたかったこと)

ルートロガーをデフォルトのまま使っていたせいで、Azure App Serviceの監視をしているLogAnalytics上でINFOログが全部ERRORで出力していたことが今回の記事のきっかけでした。
そもそもルートロガーをそのまま使うなよとかありそうですが、今回良い勉強になったのでヨシ!!!

pip freezeの出力結果をWindowsとLinuxで比べてみた

行ったこと

Windows環境とLinux(Debian)環境で同じパッケージをインストールしている状態で、pip freezeしたら本当に環境ごとに出力結果が異なるか軽く動かしています。
AzureのKey Vaultを実行するパッケージをインストールしたときに、どのような違いが出るかで確認しました。

背景

  • 業務でWindowsLinuxの環境差異でpip install -r requirements.txtがエラーになることが多い
  • Windows環境で出力したrequirements.txtをLinux環境で使うのがそもそも良くないらしい

環境

Windows

OS:Windows 11 Pro 23H2
Python:3.9.13
pip:24.0

Linux

OS:Debian GNU/Linux 11 (bullseye)
Python:3.9.13
pip:24.0

各環境上でのパッケージインストール

各環境上で以下を実行します。

pip install azure-identity
pip install azure-keyvault-secrets

Windows上では仮想環境を利用していますが、Linux環境では今回はDockerコンテナを利用しているため、仮想環境は利用せずに、コンテナにそのままパッケージをインストールしました。

パッケージのインストールなどはこちらを参考にしています。

learn.microsoft.com

pip freezeの実行

それぞれの環境で以下を実行します。

pip freeze > requirements.txt

結果を比較

Winmergeを使い、確認できた結果が以下でした。
左:Windows
右:Linux pywin32というパッケージがWindows環境でのみrequirements.txtに出力されているのがわかります。
これはAzureリソースへアクセスするためにWindows環境では必要ということなんだと思われます。 (pycparserのバージョンが異なっていますが、今回は無視します)

最後に

Dockerコンテナを利用するなどして、開発環境や本番環境の環境差異をなくすことで、今後インストールパッケージの違いなどからくるエラーをなくしていきたいですね。

WindowsLinuxでpycparserのバージョンが異なってしましたが、そもそも開発自体もDockerで本番とほぼ同じ環境を用意すれば、環境の違いによるエラーは防げるだろうと思います。
当たり前だろうと思われる方も多かったと思いますが、ここまで読んでくださってありがとうございます。

vscodeとDevContainerでらくらく開発環境構築(Python)

この記事で紹介すること

Dockerコンテナ内でPython開発をするための必要なことを紹介します。
具体的には

  • Dockeコンテナ内でファイルを同期する方法
  • vscodeのDev Container拡張機能を利用して、コンテナ環境でvscode開発を行う方法
  • コンテナ内でPythonをDebug実行する方法
    などです。PythonフレームワークとしてFlaskを利用しています。

ディレクトリ構成

.
├── app
│   ├── Dockerfile
│   ├── app.py
│   ├── requirements.txt
│   └── templates
│       └── index.html
├── .devcontainer
│   └── devcontainer.json
├── .vscode
│   └── launch.json
├── docker-compose.yml
└── test

※testディレクトリは使用しません。

開発環境用イメージのビルドで利用するDockerfileを準備する

一旦これだけです。

FROM python:3.9
RUN pip install flask

Dockerコンテナでファイルを同期する方法

ローカルホストの特定のディレクトリをコンテナ内のディレクトリに同期するにはバインドマウントを利用します。
バインドマウントをでソースコードを配置しているディレクトリをコンテナにマウントすることで、
Dev Container利用時にコンテナ環境でのファイル操作をローカルと同期できるようになります。

docker-compose.ymlを作成する

現在はdocker-composeのバージョン指定は不要みたいですが、一応付けています。

version: '3.9'
services:
  app:
    container_name: flask_app
    build: ./app
    ports:
      - 8080:5000
    tty: true
    volumes:
      - ./app:/workspace
    working_dir: /workspace
    environment:
      - FLASK_APP=app
    # flaskアプリの起動コマンド
    # command: flask run --host=0.0.0.0

この部分で、ローカルのappディレクトリをコンテナの/workspaceディレクトリにバインドマウントしています。

    volumes:
      - ./app:/workspace

ここまででdocker-compose.ymlの存在するディレクトリで

docker compose up --build

を実行すれば、FlaskパッケージをインストールしたPythonコンテナが立ち上がります。 Dockerコンテナが無事に起動することを確認できたら、DevContainerの準備に入ります。

DevContainerのインストール

vscode拡張機能で"DevContainer"と検索し、画像の拡張機能をインストールします。 (Remote Developmentをインストールしても入ります。)

devcontainer.jsonを作成する

DevContainerではdevcontainer.jsonで各種設定を行うことで、起動したコンテナ内でvscodeでの開発ができるようになります。
今回使用したdevcontainer.jsonはこちらです。

{
    "name": "flask-container",
    "service": "app",
    "workspaceFolder": "/workspace",
    "dockerComposeFile": "../../docker-compose.yml",
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
            ]
        }
    }
}

それぞれの値を解説していきます。

name値はvscodeで表示されるプロジェクト名(?)です。

"name": "flask-container",

このように表示されます。

service値は後述するdockerComposeFileで指定したdocker-compose内のサービス名を記載します。

"service": "app",

workspaceFolder値はプロジェクトのルートディレクトリを指定します。

workspaceFolder": "/workspace",

dockerComposeFile値はDevContainerで接続したいコンテナをビルドするdocker-compose.ymlを指定します。

"dockerComposeFile": "../../docker-compose.yml",

customizations値では、vscodeへの個別の設定や拡張機能を入れられるようです。

"customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
            ]
        }
    }

今回はPython拡張機能しか入れていませんが、vscodeのsettingsから設定できる値は結構入れられそうな雰囲気です。
github.com

DevContainerでコンテナ環境へ接続する

新規でvscodeのウィンドウを立ち上げます。
立ち上げたらCtrl + Pで検索窓を表示し、DevContainerと入力すると画像のようになるので、Open Folder in Container を選択します。

今回はdocker-composeでappディレクトリをビルド対象にしているため、DevContainerでappディレクトリを開きます。

コンテナ起動が成功し、DevContainerによる接続が成功すると以下のようになります(画像ではログを出力しています。)

この状態ですでにローカルPCのディレクトリとコンテナのディレクトリがバインドマウントできているため、コンテナ内で編集した内容がローカルPC側にも同期されます。

コンテナ環境でデバッグ実行する

コンテナ環境であっても、vscode拡張機能vscodeの標準機能などは利用できるため、設定を行うことでデバッグ実行もできるようになります。 以下はlaunch.jsonの設定値です。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Flask",
            "type": "python",
            "request": "launch",
            "module": "flask",
            "env": {
                "FLASK_APP": "app.py",
                "FLASK_DEBUG": "1"
            },
            "args": [
                "run",
                "--no-debugger",
                "--no-reload",
                "--host=0.0.0.0"
            ],
            "jinja": true,
        }
    ]
}

launch.jsonについての解説は今回は割愛します(ほぼデフォルトから変えていません)。
launch.jsonがある状態でapp.pyからF5を押せば以下の状態になり、flaskアプリが立ち上がります。

この状態でブラウザからhttp://localhost:8080/にアクセスすると
ちゃんとデバッガがブレークポイントで止まってくれています。

コンテナのビルド時にrequirements.txtを読み込む

今回立ち上げたコンテナのDockerfileを以下のようにすることで、コンテナイメージをビルドする際にrequirements.txtからPythonパッケージをインストールできます。

FROM python:3.9
WORKDIR /workspace
COPY ./requirements.txt /workspace/
RUN pip install --no-cache-dir -r requirements.txt

作業ディレクトリなどの指定は必須ではありませんが、一応PCとマウントしているディレクトリにrequirements.txtが配置されるようにしています。 マウントしたディレクトリにrequirements.txtがあることで、コンテナ環境で出力したパッケージ情報をPC側にも共有できるため、git管理するのもやりやすくなると思います。

参考にしたもの

Udemyのこちらの講座を参考に各種設定などを行いました。
www.udemy.com

Dockerはなんとなく苦手意識があってあまり触ってこなかったんですが、今回基礎的な部分からいろいろ触れたのでこの講座を買ってよかったです。

Microsoft MVPによるLearn解説を聞いてみた

先日こちらのイベントに参加してきました。 hack-everything.connpass.com

ここで紹介されているMicrosoft Learnの活用方法で自分が知らないことや、そうやってMicrosoft MVPの人たちは活用しているんだと参考になることが非常に多かったので、忘れないようにブログにしました。
Microsoft LearnとはいわゆるMicrosoftの公式ドキュメントのことです。

イベント内で紹介されていた内容を残しつつ、最後に自分なりにどう活用していきたいかなどを書いていこうと思います。

MS Learnの基本的な使い方

Learnのトップから入るとやりたいこと別に入口が用意されているので、そこから各リンクへ飛べるようになっています。
Microsoft Learn: キャリアの扉を開くスキルを身につける 登壇していたshibayanさん機械学習については全くの素人だというお話でしたが、資格取得のために全部Learnからキャッチアップされたらしいです。
Learnのとっつきにくさの理由の一つとして用語が難しく、何を書いているのかわからない人が多いと思いますが(自分もそうですし)、 もしLearnに書いてある用語がわからないという場合にはLearnのはじめましてから入ると良いようです。

はじめましてに入るとラーニングパスを参照というリンクがあるので、その中で知りたい内容を検索するとたくさんラーニングパスが出てきます。

すごくたくさんあるのですが、試しにAzureで絞りこむと「クラウド サービスを使用する利点について説明する」という初心者の方向けの情報も出てきます。 他にもGitHubExcelについてなど、MS製品の物だったらかなり網羅されている印象です。

各種トレーニングの最後には知識チェックのテストもあるので、トレーニング内容の確認にも活用できそうです。

自分が繰り返し見たいラーニングパスは、自分のMSアカウントのお気に入りに追加することもできます。 お気に入りはMSアカウントのプロファイルから見に行くことができます。

基本ググって出てきたLearnを見ても難しくわからない場合には、トレーニングのリンクに飛んで基本的なことをキャッチアップするのがおすすめとお話していました。

例えば、僕はAPI Managementについてキャッチアップしたいので試しに見てみると確かに画面右側にトレーニングのリンクありますね。

社員研修資料として活用できる

MS Learnで個人的な学習や調査に役立てることはもちろん、Office365と連携することで社内の人向けにラーニングパスを作成し、公開することもできるようです。 自分が詳しくないので詳細はわかりませんでしたが、LinkedInとの連携もできるみたいでした。 MS社員の方のツイートはこちらです。

オルターブースの小島さんがお話してくれました。

Azureに限らない普遍的な設計パターンを紹介してくれている

Azureアーキテクチャセンターがとても良いとお話してくれたのは
株式会社ゼンアーキテクツの三宅さんです。
アーキテクチャのプルダウンを開くと

があり、目的に応じて参考となるものを見る感じでしょうか。
三宅さんのおすすめはWell-Architectedフレームワークとのことで、こちらを参考にして設計をすることもあるようです。
ちらっと見るだけでもいろいろありますね。

クラウド導入フレームワークを利用するにはAssessmentsから入るのがおすすめとのことでした。
learn.microsoft.com

あと、そんなものまであるんだと驚いたのは業界ごとのソシューションがLearnで紹介されているという点です。
learn.microsoft.com Azureだと大企業への導入事例などがたくさんあり、そういった知見も社内に蓄積されているのかもしれないですね。

そのほかのおすすめ機能やドキュメント

日/英切り替えがワンクリックで出来る

地球儀みたいなマークをクリックすることで切り替えられるみたいです。
ずっとブラウザのバーでjpとかenって入れて切り替えていたので、ちょっと嬉しい。笑

AWS/GCPとAzureの比較を公開している

MS公式がこういったドキュメントを公開してくれているのはかなりありがたいですね。
活用する人多いんじゃないでしょうか。
AWS プロフェッショナルのための Azure - Azure Architecture Center | Microsoft Learn
Google Cloud プロフェッショナルのための Azure - Azure Architecture Center | Microsoft Learn

動画コンテンツもある

https://learn.microsoft.com/ja-jp/shows/
Learnだと表示される内容という表記でなんのこっちゃ?という感じですが、
英語版だとshowという表記みたいです。 イルカショーとかのショーってことで、動画で楽しく学べる感じっぽいです。

PDFでダウンロードができる

今まで存在自体を知らなかったのが、PDFファイルのダウンロード機能です。 画面左下のPDFをダウンロードボタンを押すと開いている技術に関連するドキュメントが一括でダウンロードされます。
Chromeでダウンロードを試しました。
最初ドキュメントの量に圧倒されたのですが、ブラウザで見ているとき同様に章で内容が分かれていて、これなら目的のページも探しやすそうですね。
これならタブレットにダウンロードしておいて、ちょっとしたときに見てみるという使い方もできそうです。

感想とか今後どうやって活用していくか

基本はshibayanさんが言っていたような、知りたいことが書いてあるページを見て意味が分からなかったらトレーニングページから入ってみる、 という使い方がよさそうだなと思っています。
今は意味が理解できない解説の場合にはChatGPTに該当の文言なりURLを渡して解説してもらいつつ、読んだりしているのですがおそらくトレーニングで基礎的な知識を確認してからの方がより深く定着できそうだと思いました。
もちろん、ChatGPTを使う方法も使いつつ、ケースバイケースでどちらが良いかという感じにはなるとは思いますが。
以前からギークな人たちはなんで公式ドキュメントを当然のように読めるのだろうと不思議だったんですが、そもそも公式ドキュメントをきちんと使い倒している印象で、ほしい知識だけつまみ食いするみたいな使い方だとそれは 前提知識が不足していたりすると「公式ドキュメント読みずらい!」になってしまうのだろうなと思いました。

そういえば、世界一流エンジニアの思考法でも理解に時間をかけるっていう話あったもんな...

なのでこれからは技術のキャッチアップの際には、できるだけ焦らずに丁寧に理解を深めながら進められたらいいな、と思います。
できないときはそれはそれで仕方ないですが。

登壇してお話してくださった小島さん、shibayanさん、三宅さんありがとうございました!

Azure Automationで作成済みの仮想マシンを自動起動するまで

この記事ではAzure Portal上でAutomation のRunbookを作成し、 Runbookのスケジュール機能で指定の日時で作成済みの仮想マシンまたはApp Serviceに対して自動起動を行うところまでを記載します。 今回Runbookに記載するスクリプトPowerShellを使用しています。

背景

仕事で動かしている開発環境の仮想マシンとApp Serviceのサーバーの起動/停止を自動化できると無駄な稼働を減らして節約できると思ったため。 もしそのようにしてほしいと依頼されたらすぐにできるように調べてみました。

大まかな手順や前提

  • 任意の仮想マシンを用意する(ここは割愛)
  • Automationアカウントを作成する
  • Automationに必要なアクセス許可を割り当てる
  • Automationに必要なモジュール(Azモジュール)を更新する(必要であれば)
  • Runbookを作成する
  • Runbookにコードを追加する
  • コードの動作確認
  • スケジュール機能の設定

以下のMicrosoft Learnを参考にしています。 learn.microsoft.com learn.microsoft.com 両方で試したのですが、今回はワークフローでの方法を記載します。 では、詳しく記載していきます。

Automationを作成する

Portal上でAutomationアカウントを作成します。 こちらのアイコンをクリックします。

Automationアカウントの作成ページで新規アカウントを作成します。 詳細設定タブではデフォルトでマネージドIDのシステム割り当てにチェックが入っているため、一旦何もしないで問題ありません。 ※マネージドIDはアクセス許可を割り当てる際に利用します。

Automationに必要なアクセス許可を割り当てる

アクセス許可を割り当てるには * Azure portal上で設定 * ローカルのPowerShellからコマンドで設定 の2つの方法がありますが、この記事ではPortal上で設定します。 PowerShellで設定するにはAzモジュールのインストールが必要となります。

Azure Poral上で以下の画面を表示し、Azure ロールの割り当てを選択します。

任意のロールを割り当てます。 画像の上二つはチュートリアルを見ながら設定しましたが、App Serviceへのアクセス権も付与したかったので リソースグループに対して共同作成者ロールも割り当てています。

Automationに必要なモジュールを更新する(必要であれば)

この手順はLearnにはないものの、やっておかないとPowerShellがエラーになってしまいました。 Automaitonアカウントのモジュール画面から以下のモジュールを更新します。 * Az.Accountsのバージョンを最新のものにする

Runbookを作成する

AutomaitonアカウントのRunbookを選択し、Runbookを作成します。 作成画面ではPowerShellワークフローを選択します。

Runbookにコードを追加する

作成したRunbookにPowerShellコードを追加します。 チュートリアルを見るといろいろあるのですが、ここでは実際に動作したコードを載せます。

workflow <WorkflowName>
{
            Param(
            [string]$resourceGroup,
            [string]$VMName
        )
    
    InlineScript{

        Import-Module Az
        
        # Ensures you do not inherit an AzContext in your runbook
        Disable-AzContextAutosave -Scope Process

        # Connect to Azure with system-assigned managed identity
        Connect-AzAccount -Identity

        # Usingスコープ修飾子を使用して外部変数を参照
        $resourceGroup = $Using:resourceGroup
        $VMName = $Using:VMName
        
        # set and store context
        $AzureContext = Set-AzContext –SubscriptionId "<SubscriptionID>"
        Start-AzVM -Name $VMName -ResourceGroupName $resourceGroup -DefaultProfile $AzureContext
    }
}

コードの

Start-AzVM

Start-AzWebApp

にするとApp Serviceの起動を行うことができます。

コードの動作確認

動作確認もPortal上で行います。 Runbookの編集画面からテストウィンドウを開き、引数に任意のリソースグループ名と仮想マシン名を入力します。 テストを実行し問題なければ以下のような表示がされます。

スケジュール機能の設定

最後に、作成したスクリプトをスケジュール機能で自動起動する方法を紹介します。 スケジュールからスケジュールの追加を選択します。

以下の画面からスケジュールとパラメータの設定を行います。

スケジュールは定期的な予定を作成することもできます。

パラメータではコードのテストの際に指定した値を保存します。

スケジュールで実行が正常に終了した場合、Runbookの概要ページで以下のように結果が残ります。

以上がAzure Automaitonで作成済みの仮想マシン自動起動するまでの手順です。 自動終了はスクリプトのStart-AzVMコマンドを書き換えるだけで動くと思いますので割愛します。 読んでいただきありがとうございました。

はてな開設

自己紹介

初めまして、ryoo03です。

子供ができてから朝に仕事(IT)関連の勉強などを行っていますが、せっかく勉強したのに忘れてしまったり、あとで振り返るのに何も残っていないともったいないなと思いブログを開設しました。

普段はPythonやAzure、SQL Serverを仕事で触っているのでそのあたりの記事を投稿できたらと思います。 今後、LinuxやDockerもある程度わかりたいのでそのあたりのことも記事にするかもしれません。

ブログが継続できそうだったら、有料版に移行したいなー。