10. Debug Laravel local & in prod. Laravel Telescope and Log viewer. Authentication for Horizon

Video version
(Leave your feedback on YouTube)

Laravel Telescope

The easiest and most convenient way to debug Laravel locally is Laravel Telescope.

The documentation is sufficient, but I have a few tips:

ALWAYS install it for local work only. Telescope records absolutely everything, every action. The database, even for a single developer locally, grows very quickly. Optimization also drops significantly. For production, set up LogViewer and external services like Sentry, New Relic...

Add public/vendor to .gitignore. Publish the web view with post-install-cmd and post-update-cmd. This applies to all packages with a web view. All packages going into production should be published as a step in the CI script.

dump is a useful Telescope feature that doesn't work with the file Cache Driver. However, it works with TELESCOPE_DUMP_WATCHER_ALWAYS set to true.

Add health check commands and routes to ignore_paths in config/telescope.php. This will reduce spam in Telescope reports.

Laravel Log Viewer

Debugging production can only be done with logs. Nothing else has been invented yet.

For production monitoring, I recommend using external services like NewRelic or Sentry.

For debugging - logs. Reading logs on the server is inconvenient and unsafe.

Minimize the number of people who have access to the server.

For logs, I recommend the Laravel Log Viewer package.

It provides:

  • A convenient web view by default at /log-view.
  • The ability to read not only laravel log files but also nginx, supervisor, php, etc.
  • Control over access to specific log files and the ability to delete log files. This will prevent malicious actors from deleting logs through the web view.

The same advice applies as for Telescope, Horizon, and any package with a web view. Add to update and insert composer hooks:

{
  "scripts": {
    "post-install-cmd": [
      "@php artisan vendor:publish --tag=log-viewer-assets --ansi --force"
    ],
    "post-update-cmd": [
      "@php artisan vendor:publish --tag=log-viewer-assets --ansi --force"
    ]
  }
}

And don't forget that Log Viewer assets need to be published when releasing to production or staging - php artisan vendor:publish --tag=log-viewer-assets --ansi --force.

And a tip for logs - enable daily logs immediately. The logger will create a log file for each day. This will make navigation easier and the file size smaller.

LOG_CHANNEL=daily

Horizon, LogViewer Authorization

Logs, queue information, queue logs - contain personal information and information that can help malicious actors gain access to the project. Closing dashboards is a must.

All packages with a web view should be protected from user access.

I highly recommend opening them only for corporate VPN IP addresses! This will provide access control for employees and is very easy to configure.

If VPN is not an option - implement your own authorization. A very simple way is to use the Laravel Very Basic Auth package.

Minimal configuration:

BASIC_AUTH_USERNAME=
BASIC_AUTH_PASSWORD=

If login and password are left empty, no authorization is required, which is convenient for local work.

Next, it is very simple to add VeryBasicAuth to the middleware for Horizon:

'middleware' => [
    'web',
    \Olssonm\VeryBasicAuth\Http\Middleware\VeryBasicAuth::class
]

For LogViewer. Publish the log-viewer config and add VeryBasicAuth to middleware and api_middleware:

 'middleware' => [
    'web',
    \Opcodes\LogViewer\Http\Middleware\AuthorizeLogViewer::class,
    \Olssonm\VeryBasicAuth\Http\Middleware\VeryBasicAuth::class
],
'api_middleware' => [
    \Opcodes\LogViewer\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    \Opcodes\LogViewer\Http\Middleware\AuthorizeLogViewer::class,
    \Olssonm\VeryBasicAuth\Http\Middleware\VeryBasicAuth::class
],

And one more tip. Change the default routes for admin panels in production. For local development, it is better to leave the defaults.

For Horizon:

HORIZON_PATH=some_complex_string_hash_is_perfect

For Log Viewer:

LOG_VIEWER_PATH=some_complex_string_hash_is_perfect

And be sure to add to the configuration:

'route_path' => env('LOG_VIEWER_PATH', 'log-viewer'),