diff --git a/packages/sane/analysis_options.yaml b/packages/sane/analysis_options.yaml
index 139ca46..9ad1a9b 100644
--- a/packages/sane/analysis_options.yaml
+++ b/packages/sane/analysis_options.yaml
@@ -1,9 +1,5 @@
 include: package:flutter_lints/flutter.yaml
 
-analyzer:
-  errors:
-    avoid_print: ignore
-
 linter:
   rules:
     prefer_single_quotes: true
diff --git a/packages/sane/example/main.dart b/packages/sane/example/main.dart
index 340b880..d93c5a7 100644
--- a/packages/sane/example/main.dart
+++ b/packages/sane/example/main.dart
@@ -3,9 +3,15 @@
 import 'dart:io';
 import 'dart:typed_data';
 
+import 'package:logging/logging.dart';
 import 'package:sane/sane.dart';
 
 void main(List<String> args) async {
+  Logger.root.level = Level.ALL;
+  Logger.root.onRecord.listen((record) {
+    print('${record.level.name}: ${record.time}: ${record.message}');
+  });
+
   final sane = SaneIsolate(sane: SaneDev());
   await sane.spawn();
 
diff --git a/packages/sane/lib/src/logger.dart b/packages/sane/lib/src/logger.dart
new file mode 100644
index 0000000..7117d01
--- /dev/null
+++ b/packages/sane/lib/src/logger.dart
@@ -0,0 +1,3 @@
+import 'package:logging/logging.dart';
+
+final logger = Logger('sane');
diff --git a/packages/sane/lib/src/sane.dart b/packages/sane/lib/src/sane.dart
index b71ac63..d72532c 100644
--- a/packages/sane/lib/src/sane.dart
+++ b/packages/sane/lib/src/sane.dart
@@ -7,6 +7,7 @@ import 'package:sane/src/bindings.g.dart';
 import 'package:sane/src/dylib.dart';
 import 'package:sane/src/exceptions.dart';
 import 'package:sane/src/extensions.dart';
+import 'package:sane/src/logger.dart';
 import 'package:sane/src/structures.dart';
 import 'package:sane/src/type_conversion.dart';
 import 'package:sane/src/utils.dart';
@@ -57,12 +58,14 @@ class Sane {
             ).nativeFunction
           : ffi.nullptr;
       final status = dylib.sane_init(versionCodePointer, nativeAuthCallback);
-      print('sane_init() -> ${status.name}');
+      logger.finest('sane_init() -> ${status.name}');
 
       status.check();
 
       final versionCode = versionCodePointer.value;
-      print('SANE version: ${SaneUtils.version(versionCodePointer.value)}');
+      logger.finest(
+        'SANE version: ${SaneUtils.version(versionCodePointer.value)}',
+      );
 
       ffi.calloc.free(versionCodePointer);
       ffi.calloc.free(nativeAuthCallback);
@@ -82,7 +85,7 @@ class Sane {
       _exited = true;
 
       dylib.sane_exit();
-      print('sane_exit()');
+      logger.finest('sane_exit()');
 
       completer.complete();
 
@@ -106,7 +109,8 @@ class Sane {
         deviceListPointer,
         saneBoolFromDartBool(localOnly),
       );
-      print('sane_get_devices() -> ${status.name}');
+
+      logger.finest('sane_get_devices() -> ${status.name}');
 
       status.check();
 
@@ -133,7 +137,7 @@ class Sane {
       final nativeHandlePointer = ffi.calloc<SANE_Handle>();
       final deviceNamePointer = saneStringFromDartString(deviceName);
       final status = dylib.sane_open(deviceNamePointer, nativeHandlePointer);
-      print('sane_open() -> ${status.name}');
+      logger.finest('sane_open() -> ${status.name}');
 
       status.check();
 
@@ -165,7 +169,7 @@ class Sane {
     Future(() {
       dylib.sane_close(_getNativeHandle(handle));
       _nativeHandles.remove(handle);
-      print('sane_close()');
+      logger.finest('sane_close()');
 
       completer.complete();
     });
@@ -307,7 +311,9 @@ class Sane {
         valuePointer.cast<ffi.Void>(),
         infoPointer,
       );
-      print('sane_control_option($index, $action, $value) -> ${status.name}');
+      logger.finest(
+        'sane_control_option($index, $action, $value) -> ${status.name}',
+      );
 
       status.check();
 
@@ -432,7 +438,7 @@ class Sane {
         _getNativeHandle(handle),
         nativeParametersPointer,
       );
-      print('sane_get_parameters() -> ${status.name}');
+      logger.finest('sane_get_parameters() -> ${status.name}');
 
       status.check();
 
@@ -453,7 +459,7 @@ class Sane {
 
     Future(() {
       final status = dylib.sane_start(_getNativeHandle(handle));
-      print('sane_start() -> ${status.name}');
+      logger.finest('sane_start() -> ${status.name}');
 
       status.check();
 
@@ -478,7 +484,7 @@ class Sane {
         bufferSize,
         bytesReadPointer,
       );
-      print('sane_read() -> ${status.name}');
+      logger.finest('sane_read() -> ${status.name}');
 
       status.check();
 
@@ -505,7 +511,7 @@ class Sane {
 
     Future(() {
       dylib.sane_cancel(_getNativeHandle(handle));
-      print('sane_cancel()');
+      logger.finest('sane_cancel()');
 
       completer.complete();
     });
@@ -523,7 +529,7 @@ class Sane {
         _getNativeHandle(handle),
         saneBoolFromIOMode(mode),
       );
-      print('sane_set_io_mode() -> ${status.name}');
+      logger.finest('sane_set_io_mode() -> ${status.name}');
 
       status.check();
 
diff --git a/packages/sane/lib/src/sane_dev.dart b/packages/sane/lib/src/sane_dev.dart
index 8438e01..8e39549 100644
--- a/packages/sane/lib/src/sane_dev.dart
+++ b/packages/sane/lib/src/sane_dev.dart
@@ -1,19 +1,22 @@
 import 'dart:typed_data';
 
+import 'package:logging/logging.dart';
 import 'package:sane/sane.dart';
 
+final _logger = Logger('sane.dev');
+
 class SaneDev implements Sane {
   @override
   Future<void> cancel(SaneHandle handle) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_cancel()');
+      _logger.finest('sane_cancel()');
     });
   }
 
   @override
   Future<void> close(SaneHandle handle) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_close()');
+      _logger.finest('sane_close()');
     });
   }
 
@@ -25,7 +28,7 @@ class SaneDev implements Sane {
     bool? value,
   }) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_controlBoolOption()');
+      _logger.finest('sane_controlBoolOption()');
       return SaneOptionResult(result: value ?? true, infos: []);
     });
   }
