format method

  1. @override
Map<String, dynamic> format(
  1. LogRecord error,
  2. List<LogRecord> contextLogs,
  3. Map<String, String> metadata
)
override

Builds the JSON-encodable payload to deliver to the remote endpoint.

error is the log record that triggered the alert. contextLogs are recently buffered log records that preceded the error. metadata contains arbitrary key-value pairs (e.g. app name, version).

Implementation

@override
Map<String, dynamic> format(
  LogRecord error,
  List<LogRecord> contextLogs,
  Map<String, String> metadata,
) {
  final blocks = <Map<String, dynamic>>[];

  // Header
  blocks.add({
    'type': 'header',
    'text': {
      'type': 'plain_text',
      'text': ':rotating_light: Error: ${error.className}',
    },
  });

  // App metadata (e.g. app name, version, environment)
  if (metadata.isNotEmpty) {
    final metaText = metadata.entries
        .map((e) => '*${e.key}:* ${e.value}')
        .join('  |  ');
    blocks.add({
      'type': 'context',
      'elements': [
        {'type': 'mrkdwn', 'text': metaText},
      ],
    });
  }

  // Error message
  blocks.add({
    'type': 'section',
    'text': {'type': 'mrkdwn', 'text': '*Message:* ${error.message}'},
  });

  // Attrs
  if (error.attrs != null && error.attrs!.isNotEmpty) {
    final attrsText = error.attrs!.entries
        .map((e) => '${e.key}: ${e.value}')
        .join('  |  ')
        .replaceAll('\n', ' ');
    blocks.add({
      'type': 'section',
      'text': {'type': 'mrkdwn', 'text': '*Attrs:* $attrsText'},
    });
  }

  // Error object
  if (error.error != null) {
    blocks.add({
      'type': 'section',
      'text': {'type': 'mrkdwn', 'text': '*Error:* `${error.error}`'},
    });
  }

  // Stack trace
  if (error.stackTrace != null) {
    final st = error.stackTrace.toString();
    final truncated = st.length > 2000 ? '${st.substring(0, 2000)}...' : st;
    blocks.add({
      'type': 'section',
      'text': {'type': 'mrkdwn', 'text': '*Stack Trace:*\n```$truncated```'},
    });
  }

  // Context logs
  if (contextLogs.isNotEmpty) {
    final contextText = contextLogs
        .map((r) {
          final base =
              '[${r.timestamp.toIso8601String()}]'
              ' ${_icons[r.level.index]}'
              ' [${r.level.name.toUpperCase()}]'
              ' ${r.className}: ${r.message}';
          if (r.attrs == null || r.attrs!.isEmpty) return base;
          final attrsText = r.attrs!.entries
              .map((e) => '${e.key}: ${e.value}')
              .join(', ');
          return '$base  {$attrsText}'.replaceAll('\n', ' ');
        })
        .join('\n');
    final truncated = contextText.length > 2000
        ? '${contextText.substring(0, 2000)}...'
        : contextText;
    blocks.add({
      'type': 'section',
      'text': {'type': 'mrkdwn', 'text': '*Context Logs:*\n```$truncated```'},
    });
  }

  // Timestamp
  blocks.add({
    'type': 'context',
    'elements': [
      {
        'type': 'mrkdwn',
        'text': 'Occurred at: ${error.timestamp.toIso8601String()}',
      },
    ],
  });

  return {'blocks': blocks};
}