Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3b8e07f
feat(logging): introduce SentryDebugLogger for enhanced diagnostic lo…
buenaflor Dec 23, 2025
cd107e8
refactor(sentry): remove debug logger warning from Sentry initialization
buenaflor Dec 23, 2025
90ffcc2
docs(debug_logger): update example usage and clarify instance require…
buenaflor Dec 23, 2025
196e2a2
refactor(sentry): remove unused debug logger import and enhance debug…
buenaflor Dec 23, 2025
0ffd9fb
refactor(sentry): remove unused debug logger import from sentry_optio…
buenaflor Dec 23, 2025
0b4f10d
docs(debug_logger): correct example usage in documentation
buenaflor Dec 23, 2025
50661e7
Update
buenaflor Dec 23, 2025
a7f32a8
refactor(debug_logger): remove unused category parameter from logging…
buenaflor Dec 23, 2025
92165ac
refactor(debug_logger_test): remove test for category logging
buenaflor Dec 23, 2025
15e714b
refactor(android_replay_handler): enhance debug logging with context
buenaflor Dec 23, 2025
b38b3c8
refactor(debug_logger_test): enhance test coverage and improve naming…
buenaflor Dec 23, 2025
007a0b0
refactor(sentry_options): improve debug logger configuration and diag…
buenaflor Dec 23, 2025
6ad2b79
refactor(logging): replace SentryDebugLogger with SentryInternalLogge…
buenaflor Jan 5, 2026
3c78396
refactor(logging): remove SentryDebugLogger and its import from the c…
buenaflor Jan 5, 2026
a755903
refactor(sentry_options): update logger configuration methods to use …
buenaflor Jan 5, 2026
90442c6
refactor(logging): rename debugLogger to internalLogger for consistency
buenaflor Jan 5, 2026
0b59cbd
refactor(logging): remove debugLogger test and update logging referen…
buenaflor Jan 5, 2026
7232380
refactor(logging): move _defaultLogOutput method to SentryInternalLogger
buenaflor Jan 5, 2026
bfd482f
refactor(logging): improve error logging format in isolate_worker
buenaflor Jan 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,5 @@ export 'src/utils/url_details.dart';
// ignore: invalid_export_of_internal_element
export 'src/utils/breadcrumb_log_level.dart';
export 'src/sentry_logger.dart';
// ignore: invalid_export_of_internal_element
export 'src/utils/debug_logger.dart' show SentryDebugLogger;
1 change: 1 addition & 0 deletions packages/dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ class SentryOptions {

set debug(bool newValue) {
_debug = newValue;
SentryDebugLogger.configure(isEnabled: _debug, minLevel: diagnosticLevel);
Comment thread
buenaflor marked this conversation as resolved.
Outdated
if (_debug == true &&
(log == noOpLog || diagnosticLog?.logger == noOpLog)) {
log = debugLog;
Comment thread
buenaflor marked this conversation as resolved.
Expand Down
106 changes: 106 additions & 0 deletions packages/dart/lib/src/utils/debug_logger.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import 'dart:developer' as dev;

import 'package:meta/meta.dart';

import '../../sentry.dart';

/// Lightweight isolate compatible diagnostic logger for the Sentry SDK.
///
/// Logger naming convention:
/// - `sentry` – core dart package
/// - `sentry.flutter` – flutter package
/// - `sentry.{integration}` – integration packages (dio, hive, etc.)
///
/// Each package should have at least one top-level instance.
///
/// Example:
/// ```dart
/// const debugLogger = SentryDebugLogger('sentry.flutter');
///
/// debugLogger.warning('My Message')
///```
@internal
class SentryDebugLogger {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think SentryInternalLogger would be a more appropriate name.

final String _name;

const SentryDebugLogger(this._name);

static bool _isEnabled = false;
static SentryLevel _minLevel = SentryLevel.warning;

@visibleForTesting
static bool get isEnabled => _isEnabled;

@visibleForTesting
static SentryLevel get minLevel => _minLevel;

/// Configure logging for the current isolate.
///
/// This needs to be called for each new spawned isolate before logging.
static void configure({
Comment thread
denrase marked this conversation as resolved.
Outdated
required bool isEnabled,
SentryLevel minLevel = SentryLevel.warning,
}) {
_isEnabled = isEnabled;
_minLevel = minLevel;
}

void debug(
String message, {
Object? error,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a case where we would log an error + stacktrace as debug? Same for info and probably also warning.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm not sure, just added it for consistency

StackTrace? stackTrace,
}) =>
_log(SentryLevel.debug, message, error: error, stackTrace: stackTrace);

void info(
String message, {
Object? error,
StackTrace? stackTrace,
}) =>
_log(SentryLevel.info, message, error: error, stackTrace: stackTrace);

void warning(
String message, {
Object? error,
StackTrace? stackTrace,
}) =>
_log(SentryLevel.warning, message, error: error, stackTrace: stackTrace);

void error(
String message, {
Object? error,
StackTrace? stackTrace,
}) =>
_log(SentryLevel.error, message, error: error, stackTrace: stackTrace);

void fatal(
String message, {
Object? error,
StackTrace? stackTrace,
}) =>
_log(SentryLevel.fatal, message, error: error, stackTrace: stackTrace);

@pragma('vm:prefer-inline')
void _log(
SentryLevel level,
String message, {
Object? error,
StackTrace? stackTrace,
}) {
if (!_isEnabled) return;
if (level.ordinal < _minLevel.ordinal) return;
Comment thread
buenaflor marked this conversation as resolved.
Outdated

dev.log(
'[${level.name}] $message',
name: _name,
level: level.toDartLogLevel(),
error: error,
stackTrace: stackTrace,
time: DateTime.now(),
);
}
}

/// Logger for the Sentry Dart SDK.
@internal
const debugLogger = SentryDebugLogger('sentry');
148 changes: 148 additions & 0 deletions packages/dart/test/utils/debug_logger_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import 'package:sentry/sentry.dart';
import 'package:sentry/src/utils/debug_logger.dart';
import 'package:test/test.dart';

import '../test_utils.dart';

void main() {
group(SentryDebugLogger, () {
tearDown(() {
// Reset to default state after each test
SentryDebugLogger.configure(isEnabled: false);
});

group('configure', () {
test('enables logging when isEnabled is true', () {
SentryDebugLogger.configure(isEnabled: true);

expect(SentryDebugLogger.isEnabled, isTrue);
});

test('disables logging when isEnabled is false', () {
SentryDebugLogger.configure(isEnabled: false);

expect(SentryDebugLogger.isEnabled, isFalse);
});

test('sets minimum level', () {
SentryDebugLogger.configure(
isEnabled: true,
minLevel: SentryLevel.error,
);

expect(SentryDebugLogger.isEnabled, isTrue);
expect(SentryDebugLogger.minLevel, equals(SentryLevel.error));
});

test('defaults minLevel to warning', () {
SentryDebugLogger.configure(isEnabled: true);

expect(SentryDebugLogger.minLevel, equals(SentryLevel.warning));
});
});

group('log methods', () {
setUp(() {
SentryDebugLogger.configure(
isEnabled: true, minLevel: SentryLevel.debug);
});

test('debug logs without throwing', () {
expect(
() => debugLogger.debug('debug message'),
returnsNormally,
);
});

test('info logs without throwing', () {
expect(
() => debugLogger.info('info message'),
returnsNormally,
);
});

test('warning logs without throwing', () {
expect(
() => debugLogger.warning('warning message'),
returnsNormally,
);
});

test('error logs without throwing', () {
expect(
() => debugLogger.error('error message'),
returnsNormally,
);
});

test('fatal logs without throwing', () {
expect(
() => debugLogger.fatal('fatal message'),
returnsNormally,
);
});

test('logs with error object without throwing', () {
expect(
() => debugLogger.error(
'error occurred',
error: Exception('test exception'),
),
returnsNormally,
);
});

test('logs with stackTrace without throwing', () {
expect(
() => debugLogger.error(
'error occurred',
error: Exception('test'),
stackTrace: StackTrace.current,
),
returnsNormally,
);
});
});

group('debugLogger constant', () {
test('is named sentry', () {
// The debugLogger constant should be accessible and usable
expect(debugLogger, isA<SentryDebugLogger>());
});
});

group('custom logger name', () {
test('can create logger with custom name', () {
const customLogger = SentryDebugLogger('sentry.flutter');

SentryDebugLogger.configure(isEnabled: true);

expect(
() => customLogger.info('test from flutter logger'),
returnsNormally,
);
});
});

group('SentryOptions integration', () {
test('setting debug to true enables SentryDebugLogger', () {
final options = defaultTestOptions();

expect(options.debug, isFalse);
options.debug = true;

expect(SentryDebugLogger.isEnabled, isTrue);
});

test('diagnosticLevel is used as minLevel when debug is enabled', () {
final options = defaultTestOptions();

options.diagnosticLevel = SentryLevel.error;
options.debug = true;

expect(SentryDebugLogger.isEnabled, isTrue);
expect(SentryDebugLogger.minLevel, equals(SentryLevel.error));
});
});
});
}
81 changes: 0 additions & 81 deletions packages/flutter/lib/src/isolate/isolate_logger.dart

This file was deleted.

18 changes: 8 additions & 10 deletions packages/flutter/lib/src/isolate/isolate_worker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:isolate';

import '../../sentry_flutter.dart';
import 'isolate_logger.dart';
import '../utils/debug_logger.dart';

typedef SpawnWorkerFn = Future<Worker> Function(WorkerConfig, WorkerEntry);

Expand Down Expand Up @@ -141,20 +141,18 @@ void runWorker(
SendPort host,
WorkerHandler handler,
) {
IsolateLogger.configure(
debug: config.debug,
level: config.diagnosticLevel,
loggerName: config.debugName,
);
// ignore: invalid_use_of_internal_member
SentryDebugLogger.configure(
isEnabled: config.debug, minLevel: config.diagnosticLevel);

final inbox = ReceivePort();
host.send(inbox.sendPort);

inbox.listen((msg) async {
if (msg == _shutdownCommand) {
IsolateLogger.log(SentryLevel.debug, 'Isolate received shutdown');
debugLogger.debug('${config.debugName}: isolate received shutdown');
inbox.close();
IsolateLogger.log(SentryLevel.debug, 'Isolate closed');
debugLogger.debug('${config.debugName}: isolate closed');
return;
}

Expand All @@ -172,8 +170,8 @@ void runWorker(
try {
await handler.onMessage(msg);
} catch (exception, stackTrace) {
IsolateLogger.log(SentryLevel.error, 'Isolate failed to handle message',
exception: exception, stackTrace: stackTrace);
debugLogger.error('${config.debugName}: isolate failed to handle message',
error: exception, stackTrace: stackTrace);
}
});
}
Loading
Loading