コマンドラインから長いRスクリプト(R --slave script.R)を実行している場合、エラー時に行番号を取得するにはどうすればよいですか?
可能な限り、スクリプトにデバッグコマンドを追加したくありません。Rを他のほとんどのスクリプト言語のように動作させたいだけです...
コマンドラインから長いRスクリプト(R --slave script.R)を実行している場合、エラー時に行番号を取得するにはどうすればよいですか?
可能な限り、スクリプトにデバッグコマンドを追加したくありません。Rを他のほとんどのスクリプト言語のように動作させたいだけです...
回答:
これでは行番号はわかりませんが、コールスタックのどこでエラーが発生したかがわかり、非常に役立ちます。
traceback()
[編集:]コマンドラインからスクリプトを実行する場合、1つまたは2つの呼び出しをスキップする必要があります。インタラクティブおよび非インタラクティブRセッションについてはtraceback()を参照してください
私は通常のデバッグの容疑者なしでこれを行う別の方法を知りません:
[編集:]申し訳ありません...コマンドラインからこれを実行しているのを見ただけです。その場合、options(error)機能を使用することをお勧めします。以下に簡単な例を示します。
options(error = quote({dump.frames(to.file=TRUE); q()}))
エラー状態で必要なだけスクリプトを作成できるので、デバッグに必要な情報を決定するだけです。
それ以外の場合、気になる特定の領域がある場合(データベースへの接続など)、それらをtryCatch()関数でラップします。
options(error=function() { traceback(2); if(!interactive()) quit("no", status = 1, runLast = FALSE) })
(承認された回答のコメントを参照)。別のスレッドへのリンクを提供するだけでなく、ここで回答に追加するのが理にかなっていると思います。
実行options(error=traceback)
すると、エラーが発生するまでの行の内容について、もう少し情報が提供されます。エラーがある場合はトレースバックが表示され、一部のエラーでは行番号が先頭に付き#
ます。しかし、それはヒットまたはミスであり、多くのエラーは行番号を取得しません。
No traceback available
。エラーの後に表示されます。
このサポートは、R 2.10以降で予定されています。Duncan Murdochが2009年9月10日にfindLineNumおよびsetBreapointについてr-develに投稿したばかりです。
デバッグを支援するために、R-develにいくつかの関数を追加しました。
findLineNum()
どの関数のどの行がソースコードの特定の行に対応するかを見つけます。setBreakpoint()
の出力を受け取り、そこにブレークポイントを設定するためのfindLineNum
呼び出しtrace()
を行います。これらは、コードにソース参照デバッグ情報があることに依存しています。これは
source()
、が読み取るコードのデフォルトですが、パッケージのデフォルトではありません。パッケージコードでソース参照を取得するには、環境変数を設定するR_KEEP_PKG_SOURCE=yes
か、R内でsetを設定してoptions(keep.source.pkgs=TRUE)
から、ソースコードからパッケージをインストールします。?findLineNum
検索をグローバル環境に限定するのではなく、パッケージ内を検索するように指示する方法の詳細を読んでください。例えば、
x <- " f <- function(a, b) { if (a > b) { a } else { b } }" eval(parse(text=x)) # Normally you'd use source() to read a file... findLineNum("<text>#3") # <text> is a dummy filename used by parse(text=)
これは印刷されます
f step 2,3,2 in <environment: R_GlobalEnv>
そしてあなたは使うことができます
setBreakpoint("<text>#3")
そこにブレークポイントを設定します。
コードにはまだいくつかの制限(そしておそらくバグ)があります。私はこれを修正します
あなたは設定することによってそれを行います
options(show.error.locations = TRUE)
この設定がRのデフォルトではないのはなぜですか。それは他のすべての言語であるので、そうあるべきです。
致命的ではないエラーを処理するためのグローバルRオプションを指定することは、エラーに関する情報を保持し、障害後にこの情報を調べるためのカスタマイズされたワークフローとともに、私にとってはうまくいきました。現在Rバージョン3.4.1を実行しています。以下に、私のために機能したワークフローの説明と、Rでグローバルエラー処理オプションを設定するために使用したいくつかのコードを含めました。
私が設定したように、エラー処理は、エラー発生時に作業メモリ内のすべてのオブジェクトを含むRDataファイルも作成します。このダンプはを使用してRに読み戻すload()
ことができ、エラー発生時に存在していたさまざまな環境を、を使用してインタラクティブに検査できますdebugger(errorDump)
。
traceback()
スタック内の任意のカスタム関数からの出力で行番号を取得できたことに注意します。ただし、スクリプトで使用される任意のカスタム関数をkeep.source=TRUE
呼び出すときにオプションを使用した場合のみですsource()
。このオプションがない場合、グローバルエラー処理オプションを以下のように設定すると、の完全な出力がtraceback()
というエラーログに送信されますerror.log
が、行番号は利用できませんでした。
ワークフローで行った一般的な手順と、非対話型Rの失敗後にメモリダンプとエラーログにアクセスする方法を次に示します。
コマンドラインから呼び出すメインスクリプトの先頭に次のコードを追加しました。これにより、Rセッションのグローバルエラー処理オプションが設定されます。私のメインスクリプトはと呼ばれていましたmyMainScript.R
。コードのさまざまな行の後には、その内容を説明するコメントがあります。基本的に、このオプションでは、Rがをトリガーするエラーに遭遇するstop()
と、ディレクトリ内のすべてのアクティブな環境全体で作業メモリのRData(* .rda)ダンプファイルを作成し、いくつかの有用な情報を~/myUsername/directoryForDump
含むエラーログをerror.log
同じディレクトリ。このスニペットを変更して、エラーに対するその他の処理を追加できます(たとえば、ダンプファイルにタイムスタンプを追加したり、エラーログファイル名を追加したりできます)。
options(error = quote({
setwd('~/myUsername/directoryForDump'); # Set working directory where you want the dump to go, since dump.frames() doesn't seem to accept absolute file paths.
dump.frames("errorDump", to.file=TRUE, include.GlobalEnv=TRUE); # First dump to file; this dump is not accessible by the R session.
sink(file="error.log"); # Specify sink file to redirect all output.
dump.frames(); # Dump again to be able to retrieve error message and write to error log; this dump is accessible by the R session since not dumped to file.
cat(attr(last.dump,"error.message")); # Print error message to file, along with simplified stack trace.
cat('\nTraceback:');
cat('\n');
traceback(2); # Print full traceback of function calls with all parameters. The 2 passed to traceback omits the outermost two function calls.
sink();
q()}))
メインスクリプトと後続の関数呼び出しから、関数がソースされるときはいつでも、オプションkeep.source=TRUE
が使用されていることを確認してください。つまり、関数をソースするには、を使用しますsource('~/path/to/myFunction.R', keep.source=TRUE)
。これは、traceback()
出力に行番号を含めるために必要です。を使用してこのオプションをグローバルに設定することもできるようですがoptions( keep.source=TRUE )
、動作するかどうかを確認するためのテストは行っていません。行番号が必要ない場合は、このオプションを省略できます。
Rscript myMainScript.R
。これにより、新しい非インタラクティブRセッションが開始され、スクリプトが実行されますmyMainScript.R
。上部に配置されている手順1のコードスニペットmyMainScript.R
は、非インタラクティブRセッションのエラー処理オプションを設定します。myMainScript.R
。これはメインスクリプト自体にあるか、いくつかの関数がネストされています。エラーが発生すると、手順1で指定されたように処理が実行され、Rセッションが終了します。errorDump.rda
およびという名前のRDataダンプファイルが、グローバルエラー処理オプション設定でerror.log
指定されたディレクトリに作成され'~/myUsername/directoryForDump'
ます。暇なときにerror.log
、エラーメッセージ自体やエラーの原因となった完全なスタックトレースなど、エラーに関する情報を確認してください。エラー時に生成されるログの例を次に示します。#
文字の後の数字は、呼び出しスタックのさまざまなポイントでのエラーの行番号です。
Error in callNonExistFunc() : could not find function "callNonExistFunc"
Calls: test_multi_commodity_flow_cmd -> getExtendedConfigDF -> extendConfigDF
Traceback:
3: extendConfigDF(info_df, data_dir = user_dir, dlevel = dlevel) at test_multi_commodity_flow.R#304
2: getExtendedConfigDF(config_file_path, out_dir, dlevel) at test_multi_commodity_flow.R#352
1: test_multi_commodity_flow_cmd(config_file_path = config_file_path,
spot_file_path = spot_file_path, forward_file_path = forward_file_path,
data_dir = "../", user_dir = "Output", sim_type = "spot",
sim_scheme = "shape", sim_gran = "hourly", sim_adjust = "raw",
nsim = 5, start_date = "2017-07-01", end_date = "2017-12-31",
compute_averages = opt$compute_averages, compute_shapes = opt$compute_shapes,
overwrite = opt$overwrite, nmonths = opt$nmonths, forward_regime = opt$fregime,
ltfv_ratio = opt$ltfv_ratio, method = opt$method, dlevel = 0)
暇なときに、errorDump.rda
を使用してインタラクティブなRセッションに読み込むことができますload('~/path/to/errorDump.rda')
。ロードされたら、呼び出しdebugger(errorDump)
て、アクティブな環境のいずれかでメモリ内のすべてのRオブジェクトを参照します。詳細については、Rのヘルプを参照してdebugger()
ください。
このワークフローは、コマンドラインで非インタラクティブRセッションが開始されていて、予期しないエラーに関する情報を保持したい、ある種の運用環境でRを実行する場合に非常に役立ちます。エラー発生時にワーキングメモリを検査するために使用できるファイルにメモリをダンプする機能と、コールスタックにエラーの行番号を含めることにより、エラーの原因を迅速に事後的にデバッグできます。