Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyスタックトレースを読んで理解する

アプリケーションでエラーが発生すると、Rubyは例外を発生させ、スタックトレースを出力します。 ログに。この記事では、スタックトレースを読み取る方法と、それを使用してアプリケーションの例外の原因を特定する方法について説明します。

コールスタック

メソッドを呼び出すたびに、Rubyはスタックフレームを配置します コールスタック (または「ランタイムスタック」ですが、単に「スタック」と呼ばれることもあります)。スタックフレームは、メソッドの引数、内部変数用のスペース、および呼び出し元のリターンアドレスを保持するメモリ割り当てです。

# divide.rb
def divide(a, b)
  "Dividing #{a} by #{b} gives #{a / b}."
end
 
puts divide(8, 4)

1つのメソッド(divide )別のメソッド(Fixnum#/ 、または/ 略して)、後者は最初のものが終了する前に実行する必要があるため、スタックの一番上に置かれます。 divide(8, 4)を呼び出す場合 この例では、Rubyは次のアクションを順番に実行します。

  1. 8./(4)に電話する
  2. 部門の結果を収集します(2 )、文字列に入れます
  3. 文字列を収集します("Dividing 8 by 4 gives 2" )、putsを使用してコンソールに出力します

スタックトレース

スタックトレース (通常、Rubyでは「バックトレース」と呼ばれますが、「スタックバックトレース」および「スタックトレースバック」とも呼ばれます)は、プログラムの実行中の特定の瞬間におけるスタックの人間が読める表現です。 /への呼び出しのスタックトレース メソッドは次のようになり、divideで呼び出されたことを示します。 <main>で呼び出された2行目のメソッド 5行目のメソッド。

divide.rb:2:in `/'
divide.rb:2:in `divide'
divide.rb:5:in `<main>'

上記の例では、divideを呼び出しています 引数の1つとして0を指定したメソッドは、ZeroDivisionErrorになります。 例外。

# divide_by_zero.rb
def divide(a, b)
  "Dividing #{a} by #{b} gives #{a / b}."
end
 
puts divide(8, 0)

その場合、Rubyは例外をスタックトレースとともにコンソールに出力します。スタックトレースは、例外が発生した場所を特定するのに役立つように、コード内の各メソッドの場所とともに、人間が読める形式でスタックを示します。

$ ruby divide_by_zero.rb
divide_by_zero.rb:2:in `/': divided by 0 (ZeroDivisionError)
        from divide_by_zero.rb:2:in `divide'
        from divide_by_zero.rb:5:in `<main>'
  1. 上記のスタックトレースの最初の行で、ZeroDivisionErrorを確認できます。 メッセージとして「0で除算」で発生しました。例外自体に加えて、divide_by_zero.rb:2:in `/'で発生したことがわかります。 、これは、サンプルファイルの2行目から、/という名前のメソッドからエラーが発生したことを意味します。 (これはFixnum#/ 、最初の引数はFixnum 8であるため 。

  2. スタックトレースの2行目は、/の場所を示しています メソッドはから呼び出されました。この場合、それは私たちのdivideからのものです 2行目のメソッド。

  3. 最後の行は、divideであることを示しています <main>から呼び出されました 、Rubyアプリケーションの初期コンテキストを参照します。一般的には、「実際の」メソッドの外部から呼び出されたことを意味します。

:Ruby 2.5では、ロガーはスタックトレースを逆に印刷して、ターミナルウィンドウに合わせます。最後の行は例外を示しており、その前に例外が発生した行があります。その上の行は、スタックを上るルートです。

スタックトレースを理解する

スタックトレースは、例外が発生するたびにコールスタックの現在の状態のダンプを提供し、問題が発生した場所を見つけるのに役立ちます。

スタックトレースの最初の行には、例外が発生した行が表示されますが、エラーの原因が常に表示されるとは限りません。上記の例では、プログラムは正しく実行されましたが、divideに渡されたデータを処理できませんでした 方法。スタックトレースをたどると、それが呼ばれる場所につながります。これは 問題の原因。

いつものように、この記事がどのように気に入ったか、質問がある場合、次に何を読みたいかを知りたいので、@AppSignalまでお知らせください。


  1. Rbenv、RubyGems、Bundlerがどのように連携するかを理解する

    Rubyでの依存関係の管理には、通常、プロジェクトが依存するRubyとgemのバージョンを指定することが含まれます。 Rubyでの作業経験では、依存関係のデバッグは私の最大の課題の1つです。多くのものが「うまくいく」ので、失敗は一般的ではありません。ただし、問題が発生した場合、通常、デバッグと修正は不必要に困難になります。この記事では、Rubyの依存関係管理に関連する部分について説明します。これは、これらの奇妙な問題が発生したときにデバッグするのに役立ちます。 ルビーコードの読み込み デフォルトでは、Ruby言語は、他の場所で定義されたコードをロードするための2つの主要なメソッドを提供

  2. Rubyでの挿入ソートを理解する

    注:これは、Rubyを使用したさまざまなソートアルゴリズムの実装を検討するシリーズのパート4です。パート1ではバブルソート、パート2では選択ソート、パート3ではマージソートについて説明しました。 データを並べ替えるためのさまざまな方法を引き続き検討するため、挿入並べ替えに目を向けます。挿入ソートが好きな理由はたくさんあります!まず、挿入ソートは安定です。 、これは、等しいキーを持つ要素の相対的な順序を変更しないことを意味します。 インプレースアルゴリズムでもあります 、は、並べ替えられた要素を格納するための新しい配列を作成しないことを意味します。最後に、挿入ソートは、すぐにわかるように、実