inline_logger 0.2.0
inline_logger: ^0.2.0 copied to clipboard
A powerful inline logger for Flutter. Log anywhere in your widget tree without breakpoints. Chain logging calls directly on any expression.
inline_logger #
A powerful inline logger for Flutter that lets you log anywhere in your widget tree without breakpoints.
Maintained by Akshay Chand T (akshaychandt)
⨠Why inline_logger? #
Traditional logging requires you to break your code flow, add print statements, and often rebuild your UI. With inline_logger, you can log any value inline - directly in your widget tree, method chains, or anywhere else - without disrupting your code!
// â Traditional way
final userName = user.name;
print('User name: $userName');
return Text(userName);
// â
With inline_logger
return Text(user.name.log('User name'));
đ Features #
- đ Chainable inline logging - Log any value without breaking code flow
- đ¯ Multiple log levels - Debug, Verbose, Info, Success, Warning, Error, Critical
- đ Clickable source locations - IDE-clickable links to the exact call site
- đ¨ Color-coded output - Different colors for each log level in console
- đ¨ Emoji indicators - Visual log levels (can be disabled)
- ⥠Zero performance impact - Automatically disabled in release mode
- đ Log history - Store important logs for crash reporting
- đ Stack trace support - Capture stack traces for errors
- đŗ Widget tree logging - Log anywhere in your build methods
- đ Extensibility hooks - Custom formatters and record sinks
- âī¸ Highly configurable - Customize timestamps, emojis, colors, log levels
đĻ Installation #
Add this to your pubspec.yaml:
dependencies:
inline_logger: ^0.2.0
Then run:
flutter pub get
đ¯ Quick Start #
Import the package #
import 'package:inline_logger/inline_logger.dart';
Basic Usage #
1. Inline Widget Tree Logging
The most powerful feature - log directly in your widget tree:
@override
Widget build(BuildContext context) {
return Column(
children: [
// Log user data inline without breaking the widget tree
Text(userData.log('User data').name),
// Log calculations inline
Text('Total: ${(price * quantity).logInfo('Calculated total')}'),
// Chain multiple logs
Text(user.log('Full user').email.logDebug('Email address')),
],
);
}
2. Method Chaining
// Chain logs on any expression
final result = apiCall()
.log('API Response')
.data
.logSuccess('Data extracted')
.firstWhere((item) => item.id == 5)
.logDebug('Found item');
3. Direct Logging Methods
Logger.debug('Debugging info');
Logger.info('General information');
Logger.success('Operation completed successfully!');
Logger.warning('Warning message');
Logger.error('Error occurred', 'Context', stackTrace);
Logger.critical('Critical failure!');
đ Log Levels #
inline_logger supports 7 log levels with color-coded output:
| Level | Color | Emoji | Method | Use Case |
|---|---|---|---|---|
| Debug | Gray | đ | .logDebug() |
Debugging information |
| Verbose | Cyan | đ | .logVerbose() |
Detailed logs |
| Info | Blue | âšī¸ | .logInfo() |
General information |
| Success | Green | â | .logSuccess() |
Successful operations |
| Warning | Yellow | â ī¸ | .logWarning() |
Warnings |
| Error | Red | â | .logError() |
Errors |
| Critical | Bright Red | đ¨ | .logCritical() |
Critical failures |
đ¨ Advanced Features #
Configuration #
// Set minimum log level (only warnings and above)
LoggerConfig.minLevel = LogLevel.warning;
// Disable timestamps
LoggerConfig.showTimestamp = false;
// Disable emojis
LoggerConfig.showEmoji = false;
// Enable/disable color-coded output
LoggerConfig.useColors = true; // Default is true
// Disable logging completely
LoggerConfig.enabled = false;
đ Clickable Source Locations #
Every log line automatically includes the exact call site (file path + line + column) appended at end-of-line in parentheses â the only format VS Code (Dart-Code) and Android Studio / IntelliJ recognise as clickable. Click the link in your IDE's Run/Debug console to jump directly to that line of source code.
[2024-01-01T12:34:56.789] âšī¸ [INFO] Counter updated â 5 (package:my_app/main.dart:42:5)
No extra arguments needed â source location is captured automatically via StackTrace.current, and the package intelligently skips its own internal frames to find your code.
The trailing (...) segment is intentionally un-styled (no ANSI), at end-of-line, with a mandatory :line:column. Anything else breaks the IDE's stack-frame scanner.
Link Formats
// Recommended default â package: URIs are clickable in both VS Code and
// Android Studio. Falls back to fileUri for files outside lib/.
LoggerConfig.clickableLinkFormat = LinkFormat.auto;
// Explicit package URI (same fallback behaviour as `auto`).
LoggerConfig.clickableLinkFormat = LinkFormat.packageUri;
// Output: (package:my_app/main.dart:42:5)
// Absolute file URI â clickable in both VS Code and Android Studio.
LoggerConfig.clickableLinkFormat = LinkFormat.fileUri;
// Output: (file:///Users/akshay/app/lib/main.dart:42:5)
// Bare absolute path â kept for older IntelliJ plugin versions.
LoggerConfig.clickableLinkFormat = LinkFormat.bareAbsolute;
// Output: (/Users/akshay/app/lib/main.dart:42:5)
// Deprecated: project-relative paths are NOT clickable in any IDE.
// Silently falls back to packageUri/fileUri.
// LoggerConfig.clickableLinkFormat = LinkFormat.projectRelative;
Source Location Configuration
// Master switch (default: true in debug, false in release)
LoggerConfig.showSourceLocation = true;
// Show/hide individual components
LoggerConfig.showFilePath = true;
LoggerConfig.showLineNumber = true;
// The rendered string always includes `:column` (IDEs require it). This
// flag controls only whether the column comes from the stack frame
// (`true`) or is forced to `:1` (`false`).
LoggerConfig.showColumnNumber = false;
LoggerConfig.showMemberName = false; // Off by default
// Omit the location segment from the rendered string entirely.
// The location is still attached to `LogRecord.source` for
// `onRecord` / `logHistory` consumers.
LoggerConfig.useClickableLinks = false;
Zero-Cost in Production
Source location capture is completely free in release builds. StackTrace.current is never called unless both LoggerConfig.enabled and LoggerConfig.showSourceLocation are true, and the message passes the minLevel filter. Filter first, capture second.
Color-Coded Console Output #
inline_logger automatically adds ANSI color codes to your console output, making it easy to distinguish between different log levels at a glance:
- Debug logs appear in gray
- Verbose logs appear in cyan
- Info logs appear in blue
- Success logs appear in green
- Warning logs appear in yellow
- Error logs appear in red
- Critical logs appear in bright red
Colors work in most modern IDEs and terminals that support ANSI escape codes. You can disable colors if needed:
LoggerConfig.useColors = false;
đ Extensibility Hooks #
Custom Record Sink
Forward every log record to external services:
LoggerConfig.onRecord = (record) {
// Forward to Crashlytics
FirebaseCrashlytics.instance.log(record.message);
// Forward to Sentry
Sentry.addBreadcrumb(Breadcrumb(message: record.message));
// Access full metadata
print('Level: ${record.level}');
print('Source: ${record.source}');
print('Time: ${record.time}');
};
Custom Formatter
Replace the built-in console formatter:
LoggerConfig.formatter = (record) {
final source = record.source != null
? ' (${record.source!.filePath}:${record.source!.line})'
: '';
return '${record.level.label}$source: ${record.message}';
};
API Logging #
// Log API requests
Logger.apiRequest(
endpoint: '/api/users',
method: 'POST',
headers: {'Authorization': 'Bearer token'},
body: {'name': 'John'},
);
// Log API responses with duration
Logger.apiResponse(
endpoint: '/api/users',
statusCode: 200,
data: responseData,
duration: Duration(milliseconds: 234),
);
Navigation Logging #
Logger.navigation('HomeView', 'ProfileView');
State Logging #
Logger.state('isLoading', true);
Logger.state('userData', userObject);
Lifecycle Logging #
Logger.lifecycle('initState', 'ViewModel initialized');
Logger.lifecycle('dispose', 'Cleaning up resources');
Log History #
Log history now stores full LogRecord objects with source locations:
// Access stored logs (warnings, errors, critical)
final history = LoggerConfig.logHistory;
// Each record includes source location
for (final record in history) {
print('${record.level}: ${record.message}');
print('Source: ${record.source}');
}
// Clear history
LoggerConfig.clearHistory();
// Configure history size
LoggerConfig.maxHistorySize = 50;
Structured Logging #
Logger.header('USER AUTHENTICATION');
Logger.info('Starting process...');
Logger.success('Completed!');
Logger.divider();
đĄ Real-World Examples #
ViewModel with inline logging #
class HomeViewModel extends ChangeNotifier {
List<User> _users = [];
Future<void> loadUsers() async {
Logger.header('LOAD USERS');
_isLoading = true.logState('isLoading');
notifyListeners();
try {
final stopwatch = Stopwatch()..start();
Logger.apiRequest(endpoint: '/api/users', method: 'GET');
final response = await _api.getUsers();
stopwatch.stop();
Logger.apiResponse(
endpoint: '/api/users',
statusCode: 200,
data: response,
duration: stopwatch.elapsed,
);
_users = response.logSuccess('Users loaded');
} catch (e, stackTrace) {
Logger.error('Failed to load users: $e', 'Error', stackTrace);
} finally {
_isLoading = false.logState('isLoading');
notifyListeners();
Logger.divider();
}
}
}
Widget with inline logging #
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length.log('Item count'),
itemBuilder: (context, index) {
final item = items[index].logDebug('Current item');
return ListTile(
title: Text(item.name.log('Item name')),
subtitle: Text(item.price.toString().logInfo('Price')),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => DetailView(
id: item.id.log('Selected item ID'),
),
),
).then((_) => Logger.navigation('DetailView', 'HomeView')),
);
},
);
}
đ§ Configuration Guide #
Production Setup #
void main() {
// Disable in production
if (kReleaseMode) {
LoggerConfig.enabled = false;
}
// Or set minimum level to only show errors
LoggerConfig.minLevel = LogLevel.error;
runApp(MyApp());
}
Development Setup #
void main() {
// Show everything in debug
LoggerConfig.minLevel = LogLevel.debug;
LoggerConfig.showTimestamp = true;
LoggerConfig.showEmoji = true;
LoggerConfig.useColors = true;
LoggerConfig.maxHistorySize = 100;
// Source locations are enabled by default in debug mode
// Customize format for your IDE:
LoggerConfig.clickableLinkFormat = LinkFormat.auto;
runApp(MyApp());
}
đ API Reference #
Extension Methods (Chainable) #
All these methods can be chained on any object:
.log([String key, LogLevel level])- Log with custom level.logDebug([String key])- Log as debug.logVerbose([String key])- Log as verbose.logInfo([String key])- Log as info.logSuccess([String key])- Log as success.logWarning([String key])- Log as warning.logError([String key])- Log as error.logCritical([String key])- Log as critical
Static Methods #
Logger.debug(value, [name])- Log debugLogger.verbose(value, [name])- Log verboseLogger.info(value, [name])- Log infoLogger.success(value, [name])- Log successLogger.warning(value, [name])- Log warningLogger.error(value, [name, stackTrace])- Log errorLogger.critical(value, [name, stackTrace])- Log criticalLogger.apiRequest({...})- Log API requestLogger.apiResponse({...})- Log API responseLogger.navigation(from, to)- Log navigationLogger.state(name, value)- Log state changeLogger.lifecycle(event, [details])- Log lifecycle eventLogger.divider([title])- Log dividerLogger.header(title)- Log header
New Types #
SourceLocation- Represents a source code location. Stores the originalUri(sopackage:URIs are preserved verbatim) plus line, optional column, and optional enclosing member. The legacyfilePathgetter and string constructor remain for back-compat.SourceLocationResolver- Resolves call sites from stack tracesLinkFormat- Enum for IDE-clickable link formatsLogRecord- Structured log event recordConsoleFormatter- Formats LogRecords for console output
Configuration #
LoggerConfig.enabled- Master switch (default:kDebugMode)LoggerConfig.minLevel- Minimum log levelLoggerConfig.showTimestamp- Show timestampsLoggerConfig.showEmoji- Show emoji indicatorsLoggerConfig.useColors- ANSI color outputLoggerConfig.showSourceLocation- Source location capture (default:kDebugMode)LoggerConfig.showFilePath- Show file pathLoggerConfig.showLineNumber- Show line numberLoggerConfig.showColumnNumber- Show column numberLoggerConfig.showMemberName- Show enclosing member nameLoggerConfig.useClickableLinks- Whenfalse, omits the location segment entirelyLoggerConfig.clickableLinkFormat- Link format (default:LinkFormat.auto)- Deprecated. The clickable segment must be un-styled for IDE recognition; this value is no longer applied.LoggerConfig.linkAnsiStyleLoggerConfig.onRecord- Custom record sinkLoggerConfig.formatter- Custom formatter overrideLoggerConfig.maxHistorySize- Max history entries
đ¤ Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
đ License #
This project is licensed under the MIT License - see the LICENSE file for details.
đ Credits #
Created with â¤ī¸ for the Flutter community.
Special thanks to aswinbbc for contributing ideas to this project.
đ Support #
- đ Report bugs
- đĄ Request features
- â Star on GitHub