質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.40%
コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

638閲覧

Pythonで構築したUIなしのEXE、実行時に生じたエラーを遡って把握するにはどうすれば良い?

saya24

総合スコア243

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2024/05/25 05:31

編集2024/05/26 05:59

実現したいこと

UIありの構築物であれば画面にエラー内容をダイアログで表示することができたし、UIなしの構築物であっても、今までは結果が思わしくなければうまくいくまで調整を繰返してゴールを導くのが常でした。
恥を忍んでお聞きします、表題の実現方法・パターンを把握したいので教えて頂けますでしょうか。

【具体的な例を示すと】
以下Pythonのプログラムは 国土交通省から市町村コードの一覧を取得するために 自分が先日作ったものです。(動作内容は正直なんでもよい、今回の問合せ主旨からすると)

国土交通省のAPIを実行するために必要な詳細情報、またこのプログラムを実行した際に得られるテキストファイルの固定名を、当該プログラムは 別途の定義ファイル(config.ini)を参照して取得する作りになっています。

python

1import json 2from unittest import result 3from gql import gql, Client 4from gql.transport.aiohttp import AIOHTTPTransport 5 6import configparser 7import os 8import sys 9 10def get_Config(): 11 try: 12 # -------------------------------------------------- 13 # configparserの宣言とiniファイルの読み込み 14 # -------------------------------------------------- 15 curpath = os.path.dirname(os.path.realpath(sys.argv[0])) 16 cfgpath = os.path.join(curpath, "config.ini") 17 18 config_ini = configparser.ConfigParser() 19 config_ini.read(cfgpath, encoding='utf-8') 20 21 # -------------------------------------------------- 22 # config,iniから値取得 23 # -------------------------------------------------- 24 var1 = config_ini['DPF']['KEYITEM'] 25 var2 = config_ini['DPF']['APIKEY'] 26 var3 = config_ini['DPF']['URL'] 27 var4 = config_ini['OUTPUT']['FILEPATH'] 28 return var1, var2, var3, var4 29 except Exception: 30 raise 31 32 33def req_URL(): 34 35 try: 36 lst_config = get_Config() 37 38 39 headers = {lst_config[0] : lst_config[1]} 40 transport = AIOHTTPTransport(url=lst_config[2], headers=headers) 41 client = Client(transport=transport) 42 43 query = gql(""" 44 query{ 45 municipalities { 46 code 47 prefecture_code 48 name 49 } 50 } 51 """) 52 53 result = client.execute(query) 54 arrLst = result["municipalities"] 55 56 path_w = lst_config[3] 57 with open(path_w, mode='w') as f: 58 59 for ccDct in arrLst: 60 61 rec = "" 62 for col in ccDct.values(): 63 rec = rec + str(col) + "," 64 rec = rec[:-1] + "\n" 65 66 f.write(rec) 67 except Exception as e: 68 print ('??? ' + str(e) + ' ???') 69 sys.exit(1) 70 71if __name__ == '__main__': 72 req_URL() 73

★以下は あえて定義ファイルを存在させない状態での実行状況です★
VisualStudio2022上でのデバッグ実行時の状況)
VS2022デバッグ実行
当該プログラムを--noconsolのオプション付きでEXE化し、コマンドプロンプト経由で実行
イメージ説明

発生している問題・分からないこと

上記のとおり、デバッグ実行時であれば異常終了した旨の把握/エラー要因の推察(定義ファイル参照できずKeyError)が可能ですが、後方のEXE化された構築物の実行パターンでは異常の検知・要因特定が行えない印象をもっています。
(sys.exitで異常終了させたのだから、標準エラー出力の確認で窺いしることができると推察も違う?)

後方のEXE化された実行パターンでも、実行後に異常がおきたことの把握・エラー内容の把握を行うにはどういった解決策があるのでしょうか?
尚、表題の「遡って」の意味合いは 当該EXEが
・人系の手動実行に留まらなくタスクスケジューラからの未明起動もありえること
・別の後続処理を有し、実行結果次第では後続処理を起動させない判断が必要になること(DB出力等)
に由来しての問合せとなっています。

