contextual 2.0.0 copy "contextual: ^2.0.0" to clipboard
contextual: ^2.0.0 copied to clipboard

A structured logging library for Dart with support for multiple output channels, customizable formatting, context management, and middleware processing.

example/contextual_example.dart

import 'dart:convert';

import 'package:contextual/contextual.dart';

/// Middleware that blocks sensitive logs containing passwords
class BlockSensitiveLogsMiddleware implements DriverMiddleware {
  @override
  DriverMiddlewareResult handle(LogEntry entry) {
    if (entry.message.contains('password')) {
      print('[Middleware] Sensitive log detected. Blocking log.');
      return DriverMiddlewareResult.stop();
    }
    return DriverMiddlewareResult.proceed();
  }
}

/// Middleware that adds a specific tag for driver-targeted messages
class AddTagMiddleware implements DriverMiddleware {
  final String tag;

  AddTagMiddleware(this.tag);

  @override
  DriverMiddlewareResult handle(LogEntry entry) {
    final modifiedMessage = '${entry.message} [$tag]';

    // Create a new LogEntry with the modified message
    final modifiedEntry = entry.copyWith(message: modifiedMessage);

    return DriverMiddlewareResult.modify(modifiedEntry);
  }
}

/// Middleware to dynamically enrich logs with user information
class AddUserMiddleware implements DriverMiddleware {
  final String username;

  AddUserMiddleware(this.username);

  @override
  DriverMiddlewareResult handle(LogEntry entry) {
    return DriverMiddlewareResult.modify(
      entry.copyWith(message: '${entry.message} | User: $username'),
    );
  }
}

/// Formatter for structured data (JSON-style)
class StructuredMapFormatter extends LogTypeFormatter<Map<String, dynamic>> {
  @override
  String format(Level level, Map<String, dynamic> message, Context context) {
    final logData = {
      'level': level.toUpperCase(),
      'data': message,
      'context': context.all(),
      'timestamp': DateTime.now().toIso8601String(),
    };
    return jsonEncode(logData);
  }
}

/// Formatter for exceptions
class ExceptionLogFormatter extends LogTypeFormatter<Exception> {
  @override
  String format(Level level, Exception exception, Context context) {
    return '[${level.toUpperCase()}] Exception: ${exception.toString()} at ${DateTime.now()} | Context: ${context.all()}';
  }
}

void main() async {
  // Configuration for multiple logging channels
  final logConfig = LogConfig(
    environment: 'production',
    channels: [
      ConsoleChannel(ConsoleOptions(), name: 'console'),
      DailyFileChannel(
        DailyFileOptions(path: 'logs/app', retentionDays: 7),
        name: 'file',
      ),
      WebhookChannel(
        WebhookOptions(
          url: Uri.parse(
            'https://webhook-test.com/b61f3ee766b6354bb67881df60708333',
          ),
        ),
        name: 'webhook',
      ),
    ],
  );

  // Initialize Logger with fluent configuration
  final logManager = await Logger.create(config: logConfig);
  logManager
      .environment('production')
      .formatter(PrettyLogFormatter()) // Human-friendly pretty logs
      .addMiddleware(
        () => {'app': 'MyApp', 'version': '1.2.0'},
      ) // Global context middleware
      .addLogMiddleware(
        BlockSensitiveLogsMiddleware(),
      ) // Global sensitive log blocker
      .addLogMiddleware(AddUserMiddleware('john_doe')) // Enrich logs with user
      .addDriverMiddleware<ConsoleLogDriver>(
        AddTagMiddleware('DEBUG-CONSOLE'),
      ) // Add console-specific tags
      .addTypeFormatter<Map<String, dynamic>>(
        StructuredMapFormatter(),
      ) // JSON structure formatter
      .addTypeFormatter<Exception>(
        ExceptionLogFormatter(),
      ); // Exception formatter

  // Enable centralized batching for driver dispatch (optional)
  await logManager.batched(
    LogSinkConfig(batchSize: 50, flushInterval: Duration(milliseconds: 500)),
  );

  // Example 1: Logging simple messages
  logManager.info('Application started successfully.');
  // logManager.error('An unexpected error occurred during execution.');

  // // Example 2: Structured data logging
  logManager.info({'event': 'login', 'user': 'john_doe', 'status': 'success'});

  // Example 3: Logging an exception
  try {
    throw Exception('Database connection failed');
  } catch (e) {
    logManager.error(e);
  }

  // Example 4: Logging to specific channels (console and file)
  logManager
      .channels(['console', 'file'])
      .critical('Critical system failure detected!');

  // Example 5: Dynamic on-demand channel configuration
  final customChannel = logManager.buildChannel({
    'driver': 'daily',
    'path': 'logs/custom.log',
    'days': 5,
  });

  logManager.addChannel('custom', customChannel);
  logManager['custom'].warning('Custom log channel warning.');

  // Example 6: Adding shared context and logging
  logManager
      .withContext({'requestId': 'abcd1234', 'operation': 'user-update'})
      .info('User details updated successfully.');

  // Example 7: Logging stack configuration (console + webhook)
  logManager
      .channels(['console', 'webhook'])
      .alert('System is under heavy load.');

  // Shutdown to flush logs
  await logManager.shutdown();
  print("something");
}
7
likes
150
points
558
downloads

Publisher

verified publisherglenfordwilliams.com

Weekly Downloads

A structured logging library for Dart with support for multiple output channels, customizable formatting, context management, and middleware processing.

Repository (GitHub)
View/report issues

Topics

#logging #structured-logging #middleware #observability #telemetry

Documentation

API reference

Funding

Consider supporting this project:

www.buymeacoffee.com

License

MIT (license)

Dependencies

ansicolor, dart_mappable, gato, intl, universal_io

More

Packages that depend on contextual