Strategic Logger

 __ ______  __ ______  __ ___  __        __  __  __ ___ ___
[__  | |__/|__| | |__ | _  |  |    |   |  || _ | _ |__ |__/
___] | |  \|  | | |___|__]_|_ |__  |___|__||__]|__]|___|  \

  Strategic Logger powered by Hypn Tech (hypn.com.br)

Pub Version License: MIT Flutter Dart

One call, all strategies. Enterprise logging for Flutter.


Quick Start

import 'package:strategic_logger/logger.dart';

// Works immediately - no initialization needed
logger.info('App started');
logger.debug('Debug details', context: {'version': '4.0.0'});
logger.error('Something failed', stackTrace: StackTrace.current);

Output:

14:30:25.123 [INFO ] App started
14:30:25.124 [DEBUG] Debug details
[CONTEXT]
   version: 4.0.0
14:30:25.125 [ERROR] Something failed
Stack Trace: ...

Full Configuration

import 'package:strategic_logger/logger.dart';

void main() async {
  await logger.initialize(
    projectName: 'My App',
    level: LogLevel.info,
    strategies: [
      ConsoleLogStrategy(useModernFormatting: true, useColors: true),
      SentryLogStrategy(),
      FirebaseCrashlyticsLogStrategy(),
      DatadogLogStrategy(apiKey: 'key', service: 'app', env: 'prod'),
    ],
  );

  // One call logs to Console + Sentry + Crashlytics + Datadog
  logger.info('User logged in', context: {'userId': '123'});
}

Built-in Strategies

Strategy Use Case Key Config
ConsoleLogStrategy Development & debugging useModernFormatting, useColors
FirebaseAnalyticsLogStrategy User behavior tracking Firebase configured externally
FirebaseCrashlyticsLogStrategy Crash reports in production Firebase configured externally
SentryLogStrategy Error monitoring with context DSN configured externally
DatadogLogStrategy APM & centralized logs apiKey, service, env
NewRelicLogStrategy Performance monitoring licenseKey, appName

Decision Matrix: When to Use Each Strategy

Scenario Recommended Strategy Why
Local development ConsoleLogStrategy Beautiful colored output, zero config
User analytics FirebaseAnalyticsLogStrategy Track events, conversions, behavior
Crash tracking FirebaseCrashlyticsLogStrategy Non-fatal and fatal crash reports
Error monitoring SentryLogStrategy Rich error context, breadcrumbs
Full observability DatadogLogStrategy APM, logs, metrics in one platform
Performance monitoring NewRelicLogStrategy Application performance insights
Custom destination Extend LogStrategy or HttpLogStrategy Full control over log routing

Features

Named Loggers

Organize logs by module or component:

final authLogger = logger.named('auth');
final paymentLogger = logger.named('payment');

authLogger.info('User logged in');      // [auth] User logged in
paymentLogger.error('Payment failed');  // [payment] Payment failed

Lazy Evaluation

Avoid expensive computations when log level is inactive:

// Always evaluates (even if debug is disabled)
logger.debug('Users: ${expensiveQuery()}');

// Only evaluates if the message is actually logged
logger.debug(() => 'Users: ${expensiveQuery()}');

Stream Listeners

Listen to log entries for custom processing:

logger.listen((entry) {
  myAnalytics.track(entry.message, entry.mergedContext);
});

Shorthand Aliases

Concise logging inspired by the logger package:

logger.d('Debug');    // Same as logger.debug()
logger.i('Info');     // Same as logger.info()
logger.w('Warning');  // Same as logger.warning()
logger.e('Error');    // Same as logger.error()
logger.f('Fatal');    // Same as logger.fatal()

Structured Logging with Context

Context is passed to ALL strategies automatically:

logger.info('User action', context: {
  'userId': '123',
  'action': 'login',
  'device': 'iPhone 15',
});

// Context available in Datadog for indexing, Sentry as extra fields,
// Firebase Analytics as parameters, console as formatted output.

Real-time Log Streaming

logger.logStream.listen((logEntry) {
  updateDashboard(logEntry);
});

Creating Custom Strategies

Simple: Override handleLog() (1 method)

import 'package:strategic_logger/logger.dart';

class MyCustomStrategy extends LogStrategy {
  @override
  Future<void> handleLog(LogEntry entry) async {
    if (!shouldLog(event: entry.event)) return;
    final context = entry.mergedContext;
    await sendToMyService(entry.message, context);
  }
}

Per-Level: Override individual methods

class MyDetailedStrategy extends LogStrategy {
  @override
  Future<void> info(LogEntry entry) async {
    // Handle info differently
  }

  @override
  Future<void> error(LogEntry entry) async {
    // Handle errors differently
  }
}

HTTP Strategy: Extend HttpLogStrategy

For strategies that send to HTTP endpoints, get batch processing, retry logic, and resource management for free:

class MyHttpStrategy extends HttpLogStrategy {
  final String apiKey;