把握したいの一言で、どうあるべきかがわかっていないのですが
標準エラー出力 というものから実行結果を判断し、要因特定用にストックトレースと呼ばれるものを個別のログファイルかWindowsのイベントログに出力する感じになるのでしょうか?
(だとすると、今回 %errorlevel%が 0で戻ってきている理由だけ明確にすればよい??)

該当のソースコード

特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

色々とネット上で調べて、標準エラー出力という概念やPython内のsys.exit(1)の記述で強制終了を達成できることは把握できましたが
自分の頭の中で話が結び付きません。

補足

ひょっとして、最初から自分が 勘違いしていただけかな、とか思いだしています。
イメージ説明

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiroki-o

2024/05/25 05:53

自分でログファイルに出力するのが一番簡単だと思います。
melian

2024/05/25 11:04 編集

以下は参考情報です。 > --noconsolのオプション付きでEXE化 … EXE化された構築物の実行パターンでは異常の検知・要因特定が行えない Using PyInstaller - Windows And Mac Os X Specific Options -w, --windowed, --noconsole https://pyinstaller.org/en/stable/usage.html#cmdoption-w > Windows and Mac OS X: do not provide a console window for standard i/o. つまり、--noconsole を付けて EXE ファイルを作成すると stdout/stderr への出力は破棄されることになります。(NUL へ出力)
saya24

2024/05/25 13:20

hiroki-oさん 貴重なコメントをありがとうございます。 --noconsolをオプションにつけた場合は 標準出力結果を 得られないんですね。 勉強になりました。
bsdfan

2024/05/26 03:52

start /wait で終了を待つようにしたら、終了コードを取得できないでしょうか。 start /wait hoge.exe echo %ERRORLEVEL%
saya24

2024/05/26 04:56

bsdfanさん、ご見解ありがとうございます。 start /wait hoge.exe echo %ERRORLEVEL% を試したら、「1」が返ってきました。
ikedas

2024/05/26 06:24

まずはEXE化しないで実行してみればいいと思います。当然実行するPCにPythonをインストールしなければなりませんが、それで正しく動作することを十分に確認してからEXE化すればいいのではないですか。 Pythonはもともとコンソールなどへの出力ができるOSを前提に設計されましたから、コンソール出力を前提としないOSに合わせてコンソール出力を潰してしまったら十分な動作確認はできません。
guest

回答2

0

後方のEXE化された実行パターンでも、実行後に異常がおきたことの把握・エラー内容の把握を行うにはどういった解決策があるのでしょうか?

適切なタイミングで適切な内容のログを出力するようにすれのはどうでしょうか。
pythonにはloggerという、それを目的としたモジュールも存在します。レベルによって出力内容を選択する機能もありますので、通常運用時・問題再現待ち時などで出力内容を変更できます。
また、tracebackモジュールを使うことで、例外発生時の情報をログなどに含めることもできます。

の後続処理を有し、実行結果次第では後続処理を起動させない判断

リターンコードを使うことが一般的と思いますが、複雑な判断が必要であれば、どこかに結果情報をファイルや標準出力に出すようにしてそれを解析するなど。

投稿2024/05/25 06:09

編集2024/05/26 02:41
TakaiY

総合スコア13337

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saya24

2024/05/25 09:03 編集

コメントをありがとうございます。 当方が示した%errorlevel%のechoは0を返しているのはなぜなんでしょうか? まずは成功だったか否かを仰られるように標準出力しているつもりでしたが。
saya24

2024/05/25 09:10

これをリターンコードというんじゃないのかな?
TakaiY

2024/05/26 02:44

windowslではerrorlevel変数がリターンコードを保持しています。
guest

0

ベストアンサー