@@ -36,7 +39,7 @@ class SaneDev implements Sane {
     required int index,
   }) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_controlButtonOption()');
+      _logger.finest('sane_controlButtonOption()');
       return SaneOptionResult(result: null, infos: []);
     });
   }
@@ -49,7 +52,7 @@ class SaneDev implements Sane {
     double? value,
   }) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_controlFixedOption()');
+      _logger.finest('sane_controlFixedOption()');
       return SaneOptionResult(result: value ?? .1, infos: []);
     });
   }
@@ -62,7 +65,7 @@ class SaneDev implements Sane {
     int? value,
   }) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_controlIntOption()');
+      _logger.finest('sane_controlIntOption()');
       return SaneOptionResult(result: value ?? 1, infos: []);
     });
   }
@@ -75,7 +78,7 @@ class SaneDev implements Sane {
     String? value,
   }) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_controlStringOption()');
+      _logger.finest('sane_controlStringOption()');
       return SaneOptionResult(result: value ?? 'value', infos: []);
     });
   }
@@ -83,7 +86,7 @@ class SaneDev implements Sane {
   @override
   Future<void> exit() {
     return Future(() {
-      print('sane_exit()');
+      _logger.finest('sane_exit()');
     });
   }
 
@@ -92,7 +95,7 @@ class SaneDev implements Sane {
     SaneHandle handle,
   ) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_getAllOptionDescriptors()');
+      _logger.finest('sane_getAllOptionDescriptors()');
       return [
         SaneOptionDescriptor(
           index: 0,
@@ -114,7 +117,7 @@ class SaneDev implements Sane {
     required bool localOnly,
   }) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_getDevices()');
+      _logger.finest('sane_getDevices()');
       return [
         for (var i = 0; i < 3; i++)
           SaneDevice(
@@ -133,7 +136,7 @@ class SaneDev implements Sane {
     int index,
   ) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_getOptionDescriptor()');
+      _logger.finest('sane_getOptionDescriptor()');
       return SaneOptionDescriptor(
         index: index,
         name: 'name',
@@ -151,7 +154,7 @@ class SaneDev implements Sane {
   @override
   Future<SaneParameters> getParameters(SaneHandle handle) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_getParameters()');
+      _logger.finest('sane_getParameters()');
       return SaneParameters(
         format: SaneFrameFormat.gray,
         lastFrame: true,
@@ -168,7 +171,7 @@ class SaneDev implements Sane {
     AuthCallback? authCallback,
   }) {
     return Future(() {
-      print('sane_init()');
+      _logger.finest('sane_init()');
       return 1;
     });
   }
@@ -176,7 +179,7 @@ class SaneDev implements Sane {
   @override
   Future<SaneHandle> open(String deviceName) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_open()');
+      _logger.finest('sane_open()');
       return SaneHandle(deviceName: deviceName);
     });
   }
@@ -184,7 +187,7 @@ class SaneDev implements Sane {
   @override
   Future<SaneHandle> openDevice(SaneDevice device) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_openDevice()');
+      _logger.finest('sane_openDevice()');
       return SaneHandle(deviceName: device.name);
     });
   }
@@ -192,7 +195,7 @@ class SaneDev implements Sane {
   @override
   Future<Uint8List> read(SaneHandle handle, int bufferSize) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_read()');
+      _logger.finest('sane_read()');
       return Uint8List.fromList([]);
     });
   }
@@ -200,14 +203,14 @@ class SaneDev implements Sane {
   @override
   Future<void> setIOMode(SaneHandle handle, SaneIOMode mode) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_setIOMode()');
+      _logger.finest('sane_setIOMode()');
     });
   }
 
   @override
   Future<void> start(SaneHandle handle) {
     return Future.delayed(const Duration(seconds: 1), () {
-      print('sane_start()');
+      _logger.finest('sane_start()');
     });
   }
 }
diff --git a/packages/sane/pubspec.lock b/packages/sane/pubspec.lock
index b2a2893..5cb05be 100644
--- a/packages/sane/pubspec.lock
+++ b/packages/sane/pubspec.lock
@@ -175,7 +175,7 @@ packages:
     source: hosted
     version: "4.0.0"
   logging:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: logging
       sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
@@ -199,7 +199,7 @@ packages:
     source: hosted
     version: "0.12.16+1"
   meta:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: meta
       sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
diff --git a/packages/sane/pubspec.yaml b/packages/sane/pubspec.yaml
index 4846fdd..fccbe9b 100644
--- a/packages/sane/pubspec.yaml
+++ b/packages/sane/pubspec.yaml
@@ -11,6 +11,7 @@ environment:
 
 dependencies:
   ffi: ^2.1.3
+  logging: ^1.3.0
   meta: ^1.16.0
 
 dev_dependencies: