Lập trình · 22/09/2026

Laravel 13 Course – Lesson 04: Laravel 13 Environment Configuration and Logging

Lesson 4 of the Laravel 13 course: separate TaskFlow settings from request handling and add one intentional log event. Following lesson 3, we keep the /taskflow page without domain tables. We want to change its display name and toggle logging without repeatedly editing the route.

Cấu hình môi trường và logging trong Laravel 13

Lesson 4 of the Laravel 13 course: separate TaskFlow settings from request handling and add one intentional log event. Following lesson 3, we keep the /taskflow page without domain tables. We want to change its display name and toggle logging without repeatedly editing the route.

1. Separate three configuration layers

Environment variables supply inputs; config files turn them into application settings; routes, controllers and services read those settings with config(). Our path is TASKFLOW_NAME → taskflow.name → the view's projectName. Tests can then replace configuration without editing the real .env file.

Use env() inside configuration files rather than throughout business code. When configuration is cached, Laravel does not load .env as it does without the cache. Calls to env() elsewhere may not find the expected value, although operating-system variables can still exist. See Laravel configuration.

2. Add TaskFlow configuration

Create config/taskflow.php and add these non-secret values to .env.example. Add overrides to your local .env only when needed; do not overwrite the existing file:

<?php
// config/taskflow.php
return [
    'name' => env('TASKFLOW_NAME', 'TaskFlow'),
    'overview_logging' => env('TASKFLOW_OVERVIEW_LOGGING', false),
];
# .env.example (and your local .env when needed)
TASKFLOW_NAME=TaskFlow
TASKFLOW_OVERVIEW_LOGGING=false

Quote names containing spaces, such as TASKFLOW_NAME="TaskFlow Local". Use the literal false shown for a disabled flag. Do not use an arbitrary string such as "off" and assume PHP treats it as false: it is a non-empty string. Uncontrolled configuration inputs need explicit validation instead of guessed coercion.

3. Replace the previous route

Replace the existing /taskflow route in routes/web.php; do not register a duplicate. Keep the welcome route and import each facade once:

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;

Route::get('/taskflow', function () {
    if (config('taskflow.overview_logging')) {
        Log::info('taskflow.overview.viewed', ['route' => 'taskflow.overview']);
    }

    return view('taskflow.overview', [
        'projectName' => config('taskflow.name'),
        'milestone' => 'Request lifecycle',
    ]);
})->name('taskflow.overview');

The Blade view from lesson 3 stays unchanged. With the flag disabled, the route does not emit this info event. When enabled, it records a stable event name and only an allowlisted route name. This is a learning example, not a requirement to log every real page view. Low-value events at high traffic can become expensive and hide important failures.

4. Choose the channel and severity

Inspect this project's config/logging.php to determine where LOG_CHANNEL sends records. For local observation, LOG_CHANNEL=single and LOG_LEVEL=debug make storage/logs/laravel.log convenient. Do not assume every deployment uses that file: a container may write to stderr for centralized collection.

Use info for meaningful normal events, warning for unusual but recoverable situations, and error for failures requiring investigation. Channel thresholds filter lower-severity events: an error threshold correctly hides this example's info record. See Laravel logging for channels and context.

Never log whole requests, Authorization headers, cookies, passwords, tokens or environment files. This example selects permitted fields instead of trying to remove every possible secret from arbitrary input. A log entry also does not prove a database transaction committed; later transaction and queue lessons will address event timing.

5. Test configuration and log context

Create tests/Feature/TaskFlowConfigurationTest.php:

<?php
namespace Tests\Feature;

use Illuminate\Support\Facades\Log;
use Tests\TestCase;

class TaskFlowConfigurationTest extends TestCase
{
    public function test_overview_uses_configuration_and_logs_only_allowlisted_context(): void
    {
        config(['taskflow.name' => 'Course Workspace', 'taskflow.overview_logging' => true]);
        Log::spy();

        $this->get('/taskflow?token=must-not-be-logged')
            ->assertOk()
            ->assertViewHas('projectName', 'Course Workspace');

        Log::shouldHaveReceived('info')->once()->with(
            'taskflow.overview.viewed',
            ['route' => 'taskflow.overview'],
        );
    }

    public function test_overview_logging_can_be_disabled(): void
    {
        config(['taskflow.overview_logging' => false]);
        Log::spy();

        $this->get('/taskflow')->assertOk();

        Log::shouldNotHaveReceived('info');
    }
}
php artisan test --filter=TaskFlowConfigurationTest
php artisan test

The spy verifies the exact call and context without writing a real file. The URL token is fake test input; never use real credentials for this experiment. This test proves the route sends only the expected context, not that every application component, proxy or access log removes sensitive data. Real tokens should not be placed in URLs in the first place.

6. Experiment with configuration caching

Only in local TaskFlow, set TASKFLOW_NAME="TaskFlow Local", run config:clear and open /taskflow. Then cache configuration:

php artisan config:cache
php artisan config:show taskflow

Change the .env name to "TaskFlow Changed" and inspect config:show taskflow again. While cached, the old value remains. Clear the cache, inspect again and finally restore TaskFlow so the lesson 3 baseline test still matches. Avoid sharing config:show database output because it may contain connection details.

Local development generally does not need a persistent configuration cache while settings are changing. During deployment, build the cache after the target environment has its correct settings; do not ship a personal-machine cache containing secrets. Long-running workers need the deployment's restart procedure to reload settings. Editing .env alone does not establish that every process has updated.

7. Troubleshooting and completion

  • .env changes do not affect the page: inspect the cache, system-level overrides and which project is serving the URL.
  • No log appears: check the feature flag, channel, level, write permissions and collection pipeline.
  • The TaskFlow name test fails: check whether an experimental name remains in .env; the new configuration test sets its own value.
  • Production exposes exceptions: APP_DEBUG must be false, while controlled internal logging remains available.

Finish when you can explain why config() works with cached settings, toggle the event without editing the route and describe the limits of a log spy. The example passed 7 tests with 13 assertions; config:cache, config:show taskflow and config:clear also succeeded. This lesson does not claim verification of a production TaskFlow deployment.

Navigation: Lesson 3 · Roadmap. Next comes a combined routing, controller and middleware flow.

Laravel 13 course navigation

Previous lesson (03) · Next lesson (05) · All 37 lessons

Discussion

Comments 0

Sign in to comment

You need an account to join the discussion and reply to other readers.

Sign inRegister

No comments yet. Be the first to share your thoughts.