「コンソールプログラムであれば、問題なくデバッグできるのに、コンソール無し(GUIアプリ)だとそれが難しい」
というのが問題ポイントであれば、開発中または障害が起こってのデバッグの際は--noconsoleを付けずにコンソールプログラムとして作るというのが簡単な方法です。
ただし、
・本番稼働中に起こった障害が再現せず、本番稼働中にも記録を残しておきたかった
・コンソール無しプログラムだと障害を再現できるが、コンソールプログラムにすると再現しない
という場合は駄目ですが。

また、標準出力、標準エラー出力が失われることが問題であれば、プログラム冒頭で、

Python

1import sys 2sys.stdout = open("D:/var/log/foo-stdout.log","a") 3sys.stderr = open("D:/var/log/foo-stderr.log","a")

のようにすることで、ファイルに書くことが出来ます。もしコンソールがあれば標準エラー出力にメッセージを出して終了するようなケースだと、ファイルに書かれて終了します。

あるいは、障害が自分で事前に検知できるなら、自分で情報を各種モジュールを使って記録したり、場合によってはダイアログを出したりすれば良いかと思います。

今回 %errorlevel%が 0で戻ってきている理由だけ明確にすればよい??

GUIプログラム/コンソール無しプログラムをコマンドプロンプトやPowershellコンソールで起動しても、すぐにプロンプトが返ってくるので、そこでERRORLEVELを表示させても今実際に動き続けているプログラムとは無関係に1つ前の値が返ります。
(すべてのGUIプログラム/コンソール無しプログラムがそうなのかは未確認)
コマンドプロンプトでキーインしての実行例:

CMD

1Z:\TEMP>python -c "import sys;sys.exit(123)" 2Z:\TEMP>echo %ERRORLEVEL% 3123 4Z:\TEMP>pythonw -c "import time;time.sleep(30)" 5Z:\TEMP> ・・・・・30秒経たずにプロンプトはすぐ表示される 6Z:\TEMP>echo %ERRORLEVEL% 7123 ・・・・さっきのpythonの結果 8Z:\TEMP>

下記のようなバッチファイルを作れば30秒後に 0 が表示されますので、コンソール無しプログラムのERRORLEVELを見たい時はバッチにすると良いでしょう。

CMD

1python -c "import sys;sys.exit(123)" 2echo %ERRORLEVEL% 3pythonw -c "import time;time.sleep(30)" 4echo %ERRORLEVEL%

ただし、電卓(calc.exe)のようなものは、バッチから起動してもすぐ終わります。これは本体処理を子プロセスで実行して親プロセスはすぐに終了しているのでしょう。

投稿2024/05/25 14:25

編集2024/05/25 14:46
otn

総合スコア85458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saya24

2024/05/26 05:38

otnさん いつもお世話になっております。 ご提示の内容を バッチファイルにして試すと おっしゃられる様に30秒後に ECHOが返ってきました お陰様で 今回当方が コマンドプロンプトで実験用のEXEを実行後、別途の指示で%ERRORLEVEL%の内容を確認しにいっていることで 混乱を招いていることに気づきました。 補足部分に 追記しますが、 タスクスケジューラで、今回例にしたEXE(外部コンフィグファイルの参照に失敗する挙動)を動作させてみたところ、しっかり前回の処理結果部分に 異常が記録されていることが判明しました。 この状況だったら、成功だったか否かはログファイルを出力するようにせずとも把握することができそうですね?? 失敗時に要因特定のために詳細を把握したい場合に、ログファイルが必要になるわけで、それを考慮してログファイルの出力必要性を 検討すれば良さそうですね。
otn

2024/05/26 11:09

タスクスケジューラーからの起動であれば、そうですね。実行終わるまでは実行中というステータスで、実行終わればリターンの値がそこに表示される。 ERRORLEVELだけ分かれば良いのであれば、「SCHTASKS /query /tn タスク名 /v」で取得できますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.40%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問