Getting a Stack Trace

When reporting a bug for an exception or a wrong behavior in code, it is crucial that you provide one or several stack traces. To understand why, you first have to understand what a stack trace is, and how it can be useful to you as a developer, and also to library maintainers.

コード内の例外または間違った動作のバグを報告する場合、1 つまたは複数のスタック トレースを提供することが重要です。その理由を理解するには、まずスタック トレースとは何か、また、スタック トレースが開発者やライブ​​ラリ メンテナーにとってどのように役立つかを理解する必要があります。

Anatomy of a Stack Trace

A stack trace is called that way because it allows one to see a trail of function calls leading to a point in code since the beginning of the program. That point is not necessarily an exception. For instance, you can use the native PHP function debug_print_backtrace() to get such a trace. For each line in the trace, you get a file and a function or method call, and the line number for that call. This is often of great help for understanding the flow of your program and how it can end up in unexpected places, such as lines of code where exceptions are thrown.

スタック トレースがそのように呼び出されるのは、プログラムの開始以降、コード内のあるポイントにつながる関数呼び出しの軌跡を確認できるためです。その点は必ずしも例外ではありません。たとえば、ネイティブ PHP 関数 debug_print_backtrace() を使用して、そのようなトレースを取得できます。トレースの各行について、ファイルと関数またはメソッドの呼び出し、およびその呼び出しの行番号を取得します。これは、プログラムの流れと、例外がスローされるコード行など、予期しない場所でプログラムがどのように終了するかを理解するのに非常に役立ちます。

Stack Traces and Exceptions

In PHP, every exception comes with its own stack trace, which is displayed by default if the exception is not caught. When using Symfony, such exceptions go through a custom exception handler, which enhances them in various ways before displaying them according to the current Server API (CLI or not). This means a better way to get a stack trace when you do not need the program to continue is to throw an exception, as follows: throw new \Exception();

PHP では、すべての例外に独自のスタック トレースが付属しており、例外がキャッチされない場合、デフォルトで表示されます。 Symfony を使用する場合、そのような例外はカスタム例外ハンドラーを通過し、現在のサーバー API (CLI またはそれ以外) に従って表示する前に、さまざまな方法でそれらを拡張します。これは、プログラムを続行する必要がない場合にスタック トレースを取得するためのより良い方法を意味します。次のように例外をスローすることです。throw new \Exception();

Nested Exceptions

When applications get bigger, complexity is often tackled with layers of architecture that need to be kept separate. For instance, if you have a web application that makes a call to a remote API, it might be good to wrap exceptions thrown when making that call with exceptions that have special meaning in your domain, and to build appropriate HTTP exceptions from those. Exceptions can be nested by using the $previous argument that appears in the signature of the Exception class: public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] ) This means that sometimes, when you get an exception from an application, you might actually get several of them.

アプリケーションが大きくなると、多くの場合、分離しておく必要があるアーキテクチャのレイヤーによって複雑さが解消されます。たとえば、リモート API を呼び出す Web アプリケーションがある場合、その呼び出しを行ったときにスローされる例外をドメイン内で特別な意味を持つ例外でラップし、それらから適切な HTTP 例外を構築するとよいでしょう。 Exception クラスのシグネチャに現れる $previousargument を使用して、例外をネストできます: public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] ) これは、次のことを意味します。場合によっては、アプリケーションから例外を取得すると、実際にはいくつかの例外を取得することがあります。

What to look for in a Stack Trace

When using a library, you will call code that you did not write. When using a framework, it is the opposite: because you follow the conventions of the framework, the framework finds your code and calls it, and does things for you beforehand, like routing or access control. Symfony being both a framework and library of components, it calls your code and then your code might call it. This means you will always have at least 2 parts, very often 3 in your stack traces when using Symfony: a part that starts in one of the entry points of the framework (bin/console or public/index.php in most cases), and ends when reaching your code, most times in a command or in a controller found under src. Then, either the exception is thrown in your code or in libraries you call. If it is the latter, there should be a third part in the stack trace with calls made in files under vendor. Before landing in that directory, code goes through numerous review processes and CI pipelines, which means it should be less likely to be the source of the issue than code from your application, so it is important that you focus first on lines starting with src, and look for anything suspicious or unexpected, like method calls that are not supposed to happen.

ライブラリを使用すると、自分が書いていないコードを呼び出すことになります。フレームワークを使用する場合は逆です。フレームワークの規則に従うため、フレームワークはコードを見つけて呼び出し、ルーティングやアクセス制御などの処理を事前に行います。Symfony はフレームワークとコンポーネントのライブラリの両方であるため、 yourcode と、コードがそれを呼び出す可能性があります。これは、Symfony を使用する場合、スタック トレースに常に少なくとも 2 つの部分、非常に多くの場合 3 つがあることを意味します。フレームワークのエントリ ポイントの 1 つで始まる部分 (ほとんどの場合、bin/console または public/index.php)、およびほとんどの場合、コマンドまたは src の下にあるコントローラーで、コードに到達したときに終了します。次に、コードまたは呼び出したライブラリ内で例外がスローされます。後者の場合、ベンダーの下のファイルで行われた呼び出しを含む 3 番目の部分がスタック トレースにあるはずです。そのディレクトリに到達する前に、コードは多数のレビュー プロセスと CI パイプラインを通過します。つまり、アプリケーションのコードよりも問題の原因となる可能性は低いはずです。そのため、最初に src で始まる行に注目し、疑わしいものを探すことが重要です。または予期しない、発生するはずのないメソッド呼び出しなど。

