diff --git a/.github/workflows/talker_drift_logger.yaml b/.github/workflows/talker_drift_logger.yaml
new file mode 100644
index 00000000..609a91cd
--- /dev/null
+++ b/.github/workflows/talker_drift_logger.yaml
@@ -0,0 +1,21 @@
+name: talker_drift_logger
+
+on:
+ push:
+ paths:
+ - "packages/talker_drift_logger/**"
+ - ".github/workflows/talker_drift_logger.yaml"
+ pull_request:
+ paths:
+ - "packages/talker_drift_logger/**"
+ - ".github/workflows/talker_drift_logger.yaml"
+permissions:
+ contents: read
+
+jobs:
+ test:
+ uses: ./.github/workflows/test.yaml
+ with:
+ package: talker_drift_logger
+ sdk: dart
+ chrome: false
diff --git a/README.md b/README.md
index 18aaea9c..1480dab1 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,7 @@ Talker is designed for any level of customization.
| [talker_chopper_logger](https://github.com/Frezyx/talker/tree/master/packages/talker_chopper_logger) | [](https://pub.dev/packages/talker_chopper_logger) | Best logger for [Chopper](https://pub.dev/packages/chopper) http calls |
| [talker_http_logger](https://github.com/Frezyx/talker/tree/master/packages/talker_http_logger) | [](https://pub.dev/packages/talker_http_logger) | Best logger for [http](https://pub.dev/packages/http) package |
| [talker_grpc_logger](https://github.com/Frezyx/talker/tree/master/packages/talker_grpc_logger) | [](https://pub.dev/packages/talker_grpc_logger) | Best logger for [grpc](https://pub.dev/packages/grpc) package |
+| [talker_drift_logger](https://github.com/Frezyx/talker/tree/master/packages/talker_drift_logger) | [](https://pub.dev/packages/talker_drift_logger) | Best logger for [Drift](https://pub.dev/packages/drift) database |
## Table of contents
@@ -128,7 +129,52 @@ Talker is designed for any level of customization.
- [Getting Started](#getting-started-4)
- [Using with Talker](#using-with-talker-3)
- [Token obfuscation](#token-obfuscation)
-- [Crashlytics integration](#crashlytics-integration)
+
+## Talker Drift Logger
+
+Lightweight, simple and pretty solution for logging Drift database operations using [Drift](https://pub.dev/packages/drift).
+
+This is how SQL statements and results will look in the console with Talker formatting and colors.
+
+### Getting Started
+Follow these steps to use this package
+
+### Add dependency
+```yaml
+dependencies:
+ talker_drift_logger: ^5.0.0
+```
+
+### Usage
+Attach an interceptor to Drift executor via `interceptWith`:
+
+```dart
+import 'package:drift/drift.dart';
+import 'package:drift/native.dart';
+import 'package:talker_drift_logger/talker_drift_logger.dart';
+
+final executor = NativeDatabase.memory().interceptWith(
+ TalkerDriftLogger(
+ settings: const TalkerDriftLoggerSettings(
+ printArgs: true,
+ printResults: true,
+ ),
+ ),
+);
+```
+
+### Using with Talker
+You can add your Talker instance for `TalkerDriftLogger` if your application already uses Talker.
+In this case, all logs and errors will fall into your unified tracking system and appear in Talker UI filters.
+
+```dart
+final talker = Talker();
+final executor = NativeDatabase('app.db').interceptWith(
+ TalkerDriftLogger(talker: talker),
+);
+```
+
+## Crashlytics integration
- [Features list](#features-list)
- [Coverage](#coverage)
- [Additional information](#additional-information)
diff --git a/packages/talker/lib/src/settings.dart b/packages/talker/lib/src/settings.dart
index 3a4dbaa2..a021f60b 100644
--- a/packages/talker/lib/src/settings.dart
+++ b/packages/talker/lib/src/settings.dart
@@ -27,6 +27,13 @@ final _defaultTitles = {
TalkerKey.riverpodDispose: 'riverpod-dispose',
TalkerKey.riverpodFail: 'riverpod-fail',
+ /// Drift section
+ TalkerKey.driftError: 'drift-error',
+ TalkerKey.driftQuery: 'drift-query',
+ TalkerKey.driftResult: 'drift-result',
+ TalkerKey.driftTransaction: 'drift-transaction',
+ TalkerKey.driftBatch: 'drift-batch',
+
/// Flutter section
TalkerKey.route: 'route',
};
@@ -58,6 +65,13 @@ final _defaultColors = {
TalkerKey.riverpodDispose: AnsiPen()..xterm(198),
TalkerKey.riverpodFail: AnsiPen()..red(),
+ /// Drift section
+ TalkerKey.driftError: AnsiPen()..red(),
+ TalkerKey.driftQuery: AnsiPen()..xterm(219),
+ TalkerKey.driftResult: AnsiPen()..xterm(46),
+ TalkerKey.driftTransaction: AnsiPen()..xterm(135),
+ TalkerKey.driftBatch: AnsiPen()..xterm(49),
+
/// Flutter section
TalkerKey.route: AnsiPen()..xterm(135),
};
diff --git a/packages/talker/lib/src/talker_key.dart b/packages/talker/lib/src/talker_key.dart
index f634d6eb..7bf730fc 100644
--- a/packages/talker/lib/src/talker_key.dart
+++ b/packages/talker/lib/src/talker_key.dart
@@ -36,6 +36,13 @@ abstract class TalkerKey {
static const grpcResponse = 'grpc-response';
static const grpcError = 'grpc-error';
+ /// Drift section
+ static const driftQuery = 'drift-query';
+ static const driftResult = 'drift-result';
+ static const driftError = 'drift-error';
+ static const driftTransaction = 'drift-transaction';
+ static const driftBatch = 'drift-batch';
+
/// Flutter section
static const route = 'route';
diff --git a/packages/talker_drift_logger/.gitignore b/packages/talker_drift_logger/.gitignore
new file mode 100644
index 00000000..27f7b8ce
--- /dev/null
+++ b/packages/talker_drift_logger/.gitignore
@@ -0,0 +1,31 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.packages
+build/
+.flutter-plugins
+.flutter-plugins-dependencies
diff --git a/packages/talker_drift_logger/.metadata b/packages/talker_drift_logger/.metadata
new file mode 100644
index 00000000..7b724eb7
--- /dev/null
+++ b/packages/talker_drift_logger/.metadata
@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
+ channel: stable
+
+project_type: package
diff --git a/packages/talker_drift_logger/CHANGELOG.md b/packages/talker_drift_logger/CHANGELOG.md
new file mode 100644
index 00000000..6ccf27d6
--- /dev/null
+++ b/packages/talker_drift_logger/CHANGELOG.md
@@ -0,0 +1,6 @@
+## 5.0.0
+- Initial release of `talker_drift_logger`
+- Drift `QueryInterceptor` with query/result/error/transaction/batch logs
+- Pretty JSON output, args/result printing with obfuscation and limits
+- Customization via `TalkerDriftLoggerSettings`
+- Tests and example
diff --git a/packages/talker_drift_logger/LICENSE b/packages/talker_drift_logger/LICENSE
new file mode 100644
index 00000000..17a8f2a6
--- /dev/null
+++ b/packages/talker_drift_logger/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Stanislav Ilin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/talker_drift_logger/README.md b/packages/talker_drift_logger/README.md
new file mode 100644
index 00000000..a678ac0e
--- /dev/null
+++ b/packages/talker_drift_logger/README.md
@@ -0,0 +1,90 @@
+# talker_drift_logger
+Lightweight and customizable [Drift](https://pub.dev/packages/drift) SQL logger on [talker](https://pub.dev/packages/talker) base.
+[Talker](https://github.com/Frezyx/talker) - Advanced exception handling and logging for dart/flutter applications 🚀
+
+
+
+
+
+
+
+
+## Getting started
+
+### Add dependency
+```yaml
+dependencies:
+ talker_drift_logger: ^5.0.0
+```
+
+### Usage
+Attach `TalkerDriftLogger` via Drift interceptors and that's it:
+
+```dart
+import 'package:drift/drift.dart';
+import 'package:drift/native.dart';
+import 'package:talker_drift_logger/talker_drift_logger.dart';
+
+final talker = Talker();
+
+final executor = NativeDatabase.memory().interceptWith(
+ TalkerDriftLogger(
+ talker: talker,
+ settings: const TalkerDriftLoggerSettings(
+ printArgs: true,
+ printResults: true,
+ ),
+ ),
+);
+
+// If you're using a GeneratedDatabase subclass:
+final db = MyDatabase(executor);
+```
+
+You can also wrap an existing `DatabaseConnection` or use `runWithInterceptor` for scoped logging.
+
+## Settings
+
+`TalkerDriftLoggerSettings` gives you full control:
+
+- enabled (default: true)
+- logLevel (default: LogLevel.debug)
+- printArgs / printResults
+- resultRowLimit / resultMaxChars
+- printTransaction / printBatch
+- obfuscateColumns (case-insensitive)
+- obfuscatePatterns (Pattern-based masking)
+- queryPen / resultPen / errorPen / transactionPen / batchPen
+- statementFilter / errorFilter
+- resultPrinter / argsPrinter
+
+Example:
+```dart
+TalkerDriftLogger(
+ talker: talker,
+ settings: const TalkerDriftLoggerSettings(
+ printArgs: true,
+ printResults: true,
+ resultRowLimit: 50,
+ resultMaxChars: 2000,
+ obfuscateColumns: {'password', 'token'},
+ ),
+);
+```
+
+## Using with Talker
+Provide your Talker instance if your app already uses Talker. In this case, all logs will go into your unified logging pipeline and UI (filters).
+
+```dart
+final talker = Talker();
+final executor = NativeDatabase('app.db').interceptWith(TalkerDriftLogger(talker: talker));
+```
+
+## Notes
+
+- Transactions (`begin`, `commit`, `rollback`) and batched statements are logged as well (configurable).
+- This package prints pretty JSON, masks sensitive data, and limits result sizes to keep console clean.
+
+## Additional information
+The project is under development and ready for your pull-requests and issues 👍
+Thank you for support ❤️
diff --git a/packages/talker_drift_logger/analysis_options.yaml b/packages/talker_drift_logger/analysis_options.yaml
new file mode 100644
index 00000000..46ffaf4b
--- /dev/null
+++ b/packages/talker_drift_logger/analysis_options.yaml
@@ -0,0 +1,16 @@
+# This file configures the static analysis results for your project (errors,
+# warnings, and lints).
+#
+# This enables the 'recommended' set of lints from `package:lints`.
+# The core lints are also what is used by pub.dev for scoring packages.
+
+include: package:lints/recommended.yaml
+
+# Uncomment to customize rules
+# linter:
+# rules:
+# - always_use_package_imports
+
+# analyzer:
+# exclude:
+# - test/**/goldens/**
diff --git a/packages/talker_drift_logger/example/lib/main.dart b/packages/talker_drift_logger/example/lib/main.dart
new file mode 100644
index 00000000..a3f3006b
--- /dev/null
+++ b/packages/talker_drift_logger/example/lib/main.dart
@@ -0,0 +1,39 @@
+import 'package:drift/drift.dart';
+import 'package:drift/native.dart';
+import 'package:talker/talker.dart';
+import 'package:talker_drift_logger/talker_drift_logger.dart';
+
+// Run: dart run bin/main.dart
+Future main() async {
+ final talker = Talker();
+
+ final executor = NativeDatabase.memory().interceptWith(
+ TalkerDriftLogger(
+ talker: talker,
+ settings: const TalkerDriftLoggerSettings(
+ printArgs: true,
+ printResults: true,
+ ),
+ ),
+ );
+
+ final db = _DummyDb(executor);
+
+ await db.customStatement(
+ 'CREATE TABLE users (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT);');
+ await db.customStatement("INSERT INTO users (name) VALUES ('Alice')");
+ await db.customStatement("INSERT INTO users (name) VALUES ('Bob')");
+
+ final rows = await db.customSelect('SELECT * FROM users').get();
+ talker.info('Selected ${rows.length} users');
+}
+
+class _DummyDb extends GeneratedDatabase {
+ _DummyDb(QueryExecutor e) : super(e);
+ @override
+ int get schemaVersion => 1;
+ @override
+ Iterable> get allTables => const [];
+ @override
+ List get allSchemaEntities => const [];
+}
diff --git a/packages/talker_drift_logger/example/pubspec.lock b/packages/talker_drift_logger/example/pubspec.lock
new file mode 100644
index 00000000..6d4509dd
--- /dev/null
+++ b/packages/talker_drift_logger/example/pubspec.lock
@@ -0,0 +1,132 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ ansicolor:
+ dependency: transitive
+ description:
+ name: ansicolor
+ sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.3"
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.13.0"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.19.1"
+ convert:
+ dependency: transitive
+ description:
+ name: convert
+ sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.2"
+ drift:
+ dependency: "direct main"
+ description:
+ name: drift
+ sha256: "6aaea757f53bb035e8a3baedf3d1d53a79d6549a6c13d84f7546509da9372c7c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.28.1"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.17.0"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.1"
+ sqlite3:
+ dependency: "direct main"
+ description:
+ name: sqlite3
+ sha256: f393d92c71bdcc118d6203d07c991b9be0f84b1a6f89dd4f7eed348131329924
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.9.0"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.12.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ talker:
+ dependency: "direct main"
+ description:
+ name: talker
+ sha256: "2d742b54e5cda58b7d386cd2d95088c3429ef273b2a0869dec552fe02601367a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.0.0"
+ talker_drift_logger:
+ dependency: "direct main"
+ description:
+ path: ".."
+ relative: true
+ source: path
+ version: "5.0.0"
+ talker_logger:
+ dependency: transitive
+ description:
+ name: talker_logger
+ sha256: "4f06d46db664c11cf4d629378da661f2c75aee629e3ef898dbc3cf44a0c41cd7"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.0.0"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+sdks:
+ dart: ">=3.7.0 <4.0.0"
diff --git a/packages/talker_drift_logger/example/pubspec.yaml b/packages/talker_drift_logger/example/pubspec.yaml
new file mode 100644
index 00000000..1f712aa3
--- /dev/null
+++ b/packages/talker_drift_logger/example/pubspec.yaml
@@ -0,0 +1,17 @@
+name: talker_drift_logger_example
+publish_to: "none"
+version: 1.0.0
+
+environment:
+ sdk: '>=2.17.0 <4.0.0'
+
+dependencies:
+ talker: ^5.0.0
+ talker_drift_logger:
+ path: ..
+ drift: ^2.28.1
+ sqlite3: ^2.9.0
+
+# This is a pure Dart console example
+executables:
+ talker_drift_logger_example: main
diff --git a/packages/talker_drift_logger/lib/drift_logs.dart b/packages/talker_drift_logger/lib/drift_logs.dart
new file mode 100644
index 00000000..32d20add
--- /dev/null
+++ b/packages/talker_drift_logger/lib/drift_logs.dart
@@ -0,0 +1,250 @@
+import 'dart:convert';
+
+import 'package:talker/talker.dart';
+import 'package:talker_drift_logger/talker_drift_logger_settings.dart';
+
+const _encoder = JsonEncoder.withIndent(' ');
+const _hiddenValue = '*****';
+
+String _truncate(String input, int? maxChars) {
+ if (maxChars == null) return input;
+ if (input.length <= maxChars) return input;
+ return input.substring(0, maxChars) + '...';
+}
+
+String _maskPatterns(String value, Set patterns) {
+ var v = value;
+ for (final p in patterns) {
+ v = v.replaceAll(p, _hiddenValue);
+ }
+ return v;
+}
+
+List