Skip to content

Logging

Log.info('post.created id=${post.id}');
Log.debug('Cache miss for key $key');
Log.warning('Payment retried');
Log.error('Checkout failed', error, stackTrace);

Every line is written to standard output, and to a file when one is configured:

[2026-09-02 09:48:22] production.ERROR: Checkout failed | Bad state: no gateway

The format is timestamp, environment, level, message — so local.INFO and production.ERROR are distinguishable when logs from several environments end up in the same place.

Levels

Method Use for
Log.debug Detail useful only while diagnosing something.
Log.info Ordinary events worth a record.
Log.warning Something recoverable that should not be normal.
Log.error A failure.

Each accepts an optional error and stack trace:

Log.error(Object message, [Object? error, StackTrace? stackTrace]);

The error is appended after a |, and the stack trace on the following lines.

Configuration

The log path comes from your application config:

config/app.dart
Map<String, dynamic> get app => {
'log_path': 'storage/logs/app.log',
};

The path is resolved against the application’s base path, and directories are created as needed. Remove the key and logs go to standard output only — which is what you usually want in a container, where the runtime collects stdout.

Log.environment is set from APP_ENV when the application is created.

Writing Somewhere Else

Log.sink is a plain StringSink, which makes logging testable and redirectable:

final buffer = StringBuffer();
Log.sink = buffer;
Log.info('hello');
expect(buffer.toString(), contains('INFO: hello'));

Logging and Error Handling

Unhandled exceptions are reported through Log.error automatically, with their stack trace. You do not need to log an exception you are about to throw — the handler does it.

HttpException and ValidationException are deliberately not logged. A 404 or a failed validation is an ordinary outcome, and recording them buries the failures that matter.

To send errors somewhere else as well, add a reporter rather than replacing the log:

.withExceptions((exceptions) {
exceptions.report((error, stackTrace) => errorTracker.send(error, stackTrace));
})

See Error Handling.

Production Guidance

Write logs to stdout in containers and let the runtime collect them. Avoid passwords, bearer tokens, full request bodies, and other secrets; logs usually outlive the request and are visible to more systems and people than application data.

Use stable event-like messages such as post.created plus identifiers. They are easier to search than prose that changes from one call site to another.