Who this is for: Laravel developers who need useful production diagnostics without collecting credentials or unnecessary visitor data.
What you will learn: how channels and levels work, how to add structured context, what TeachyLeaf's contact form logs, and why reset links must be delivered privately rather than written to a log.
Prerequisites: Basic Laravel controllers and environment configuration.
Tested environment: Laravel Framework 13.16.1 and PHP 8.4.15. Feature tests verify the password-reset notification and generated admin URL using Laravel's notification fake; they do not send a real email.
Channels choose where logs go
A Laravel log channel configures a destination and handler. TeachyLeaf's config/logging.php uses a stack channel by default. Its LOG_STACK setting selects the channel or channels in that stack; the example environment sets it to single, which writes to storage/logs/laravel.log.
The configuration also includes a daily channel with a configurable retention period. Setting LOG_DAILY_DAYS=14 keeps up to fourteen daily files for that channel; it does not automatically make the default single-file channel rotate.
A simplified set of example values looks like this:
LOG_CHANNEL=stack
LOG_STACK=single
LOG_LEVEL=debug
LOG_DAILY_DAYS=14
Other configured destinations include stderr, the system log, and external services. If logs are sent to a provider, its access rules, retention, location, and privacy terms matter too. Do not copy secret webhook URLs or private log output into tickets, screenshots, or public examples.
Levels help separate routine events from failures
Laravel's logging API supports severity levels such as debug, info, notice, warning, error, and critical. LOG_LEVEL sets the minimum level accepted by a channel: a channel configured for warning omits lower-severity debug and informational messages.
A lower threshold may be useful while diagnosing a local issue, but it can create noisy logs and retain more data. Choose a production level that supports operations, then review what the application writes and how long it remains accessible. Configuration is cached during deployment, so environment changes may require rebuilding the configuration cache.
Add structured, limited context
TeachyLeaf's contact controller records an error when the mail transport fails. It logs the event and exception class, not the submitted message or the exception's full transport text:
Log::error('Contact form email delivery failed.', [
'exception_class' => $exception::class,
]);
Structured context helps group and filter events without adding the whole request to the log. Add only fields that have a clear diagnostic purpose. Avoid passwords, session identifiers, reset tokens, full URLs containing tokens, contact-message bodies, and unnecessary personal data. A log file may be readable by more people and kept longer than the application database.
Never log a password-reset URL
A password-reset URL contains a temporary bearer token: anyone who obtains a usable link may be able to set a new password. Do not write that URL or its token to application logs, browser analytics, or ordinary support messages.
TeachyLeaf previously created a token, wrote the reset URL to an info log, and displayed a message claiming an email had been sent—even though no notification was sent. The flow now uses Laravel's password broker to create and send its reset notification:
Password::sendResetLink($request->only('email'));
The broker uses the configured token table, expiry, and throttle. The current settings make tokens valid for 60 minutes and prevent another token from being generated for the same account for 60 seconds. The application maps Laravel's reset notification to the existing admin reset route with ResetPassword::createUrlUsing. The visitor receives the same response whether or not an account exists, which avoids revealing account presence in the page message.
The POST route also has a request throttle. The notification fake in the automated test proves that Laravel builds the notification and uses the intended admin URL; it does not prove that the configured production mail transport delivers it. After deployment, test the reset flow with an authorized account and confirm that no reset token appears in logs.
Inspect the destination without exposing its contents
Before diagnosing a production logging issue, confirm the deployed environment and configured destination through the hosting provider's protected controls. Do not paste complete environment output into a public issue or chat: destinations can contain private endpoints or credentials. After changing logging environment values, follow the host's deployment procedure for clearing or rebuilding Laravel's configuration cache.
Check that the application can write to its configured destination, that rotated files have an appropriate retention period, and that only authorized operators can access them. External log services add another recipient for operational data, so configure them deliberately.
Practice: choose safe context
A mail failure occurs while processing a contact form. Which log entry is safer and still useful?
Log::error('Mail failed', ['message' => $request->message, 'reset_url' => $url]);Log::error('Contact form email delivery failed.', ['exception_class' => $exception::class]);
Show the answer
The second entry records the failure category without copying private message content or a reset URL into logs. If more context is needed, add only a non-sensitive identifier with a clear operational purpose and a retention plan.