Next, you can have a look at what packages are involved. Files under vendor are organized by Composer in the following way: vendor/acme/router where acme is the vendor, router the library and acme/router the Composer package. If you plan on reporting the bug, make sure to report it to the library throwing the exception. composer home acme/router should lead you to the right place for that. As Symfony is a mono-repository, use composer home symfony/symfony when reporting a bug for any component.

次に、どのパッケージが関係しているかを確認できます。ベンダーのファイルは Composer によって次のように編成されます:vendor/acme/router (acme はベンダー、router はライブラリ、acme/router は Composer パッケージ)。バグを報告する予定がある場合は、例外をスローしているライブラリに必ず報告してください。 composer home acme/router は、そのための適切な場所に導くはずです。 Symfony は単一リポジトリであるため、コンポーネントのバグを報告する場合は composer homesymfony/symfony を使用してください。

Getting Stack Traces with Symfony

Now that we have all this in mind, let us see how to get a stack trace with Symfony.

これらすべてを念頭に置いたので、Symfony でスタック トレースを取得する方法を見てみましょう。

Stack Traces in your Web Browser

Several things need to be paid attention to when picking a stack trace from your development environment through a web browser:

Web ブラウザーを介して開発環境からスタック トレースを選択する場合、いくつかの点に注意する必要があります。
  1. Are there several exceptions? If yes, the most interesting one is often exception 1/n which, is shown last in the example below (it is the one marked as an exception [1/2]).
    いくつかの例外はありますか?はいの場合、最も興味深いのは例外 1/n であることが多く、以下の例で最後に示されています (例外 [1/2] としてマークされているものです)。
  2. Under the "Stack Traces" tab, you will find exceptions in plain text, so that you can easily share them in e.g. bug reports. Make sure to remove any sensitive information before doing so.
    「スタック トレース」タブでは、平文で例外を見つけることができるため、例: などで簡単に共有できます。バグ報告。そうする前に、機密情報を削除してください。
  3. You may notice there is a logs tab too; this tab does not have to do with stack traces, it only contains logs produced in arbitrary places in your application. They may or may not relate to the exception you are getting, but are not what the term "stack trace" refers to.
    ログタブもあることに気付くかもしれません。このタブは、スタック トレースを扱う必要はありません。アプリケーションの任意の場所で生成されたログのみが含まれます。それらは、取得している例外に関連する場合と関連しない場合がありますが、「スタック トレース」という用語が指すものではありません。

Since stack traces may contain sensitive data, they should not be exposed in production. Getting a stack trace from your production environment, although more involving, is still possible with solutions that include but are not limited to sending them to an email address with Monolog.

スタック トレースには機密データが含まれている可能性があるため、本番環境では公開しないでください。実稼働環境からスタック トレースを取得することは、より複雑ではありますが、Monolog を使用して電子メール アドレスに送信することを含むがこれに限定されないソリューションを使用することで可能です。

Stack Traces in the CLI

Exceptions might occur when running a Symfony command. By default, only the message is shown because it is often enough to understand what is going on:

Symfony コマンドの実行時に例外が発生する場合があります。デフォルトでは、何が起こっているかを理解するのに十分な場合が多いため、メッセージのみが表示されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ php bin/console debug:exception


   Command "debug:exception" is not defined.

   Did you mean one of these?
       debug:autowiring
       debug:config
       debug:container
       debug:event-dispatcher
       debug:form
       debug:router
       debug:translation
       debug:twig

If that is not the case, you can obtain a stack trace by increasing the verbosity level with --verbose:

そうでない場合は、--verbose を使用して詳細レベルを上げると、スタック トレースを取得できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ php bin/console --verbose debug:exception

 In Application.php line 644:

   [Symfony\Component\Console\Exception\CommandNotFoundException]
   Command "debug:exception" is not defined.

   Did you mean one of these?
       debug:autowiring
       debug:config
       debug:container
       debug:event-dispatcher
       debug:form
       debug:router
       debug:translation
       debug:twig


 Exception trace:
   at /app/vendor/symfony/console/Application.php:644
  Symfony\Component\Console\Application->find() at /app/vendor/symfony/framework-bundle/Console/Application.php:116
  Symfony\Bundle\FrameworkBundle\Console\Application->find() at /app/vendor/symfony/console/Application.php:228
  Symfony\Component\Console\Application->doRun() at /app/vendor/symfony/framework-bundle/Console/Application.php:82
  Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /app/vendor/symfony/console/Application.php:140
  Symfony\Component\Console\Application->run() at /app/bin/console:42

Stack Traces and API Calls

When getting an exception from an API, you might not get a stack trace, or it might be displayed in a way that is not suitable for sharing. Luckily, when in the dev environment, you can obtain a plain text stack trace by using the profiler. To find the profile, you can have a look at the X-Debug-Token-Link response headers:

API から例外を取得する場合、スタック トレースが取得されないか、共有に適していない方法で表示される場合があります。幸い、開発環境では、プロファイラーを使用してプレーン テキストのスタック トレースを取得できます。 .プロファイルを見つけるには、X-Debug-Token-Link 応答ヘッダーを調べます。
1
2
3
4
5
6
$ curl --head http://localhost:8000/api/posts/1
… more headers
X-Debug-Token: 110e1e
X-Debug-Token-Link: http://localhost:8000/_profiler/110e1e
X-Robots-Tag: noindex
X-Previous-Debug-Token: 209101

Following that link will lead you to a page very similar to the one described above in Stack Traces in your Web Browser.

そのリンクをたどると、上記の「Web ブラウザのスタック トレース」によく似たページが表示されます。