Diagnostic output written with print instead of a logger
ID |
dart.maintainability.print_in_production |
Severity |
info |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Api Design |
Language |
Dart |
Description
Reports a call to the top-level print function. Calls guarded by kDebugMode or !kReleaseMode, Flutter’s debugPrint, and writes through stdout or a logging abstraction are not reported, and neither are files under test, bin, tool or example, where console output is the program’s own interface rather than a debugging channel.
Rationale
print is the statement typically added while chasing a problem and then left behind, and it gives the application no control over what it wrote: no level, no structure, no correlation identifier, and no way to turn it off short of editing the code. In a released Flutter application the destination makes it worse - output goes to the platform log, where it is retained by the device, readable by anyone with a debug bridge attached, and frequently ends up containing request payloads or user data that were never meant to leave the process. On the web it lands in the browser console, visible to every user. Each call also formats its string and performs a synchronous write even when nothing is listening, which on a hot path costs frames.
The following code illustrates the pattern detected by this rule:
class OrderService {
Future<void> submit(String reference, num amount) async {
// FLAGGED: Diagnostic output written with print instead of a logger
print('submitting $reference');
try {
await _post(reference, amount);
} catch (e) {
// FLAGGED: Diagnostic output written with print instead of a logger
print('failed: $e');
rethrow;
}
}
num amountOf(String reference) => 1;
Future<void> _post(String reference, num amount) async {}
}
Remediation
Route the message through the application’s logging abstraction (package:logging, or the logger the project already uses) at a level that matches it, and pass the error and stack trace objects rather than their toString(). Delete the call if it was only scaffolding. Where the output really is for a developer, use Flutter’s debugPrint, which is rate-limited and stripped in release builds, or guard the call with if (kDebugMode).