A small Flutter logging library focused on:
- Always including caller information (file, line, column, member)
- Supporting severity levels (
LogLevel) - Supporting standardized types (
LogType) likeHTTP.REQUEST,DB.QUERY, ... - Emitting structured JSON fields
The default formatter produces lines like:
2025-12-18T16:52:10.123Z INFO [network] package:my_app/data/api_client.dart:123:17 ApiClient.fetchUser - Request completed {"status":200,"ms":84} [TYPE:HTTP.RESPONSE]
If a stack trace is provided, it is appended on a new line.
Loggerinterface +AbstractLoggerimplementationDebugPrintLoggerbackend (FlutterdebugPrint)DeveloperLogLoggerbackend (dart:developer)DebugAndProdLogger(different logger in debug vs--release)DefaultLogFormatter(caller + JSON fields +[TYPE:...]suffix)CompositeLogger(fan-out to multiple backends)FilteringLogger(minimum level filtering)
Add the dependency to your pubspec.yaml:
dependencies:
flutter_infofactory_logger:
path: ../flutter_infofactory_loggerThen run:
flutter pub getimport 'package:flutter_infofactory_logger/flutter_infofactory_logger.dart';
final logger = DebugPrintLogger(
minLevel: LogLevel.debug,
formatter: const DefaultLogFormatter(),
);
logger.info(
'Request completed',
tag: 'network',
type: LogType.httpResponse,
fields: {'status': 200, 'ms': 84},
);Environment configuration (--dart-define):
DebugPrintLogger.minLevel- Allowed values:
none(disables logging)trace,debug,info,warn,error,fatal- aliases:
off,disabled=>none
- Allowed values:
Example:
flutter run --dart-define=DebugPrintLogger.minLevel=debugAnd in code:
final logger = DebugPrintLogger.fromEnvironment();Example output:
2025-12-18T16:52:10.123Z INFO [network] package:my_app/data/api_client.dart:123:17 ApiClient.fetchUser - Request completed {"status":200,"ms":84} [TYPE:HTTP.RESPONSE]
import 'package:flutter_infofactory_logger/flutter_infofactory_logger.dart';
final logger = DeveloperLogLogger(
minLevel: LogLevel.trace,
formatter: const DefaultLogFormatter(),
name: 'my_app',
);
try {
throw StateError('boom');
} catch (e, st) {
logger.error(
'Unexpected error',
tag: 'app',
type: LogType.error,
error: e,
stackTrace: st,
fields: {'feature': 'startup'},
);
}Environment configuration (--dart-define):
DeveloperLogLogger.minLevel- Allowed values:
none(disables logging)trace,debug,info,warn,error,fatal- aliases:
off,disabled=>none
- Allowed values:
DeveloperLogLogger.name- String, used as the
developer.logname whentagis not set.
- String, used as the
Example:
flutter run \
--dart-define=DeveloperLogLogger.minLevel=info \
--dart-define=DeveloperLogLogger.name=my_appAnd in code:
final logger = DeveloperLogLogger.fromEnvironment();Example output:
2025-12-18T16:52:12.456Z ERROR [app] package:my_app/main.dart:42:9 main - Unexpected error {"feature":"startup"} error=Bad state: boom [TYPE:ERROR]
<stack trace...>
Use one logger while running in debug/profile and a different one when running in release.
The selection is based on kReleaseMode (so flutter run --release).
import 'package:flutter_infofactory_logger/flutter_infofactory_logger.dart';
final logger = DebugAndProdLogger(
debugLogger: DebugPrintLogger.fromEnvironment(),
releaseLogger: DeveloperLogLogger.fromEnvironment(),
);Environment configuration (--dart-define):
- None directly. Configure the underlying loggers instead.
import 'package:flutter_infofactory_logger/flutter_infofactory_logger.dart';
final formatter = const DefaultLogFormatter();
final logger = CompositeLogger(
children: [
DebugPrintLogger(minLevel: LogLevel.debug, formatter: formatter),
DeveloperLogLogger(minLevel: LogLevel.info, formatter: formatter, name: 'my_app'),
],
);
logger.debug('Only debugPrint receives this', tag: 'dev');
logger.info('Both backends receive this', tag: 'app');Environment configuration (--dart-define):
- None.
import 'package:flutter_infofactory_logger/flutter_infofactory_logger.dart';
final formatter = const DefaultLogFormatter();
final inner = DebugPrintLogger(minLevel: LogLevel.trace, formatter: formatter);
final logger = FilteringLogger(
inner: inner,
minLevel: LogLevel.warn,
);
logger.info('Filtered out');
logger.warn('Visible');Environment configuration (--dart-define):
- None.
- Caller information is extracted using
package:stack_trace. - Capturing stack traces has a cost; use an appropriate
minLevelin production. - Set
minLeveltoLogLevel.noneto disable logging.