structured_log 0.1.0 copy "structured_log: ^0.1.0" to clipboard
structured_log: ^0.1.0 copied to clipboard

Structured logging for Dart, inspired by Python's structlog. Log JSON with context binding.

structured_log #

Structured logging for Dart, inspired by Python's structlog.

Log JSON with context binding, processors, and flexible output destinations.

Features #

  • Structured JSON output — logs are machine-readable by default
  • Context binding — immutable bind() / unbind() for attaching metadata to loggers
  • Processors — transform log entries before output (filter, enrich, format)
  • Multiple outputs — stdout, file, rotating file, or custom
  • Colored console — human-readable development output
  • Configurable — global configuration with StructlogConfiguration.configure()
  • Zero dependencies — only Dart SDK

Installation #

Add to your pubspec.yaml:

dependencies:
  structured_log:
    # or pub.dev when published

Quick Start #

import 'package:structured_log/structured_log.dart';

void main() {
  final log = getLogger();
  log.info('user_login', context: {'user_id': 42, 'ip': '127.0.0.1'});
}

Output:

{
  "user_id": 42,
  "ip": "127.0.0.1",
  "event": "user_login",
  "level": "info",
  "timestamp": "2026-04-27T12:00:00.000000"
}

API Reference #

Getting a Logger #

// Default logger
final log = getLogger();

// Named logger (adds 'logger' key to context)
final log = getLogger('auth');

Log Levels #

Method Level Color (console)
debug() debug cyan
info() info green
warning() warning yellow
error() error red
critical() critical magenta
log.debug('cache miss', context: {'key': 'session:42'});
log.info('request completed', context: {'duration_ms': 150});
log.warning('slow query', context: {'sql': 'SELECT ...', 'ms': 2000});
log.error('payment failed', context: {'error': 'timeout', 'order_id': 123});
log.critical('database down', context: {'host': 'db-primary'});

Context Binding #

bind() returns a new logger instance with merged context (immutable pattern):

final baseLog = getLogger();

// Bind request-level context
final requestLog = baseLog.bind({'request_id': 'abc-123', 'trace_id': 'xyz'});

// Bind user-level context on top
final userLog = requestLog.bind({'user_id': 42});

userLog.info('purchase');
// → {"request_id": "abc-123", "trace_id": "xyz", "user_id": 42, "event": "purchase", ...}

unbind() removes keys:

final cleanLog = userLog.unbind(['user_id']);

Inline Context #

Pass per-call context directly:

log.info('event', context: {'one_off': true});

Context is merged in order: initialContextbind() → inline context.

Configuration #

Global Configuration #

StructlogConfiguration.configure(
  processors: [dropNullValues, myCustomProcessor],
  output: fileOutput('logs/app.log'),
  initialContext: {'app': 'my_app', 'version': '1.0.0'},
);
Parameter Type Default Description
processors List<Processor> [dropNullValues] Pipeline to transform entries
output OutputFunction defaultOutput Where to send log entries
initialContext Map<String, dynamic> {} Context added to all loggers

Reset to defaults:

StructlogConfiguration.reset();

Outputs #

Console (default)

Pretty-printed JSON to stdout:

StructlogConfiguration.configure(output: defaultOutput);

Colored Console

Human-readable with ANSI colors:

StructlogConfiguration.configure(output: coloredConsoleOutput);

Output:

[2026-04-27T12:00:00.000000] INFO: user_login {"user_id": 42}

File

Append JSON lines (JSONL) to a file. Directories are created automatically:

StructlogConfiguration.configure(
  output: fileOutput('logs/app.log'),
);

Rotating File

Automatically rotates when file exceeds size limit:

StructlogConfiguration.configure(
  output: rotatingFileOutput(
    'logs/app.log',
    maxSizeBytes: 10 * 1024 * 1024, // 10MB
    maxBackups: 5,                   // keep 5 rotated files
  ),
);

Rotated files: app.log, app.log.0, app.log.1, ... app.log.4

Custom Output

Implement your own:

void myOutput(Map<String, dynamic> entry, LogLevel level) {
  // Send to Sentry, CloudWatch, etc.
}

StructlogConfiguration.configure(output: myOutput);

Processors #

Processors are functions that transform log entries before output. Return null to drop the entry.

Built-in Processors #

Processor Description
dropNullValues Removes keys with null value
addTimestamp Adds ISO 8601 timestamp
addLogLevel Ensures level key exists
jsonRenderer Prints entry as JSON
logfmtRenderer Prints as key=value pairs

Custom Processor #

Map<String, dynamic>? maskPasswords(Map<String, dynamic> entry) {
  if (entry.containsKey('password')) {
    entry['password'] = '***';
  }
  return entry;
}

StructlogConfiguration.configure(
  processors: [dropNullValues, maskPasswords],
);

Processor order matters — they run sequentially:

processors: [
  dropNullValues,      // 1. Clean nulls
  maskPasswords,       // 2. Mask secrets
  addCorrelationId,    // 3. Enrich
]

Examples #

Web Server Request Logging #

import 'package:structured_log/structured_log.dart';

void handleRequest(Request req) {
  final log = getLogger().bind({
    'request_id': req.id,
    'method': req.method,
    'path': req.path,
    'ip': req.remoteAddress,
  });

  log.info('request started');

  try {
    final response = processRequest(req);
    log.info('request completed', context: {
      'status': response.status,
      'duration_ms': response.duration,
    });
  } catch (e, st) {
    log.error('request failed', context: {
      'error': e.toString(),
      'stack_trace': st.toString(),
    });
    rethrow;
  }
}

Multiple Loggers (file + console) #

// Console logger for development
final consoleLog = getLogger('console');
consoleLog.info('app started');

// Switch to file output
StructlogConfiguration.configure(output: fileOutput('logs/production.log'));
final fileLog = getLogger('production');
fileLog.info('same event, different output');

Async-Safe Logging #

The library uses synchronous file I/O, making it safe for use in any context:

Future<void> asyncTask() async {
  final log = getLogger().bind({'task': 'background_job'});
  log.info('task started');

  await Future.delayed(Duration(seconds: 1));

  log.info('task completed');
}

Comparison with Python structlog #

Feature Python structlog Dart structured_log
Context binding bind() bind()
Processors Yes Yes
JSON output Yes Yes
Console output Yes Yes (colored)
File output Via stdlib Built-in
Rotating file Via handlers Built-in
Async support Yes Sync I/O
Wrapper classes Yes No (simple)

License #

MIT

0
likes
0
points
273
downloads

Publisher

unverified uploader

Weekly Downloads

Structured logging for Dart, inspired by Python's structlog. Log JSON with context binding.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

meta

More

Packages that depend on structured_log