|
9 | 9 |
|
10 | 10 | --- |
11 | 11 |
|
12 | | -## Summary |
| 12 | +`df_log` is a massive upgrade from `print()`. It makes your console output beautiful, readable, and powerful, turning your logs into a central event bus for debugging, analytics, and crash reporting. It’s for the developer who wants the simplicity of `print()` but with more clarity, context, and control. |
13 | 13 |
|
14 | | -A starting point for Dart or Flutter packages. |
| 14 | +## ✨ Features |
15 | 15 |
|
16 | | -## Installation |
| 16 | +- **Categorized Logging:** Pre-defined methods like `Log.info`, `Log.err`, `Log.ok` for semantic logging. |
| 17 | +- **Beautifully Styled Output:** Uses ANSI colors and emojis for clear, readable logs in supported consoles. |
| 18 | +- **Tag-Based Filtering:** Assign tags to logs and filter the console output to show only what you need. |
| 19 | +- **In-Memory Log Storage:** Keeps a configurable queue of recent logs for debugging or inspection. |
| 20 | +- **Release Mode Control:** Configure logs and assertions to be active even in release builds. |
| 21 | +- **Customizable Output:** Show or hide timestamps, log IDs, and tags. |
| 22 | +- **IDE Integration:** Optionally uses `dart:developer`'s `log` function for a richer experience in some IDEs. |
| 23 | +- **Isolate-Friendly:** Set `Log.context` per isolate to instantly see where logs come from. Works on web too. |
| 24 | +- **Log Export:** Export stored logs as JSONL with `Log.exportLogsAsJsonLines()`. |
| 25 | +- **Extensible:** Add custom callbacks to integrate with other services (e.g., crash reporting). |
17 | 26 |
|
18 | | -```sh |
19 | | -dart pub add df_log |
20 | | -# or, for a Flutter project: |
21 | | -flutter pub add df_log |
22 | | -``` |
| 27 | +## 🚀 Getting Started |
| 28 | + |
| 29 | +For an introduction, please refer to this article: |
| 30 | + |
| 31 | +- **MEDIUM.COM** [Dart Logging: Your New Best Friend](https://medium.com/@dev-cetera/dart-logging-your-new-best-friend-7e0dbd701dc7) |
| 32 | +- **DEV.TO** [Dart Logging: Your New Best Friend](https://dev.to/dev_cetera/dart-logging-your-new-best-friebd-ae1) |
| 33 | +- **GITHUB** [Dart Logging: Your New Best Friend](https://github.com/dev-cetera/df_log/blob/main/ARTICLE.md) |
| 34 | + |
| 35 | +## 🧐 Overview |
23 | 36 |
|
24 | | -## Usage |
| 37 | +### 💡 1. Categorized Logs |
| 38 | + |
| 39 | +The package comes with a few default log types that you can use creatively. |
25 | 40 |
|
26 | 41 | ```dart |
27 | 42 | import 'package:df_log/df_log.dart'; |
28 | 43 |
|
29 | 44 | void main() { |
30 | | - // ... |
| 45 | + Log.start('Application starting...'); |
| 46 | + Log.info('Checking for user session...'); |
| 47 | + Log.alert('Network connection is slow. Retrying in 5s.'); |
| 48 | + Log.ok('User session found and validated.'); |
| 49 | + Log.err('Failed to load user preferences!'); |
| 50 | + Log.stop('Application shutting down.'); |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +### 💡 2. Colored Logs |
| 55 | + |
| 56 | +Colored logs enhance readability and help you quickly identify different types of messages in the console. By applying distinct colors, you can easily track errors, successes, warnings, and other log types at a glance. |
| 57 | + |
| 58 | +```dart |
| 59 | +Log.printRed('This is printed in RED!'); |
| 60 | +Log.printGreen('This is printed in GREEN!'); |
| 61 | +Log.printBlue('This is printed in BLUE!'); |
| 62 | +Log.printYellow('This is printed in YELLOW!'); |
| 63 | +Log.printCyan('This is printed in CYAN!'); |
| 64 | +Log.printPurple('This is printed in PURPLE!'); |
| 65 | +Log.printBlack('This is printed in BLACK!'); |
| 66 | +Log.printWhite('This is printed in WHITE!'); |
| 67 | +// and many more... |
| 68 | +``` |
| 69 | + |
| 70 | +### 💡 3. Tags |
| 71 | + |
| 72 | +Using tags with logs simplifies debugging and organization. Tags allow you to filter logs by including or excluding specific categories, making it easier to focus on relevant information. They can also help categorize data for analytics or other purposes. |
| 73 | + |
| 74 | +```dart |
| 75 | +// main.dart |
| 76 | +void main() { |
| 77 | + // Only show logs tagged with #auth or #ui. |
| 78 | + Log.addTags({#auth, #ui}); |
| 79 | +
|
| 80 | + // Printed! |
| 81 | + Log.info('Initializing UI elements...', tags: {#ui}); |
| 82 | + Log.ok('User logged in.', tags: {#auth}); |
| 83 | + Log.trace('Connecting to database...', tags: {#auth, #firebase}); |
| 84 | +
|
| 85 | + // Not printed - #db tag doesn't exist! |
| 86 | + Log.trace('Connecting to database...', tags: {#db}); |
| 87 | +
|
| 88 | + // Not printed - #ui exists but #button doesn't! |
| 89 | + Log.trace('Rendering button...', tags: {#ui, #button}); |
| 90 | +
|
| 91 | + // Printed! |
| 92 | + Log.addTags({#button}); |
| 93 | + Log.trace('Rendering button...', tags: {#ui, #button}); |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +### 💡 4. Structured Metadata |
| 98 | + |
| 99 | +Pair a log with a structured `metadata` payload that travels through `Log.addCallback` to analytics or crash reporting. The console output stays human-readable; the metadata is for machines. |
| 100 | + |
| 101 | +```dart |
| 102 | +void main() { |
| 103 | + // Forward user-action logs to analytics, with their metadata as event params. |
| 104 | + Log.addCallback((logItem) { |
| 105 | + if (logItem.tags.contains(#userAction)) { |
| 106 | + final metadata = logItem.metadata as Map<String, Object?>?; |
| 107 | + // analytics.logEvent(name: logItem.message.toString(), parameters: metadata); |
| 108 | + } |
| 109 | + }); |
| 110 | +
|
| 111 | + // Call sites pass a stable event name as the message and the params as metadata. |
| 112 | + Log.info( |
| 113 | + 'create_group', |
| 114 | + tags: {#userAction}, |
| 115 | + metadata: {'has_description': true, 'member_count': 1}, |
| 116 | + ); |
| 117 | +
|
| 118 | + Log.err( |
| 119 | + 'item_sync_failed', |
| 120 | + tags: {#userAction}, |
| 121 | + metadata: {'item_id': 'abc123', 'status_code': 500}, |
| 122 | + ); |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +`metadata` is `Object?`, so any serializable shape works (maps, lists, nested structures). It also lands in `LogItem.toJson()`, so `Log.exportLogsAsJsonLines()` carries it through. |
| 127 | + |
| 128 | +### 💡 5. Isolate Context |
| 129 | + |
| 130 | +When debugging across isolates, set `Log.context` at the start of each isolate. Since Dart statics are per-isolate, each isolate gets its own value automatically - no locking, no shared state, no complexity. |
| 131 | + |
| 132 | +```dart |
| 133 | +void main() { |
| 134 | + Log.context = 'MAIN'; |
| 135 | + Log.info('Starting app'); |
| 136 | + // Output: [🟣 example #5 MAIN] Starting app |
| 137 | + runApp(const App()); |
| 138 | +} |
| 139 | +
|
| 140 | +@pragma("vm:entry-point") |
| 141 | +void overlayMain() { |
| 142 | + Log.context = 'OVERLAY'; |
| 143 | + Log.info('Overlay started'); |
| 144 | + // Output: [🟣 example #5 OVERLAY] Overlay started |
| 145 | + runApp(const Overlay()); |
| 146 | +} |
| 147 | +``` |
| 148 | + |
| 149 | +Use a short tag like `M` to save space, or a full string like `ISOLATE_MAIN` for clarity. |
| 150 | + |
| 151 | +**How it works:** In Dart, each isolate has its own memory. All `Log` statics (`context`, `items`, `activeTags`, etc.) are independent per isolate. This means `Log.context = 'OVERLAY'` in one isolate has zero effect on another. The only shared thing is the console output (stdout), which is why `Log.context` exists - so you can tell which isolate printed what. This works on all platforms including web. |
| 152 | + |
| 153 | +### 💡 6. Configuration |
| 154 | + |
| 155 | +You can customize the logging behavior to suit your needs, including styling, output format, and storage options. The Log class provides various settings to control how logs are displayed and managed. |
| 156 | + |
| 157 | +```dart |
| 158 | +void main() { |
| 159 | + // Set a label for the current isolate (useful for multi-isolate debugging). |
| 160 | + Log.context = 'MAIN'; |
| 161 | +
|
| 162 | + // Enable or disable ANSI colors and icons. Disable this if your console doesn't support it. |
| 163 | + Log.enableStyling = true; |
| 164 | +
|
| 165 | + // Show a timestamp like 'HH:mm:ss.SSS' in the printed output. |
| 166 | + Log.showTimestamps = true; |
| 167 | +
|
| 168 | + // Show tags like '#auth #network' in the printed output. |
| 169 | + Log.showTags = true; |
| 170 | +
|
| 171 | + // Show a unique ID for each log item in the printed output. |
| 172 | + Log.showIds = false; |
| 173 | +
|
| 174 | + // By default, logs only appear in debug mode. |
| 175 | + Log.enableReleaseAsserts = true; |
| 176 | +
|
| 177 | + // Keep a history of logs in memory. |
| 178 | + Log.storeLogs = true; |
| 179 | +
|
| 180 | + // Set the max number of logs to store. |
| 181 | + Log.maxStoredLogs = 500; |
| 182 | +
|
| 183 | + // Use a richer log viewer in supported IDEs (like VS Code's Debug Console). |
| 184 | + Log.useDeveloperLog(); |
| 185 | +
|
| 186 | + // Or revert to the standard `print` function. |
| 187 | + Log.useStandardPrint(); |
| 188 | +
|
| 189 | + // Add a function to trigger each time a log is added. |
| 190 | + final callback = Log.addCallback((LogItem logItem) { |
| 191 | + final json = logItem.toJson(); |
| 192 | + // TODO: Send your log to something like Google Analytics. |
| 193 | + }); |
| 194 | +
|
| 195 | + // Remove an existing callback. |
| 196 | + Log.removeCallback(callback); |
| 197 | +
|
| 198 | + // Get notified when old logs are discarded from the queue. |
| 199 | + Log.onLogDiscarded = (discardedItem) { |
| 200 | + // TODO: Forward to analytics before it's gone. |
| 201 | + }; |
| 202 | +
|
| 203 | + // Clear log history. |
| 204 | + Log.clear(); |
| 205 | +
|
| 206 | + // Export all stored logs as a JSONL string. |
| 207 | + final jsonl = Log.exportLogsAsJsonLines(); |
| 208 | +
|
| 209 | + runApp(MyApp()); |
31 | 210 | } |
32 | 211 | ``` |
33 | 212 |
|
@@ -57,8 +236,6 @@ No matter how you choose to contribute, your involvement is greatly appreciated |
57 | 236 |
|
58 | 237 | If you're enjoying this package and find it valuable, consider showing your appreciation with a small donation. Every bit helps in supporting future development. You can donate here: https://www.buymeacoffee.com/dev_cetera |
59 | 238 |
|
60 | | -<a href="https://www.buymeacoffee.com/dev_cetera" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" height="40"></a> |
61 | | - |
62 | 239 | ## LICENSE |
63 | 240 |
|
64 | 241 | This project is released under the [MIT License](https://raw.githubusercontent.com/dev-cetera/df_log/main/LICENSE). See [LICENSE](https://raw.githubusercontent.com/dev-cetera/df_log/main/LICENSE) for more information. |
0 commit comments