  MyHttpStrategy({required this.apiKey})
      : super(batchSize: 50, batchTimeout: Duration(seconds: 10));

  @override
  String get strategyName => 'MyHttpStrategy';

  @override
  String get endpoint => 'https://api.example.com/logs';

  @override
  Map<String, String> get headers => {'Authorization': 'Bearer $apiKey'};

  @override
  Map<String, dynamic> formatLogEntry(LogEntry entry) => {
    'message': entry.message.toString(),
    'level': entry.level.name,
    'context': entry.mergedContext,
  };
}

Strategy Configuration

ConsoleLogStrategy

ConsoleLogStrategy(
  logLevel: LogLevel.debug,
  useModernFormatting: true,  // Rich formatting with colors
  useColors: true,            // Enable ANSI colors
  autoDetectColors: true,     // iOS/Android safe (no ANSI garbage)
  showTimestamp: true,
  showContext: true,
)

DatadogLogStrategy

DatadogLogStrategy(
  apiKey: 'your-api-key',
  service: 'my-app',
  env: 'production',
  enableCompression: true,    // Gzip compression (default)
  batchSize: 100,             // Send after 100 entries
  batchTimeout: Duration(seconds: 5),  // Or after 5 seconds
  maxRetries: 3,              // Retry failed batches
)

NewRelicLogStrategy

NewRelicLogStrategy(
  licenseKey: 'your-license-key',
  appName: 'my-app',
  batchSize: 50,
  batchTimeout: Duration(seconds: 10),
)

Firebase Strategies

FirebaseAnalyticsLogStrategy(logLevel: LogLevel.info)
FirebaseCrashlyticsLogStrategy(logLevel: LogLevel.error)

SentryLogStrategy

SentryLogStrategy(logLevel: LogLevel.error)

Flutter App Integration

import 'package:flutter/material.dart';
import 'package:strategic_logger/logger.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await logger.initialize(
    projectName: 'My App',
    strategies: [
      ConsoleLogStrategy(useModernFormatting: true),
      FirebaseCrashlyticsLogStrategy(),
    ],
  );

  runApp(const MyApp());
}

Performance

  • Synchronous API - Logging calls return immediately (fire-and-forget)
  • Isolate-based processing - Heavy operations run in background isolates
  • Batch processing - HTTP strategies batch logs (100 entries or 5s timeout)
  • Async queue - Backpressure control with 1000-entry buffer
  • Retry logic - Exponential backoff for failed network operations
final stats = logger.getPerformanceStats();

Troubleshooting

ANSI colors showing as garbage on iOS/Android

Colors are auto-detected and disabled on platforms that don't support ANSI. If you still see issues:

ConsoleLogStrategy(autoDetectColors: true)  // Default - auto-detect
ConsoleLogStrategy(useColors: false)         // Force disable

Isolates not working on Web

Isolates are automatically disabled on web platform. No configuration needed.

HTTP strategy batch delays

Logs are batched for efficiency. To flush immediately:

logger.flush();

Auto-init warning on startup

If you see the auto-initialization warning, call initialize() explicitly:

await logger.initialize(strategies: [ConsoleLogStrategy()]);

Migration Guide

From v3.x to v4.0.0

v4.0.0 is backward compatible. New features are additive:

  • handleLog() - New single-method override for custom strategies (optional, old log/info/error/fatal overrides still work)
  • logger.named('module') - Named loggers for organizing by component
  • logger.debug(() => 'lazy') - Lazy evaluation support
  • logger.listen() - Stream-based extensibility
  • logger.d(), i(), w(), e(), f() - Shorthand aliases
  • HttpLogStrategy - Base class for HTTP strategies
  • LogEntry - Now exported from main logger.dart

From v2.x to v3.0.0

// v2.x - required await
await logger.info('message');

// v3.0.0+ - synchronous, no await
logger.info('message');

See CHANGELOG.md for full version history.


API Reference

LogEntry

class LogEntry {
  final dynamic message;
  final LogLevel level;
  final DateTime timestamp;
  final LogEvent? event;
  final Map<String, dynamic>? context;
  final StackTrace? stackTrace;

  /// Merges context and event.parameters into one map
  Map<String, dynamic> get mergedContext;
}

LogStrategy

abstract class LogStrategy {
  Future<void> handleLog(LogEntry entry);  // Override this (recommended)
  Future<void> log(LogEntry entry);        // Or override per-level
  Future<void> info(LogEntry entry);
  Future<void> error(LogEntry entry);
  Future<void> fatal(LogEntry entry);
  bool shouldLog({LogEvent? event});
}

Supported Platforms

  • Android, iOS, Web, macOS, Linux, Windows

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Read CLAUDE.md for development guidelines
  4. Run flutter test and flutter analyze
  5. Open a Pull Request

Sponsored by Hypn Tech - Building the future of mobile applications

GitHub Pub

MIT License - See LICENSE for details.