You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#The Ultimate Guide to `df_log`: Go Beyond `print()`in Flutter
1
+
## Tired of `print()`? A Pragmatic Guide to Better Logging in Flutter.
2
2
3
-
### A beginner-friendly tutorial and complete reference manual for making your Flutter debugging, analytics, and crash reporting smarter.
3
+
### An honest, beginner-friendly look at `df_log` — a package that aims to make your console debugging, analytics, and crash reporting smarter, not just more complicated.

6
6
7
-
If you're a Flutter developer, your journey probably started with `print()`. It’s our oldest and most reliable friend for debugging. We sprinkle it everywhere to check a variable's value, confirm a function was called, or see if a widget rebuilt.
7
+
If you're a Flutter developer, your journey started with `print()`. It’s our oldest friend for debugging. We sprinkle it everywhere to check a variable, confirm a function was called, or see if a widget rebuilt.
8
8
9
-
But let's be honest. As our apps grow, the console becomes a chaotic wall of white text.
9
+
But as our apps grow, the console becomes a chaotic, colorless waterfall of text.
10
10
11
11
```
12
12
Button tapped
@@ -16,40 +16,25 @@ Network error
16
16
UI updated
17
17
```
18
18
19
-
You're left asking: _Which_ button was tapped? _Where_ did the network error happen? This ambiguity is where we waste precious time.
19
+
You're left asking: *Which* button was tapped? *Where* did that network error happen? This ambiguity is where we waste precious time.
20
20
21
-
What if your logs could be smart, organized, beautiful, and tell you _exactly_ where they came from? What if they could power your analytics and crash reporting automatically?
21
+
Of course, there are powerful, "correct" ways to debug. The **Flutter Debugger** is an incredible tool that lets you pause your app with breakpoints, inspect the entire state, and step through code line by line. For complex bug hunting, it’s unbeatable.
22
22
23
-
Meet **[df_log](https://pub.dev/packages/df_log)**, a simple but profoundly powerful logging package for Dart and Flutter. This guide will take you from a complete beginner to a master of `df_log`, showing you how it will fundamentally change the way you build and debug your apps.
23
+
So, why talk about another logging package?
24
24
25
-
---
26
-
27
-
### Part 1: Your First Steps - The 5-Minute Upgrade
28
-
29
-
Let’s get you started. The initial payoff is immediate.
25
+
Because sometimes, you don’t want to pause your app. You just want to watch the story of your code unfold in the console. You want the simplicity of `print()` but with more clarity, context, and control. What if your logs could also power your analytics and crash reporting automatically?
30
26
31
-
#### Installation
27
+
Meet **[df_log](https://pub.dev/packages/df_log)**, a pragmatic, opinionated tool designed to do one thing well: **make your console output beautiful, readable, and powerful.**
32
28
33
-
1. Open your `pubspec.yaml` file.
34
-
2. Add `df_log` to your dependencies:
35
-
36
-
```yaml
37
-
dependencies:
38
-
flutter:
39
-
sdk: flutter
40
-
df_log: ^latest_version # Check pub.dev for the latest version
41
-
```
29
+
---
42
30
43
-
3. Run `flutter pub get` in your terminal.
44
-
4. Import the package in any Dart file where you want to log:
31
+
### Part 1: Your First Steps - The 5-Minute Upgrade
45
32
46
-
```dart
47
-
import 'package:df_log/df_log.dart';
48
-
```
33
+
The initial payoff is immediate. After adding `df_log` to your `pubspec.yaml` and importing it, you can immediately upgrade your `print()` statements.
49
34
50
35
#### Your First "Smart" Log
51
36
52
-
Now, replace a `print()` statement with a `df_log` equivalent.
37
+
Replace a `print()` statement with a `df_log` equivalent.
Run your app and look at the console. Instead of plain text, you’ll see something like this:
67
54
68
-
`🟢 [lib/data/auth_repository.dart:42] User successfully authenticated.`
55
+
`🟢 [auth_service/authenticateUser #42] User successfully authenticated.`
69
56
70
57
This is the first "Aha!" moment. You instantly get three upgrades:
71
58
72
59
1.**A Category Icon (`🟢`):** You can tell at a glance that this was a success.
73
-
2. **The Exact Location:** You know this log came from `auth_repository.dart` on line `42`. No more guessing! You can click this in most IDEs to jump straight to the code.
60
+
2.**Precise Context `[filename/member #linenumber]`:** You know exactly where this log came from: the `authenticateUser` function inside the `auth_service.dart` file, on line `42`. No more guessing! You can click this in most IDEs to jump straight to the code.
74
61
3.**Color:** In supported consoles, the output is beautifully colored, making it easy to scan.
75
62
76
63
You’ve already saved yourself minutes of future debugging time.
@@ -83,7 +70,7 @@ Now let's explore the foundational features that make `df_log` so effective.
83
70
84
71
#### 1. Semantic Logging: Speaking with Intent
85
72
86
-
`df_log`provides methods for different kinds of events. This gives your logs meaning.
73
+
`df_log` provides methods for different kinds of events. This gives your logs meaning and turns your console into a readable story of your app's execution.
87
74
88
75
```dart
89
76
void main() {
@@ -96,8 +83,6 @@ void main() {
96
83
}
97
84
```
98
85
99
-
This turns your console into a readable story of your app's execution, not just a random list of events.
100
-
101
86
#### 2. Precision Filtering with Tags
102
87
103
88
This is arguably the most powerful debugging feature. You can assign tags to your logs and then filter the console to show only what you need.
@@ -110,15 +95,12 @@ Let’s see it in action.
110
95
// main.dart
111
96
void main() {
112
97
// Let's say we only want to debug the UI for the authentication flow.
113
-
Log.addTags({#ui, #auth});
98
+
Log.activeTags = {#ui, #auth};
114
99
115
100
// ✅ Printed! Has the #auth tag, which is active.
116
101
Log.ok('User logged in.', {#auth});
117
102
118
-
// ✅ Printed! Has the #ui tag, which is active.
119
-
Log.info('Rendering profile screen...', {#ui});
120
-
121
-
// ❌ NOT Printed! It requires the #network tag, which we haven't activated.
103
+
// ❌ NOT Printed! It requires the #network tag, which we haven't activated yet.
122
104
Log.trace('Fetching user avatar...', {#ui, #network});
123
105
124
106
// --- Now, let's debug the network call for the avatar ---
@@ -137,11 +119,11 @@ With tags, you can silence the noise from every other part of your app and focus
137
119
138
120
This is where `df_log` transcends being just a logger. Using callbacks, you can turn it into a central event bus for your entire application.
139
121
140
-
The `Log.addCallback()` method lets you execute a function every single time a log is created, giving you access to the complete `LogItem` object (message, tags, timestamp, etc.).
122
+
The `Log.addCallback()` method lets you execute a function every single time a log is created, giving you access to the complete `LogItem` object.
141
123
142
124
#### Use Case 1: Smarter Crash Reporting with Breadcrumbs
143
125
144
-
When a crash happens, the error message is only half the story. The other half is _what the user did right before it_. `df_log` can automatically provide this context.
126
+
When a crash happens, the error message is only half the story. The other half is *what the user did right before it*. `df_log` can automatically provide this context.
145
127
146
128
```dart
147
129
// In your main.dart
@@ -157,7 +139,7 @@ void main() {
157
139
// Get the history of recent events.
158
140
final breadcrumbs = Log.items.map((item) => item.toMap()).toList();
159
141
160
-
// Send the error and the breadcrumbs to your reporting service.
142
+
// Send the error and the breadcrumbs to your reporting service (e.g., Sentry).
161
143
MyCrashReporter.captureException(
162
144
exception: logItem.message,
163
145
extraData: {'log_breadcrumbs': breadcrumbs},
@@ -172,7 +154,6 @@ void main() {
172
154
void updateUserProfile() {
173
155
Log.info('Navigated to profile screen.', {#ui, #profile});
174
156
try {
175
-
// ... code that might fail ...
176
157
throw Exception('Connection timed out');
177
158
} catch (e) {
178
159
// This single line now does two things:
@@ -194,7 +175,11 @@ void setupAnalytics() {
194
175
if (logItem.tags.contains(#analytics_event)) {
195
176
// The log message can be the event name!
196
177
final eventName = logItem.message.toString();
197
-
MyAnalyticsService.logEvent(name: eventName);
178
+
// The LogItem can be converted to a map for parameters.
179
+
final parameters = logItem.toMap();
180
+
181
+
// Send to your service, e.g., Google Analytics / Firebase
If you ever change your analytics provider, you only have to update one callback function, not hundreds of files. Your code becomes cleaner and completely decoupled from the analytics implementation.
196
+
If you ever change your analytics provider, you only have to update **one callback function**, not hundreds of files. Your code becomes cleaner and completely decoupled from the analytics implementation.
212
197
213
198
---
214
199
215
-
### Part 4: The Official `df_log` Manual (API Reference)
200
+
### Part 4: The `df_log` Manual (Full Feature Set)
216
201
217
-
Here is a quick reference to all the main features available in `df_log`.
202
+
Here is a quick reference to all the main features available.
218
203
219
204
#### Main Logging Methods
220
205
221
-
- `Log.info(message, [tags])`: For general informational messages. (`🟣`)
222
-
- `Log.ok(message, [tags])`: For success operations. (`🟢`)
223
-
- `Log.err(message, [tags])`: For errors or exceptions. (`🔴`)
224
-
- `Log.alert(message, [tags])`: For warnings that need attention. (`🟠`)
225
-
- `Log.start(message, [tags])`: To mark the beginning of a process. (`🔵`)
226
-
- `Log.stop(message, [tags])`: To mark the end of a process. (`⚫`)
227
-
- `Log.trace(message, [tags])`: For fine-grained debugging information. (`⚪️`)
228
-
- `Log.printGreen(message)`: Prints a message in a specific color without any other formatting. Many other colors are available (`printRed`, `printYellow`, etc.).
206
+
-`Log.info(msg, [tags])`: For general informational messages. (`🟣`)
207
+
-`Log.ok(msg, [tags])`: For success operations. (`🟢`)
208
+
-`Log.err(msg, [tags])`: For errors or exceptions. (`🔴`)
209
+
-`Log.alert(msg, [tags])`: For warnings that need attention. (`🟠`)
210
+
-`Log.start(msg, [tags])`: To mark the beginning of a process. (`🔵`)
211
+
-`Log.stop(msg, [tags])`: To mark the end of a process. (`⚫`)
212
+
-`Log.trace(msg, [tags])`: For fine-grained debugging information. (`⚪️`)
213
+
-`Log.printGreen(message)`: Prints a message in a specific color without any other formatting. Many other colors are available (`printRed`, `printYellow`, `printBlue`, etc.).
229
214
230
215
#### Configuration (Static Properties on `Log`)
231
216
232
-
- `Log.enableStyling = true`: Enables/disables ANSI colors and icons. Set to `false` if your console doesn't support them.
233
-
- `Log.showTimestamps = true`: Shows a `HH:mm:ss.SSS` timestamp on each log.
234
-
- `Log.showTags = true`: Shows tags like `#auth #ui` on each log.
235
-
- `Log.showIds = false`: Shows a unique ID on each log.
236
-
- `Log.enableReleaseAsserts = false`: By default, logs only work in debug mode. Set this to `true` to enable logging and asserts in release builds (use with caution).
217
+
-`Log.enableStyling = true`: Enables/disables ANSI colors and icons.
218
+
-`Log.showTimestamps = true`: Shows a `HH:mm:ss.SSS` timestamp on each log.
219
+
-`Log.showTags = true`: Shows tags like `#auth #ui` on each log.
220
+
-`Log.showIds = false`: Shows a unique ID on each log.
221
+
-`Log.enableReleaseAsserts = false`: By default, logs only work in debug mode. Set to `true` to enable logging in release builds (use with caution).
237
222
238
-
#### In-Memory Storage
223
+
#### In-Memory Storage & Callbacks
239
224
240
-
- `Log.storeLogs = true`: If `true`, keeps a history of logs in memory.
241
-
- `Log.maxStoredLogs = 1000`: Sets the maximum number of `LogItem` objects to store in the queue.
242
-
- `Log.items`: A `Queue<LogItem>` containing the stored logs. You can access it directly to inspect history.
225
+
-`Log.storeLogs = true`: If `true`, keeps a history of logs in memory.
226
+
-`Log.maxStoredLogs = 1000`: Sets the max number of `LogItem` objects to store.
227
+
-`Log.items`: A `Queue<LogItem>` containing the stored logs.
228
+
-`Log.addCallback(callback)`: Registers a function `void Function(LogItem item)` that runs for every log.
229
+
-`Log.removeCallback(callback)`: Removes a previously registered callback.
243
230
244
-
#### Tag Management
231
+
#### Advanced Output
245
232
246
-
- `Log.activeTags`: A `Set<Symbol>` of all currently active tags.
247
-
- `Log.addTags(Set<Symbol> tags)`: Adds one or more tags to the active set.
248
-
- `Log.removeTags(Set<Symbol> tags)`: Removes tags from the active set.
233
+
-`Log.useDeveloperLog()`: Switches output to `dart:developer`'s `log` function for a richer experience in some IDEs.
234
+
-`Log.useStandardPrint()`: Reverts the output to the standard `print` function.
249
235
250
-
#### Advanced Features
236
+
---
251
237
252
-
- `Log.addCallback(callback)`: Registers a function `void Function(LogItem item)` that is called every time a log is created. Returns the callback so you can remove it later.
253
-
- `Log.removeCallback(callback)`: Removes a previously registered callback.
254
-
- `Log.useDeveloperLog()`: Switches the output to `dart:developer`'s `log` function, which can provide a richer experience in IDEs like VS Code's Debug Console.
255
-
- `Log.useStandardPrint()`: Reverts the output to the standard `print` function.
238
+
### Final Thoughts: Is This For You?
256
239
257
-
---
240
+
Let’s be clear to pre-emptively address the critics. `df_log` is not trying to be the most powerful logging framework in the world.
241
+
242
+
- If you need advanced features like log rotation, writing to files, or complex custom formatters, a package like `logger` or `floggy` might be a better choice.
243
+
- If you are deep in a bug and need to inspect object properties and the call stack, **use the Flutter Debugger**. It is the right tool for that job.
258
244
259
-
### Conclusion
245
+
So, who is `df_log` for?
260
246
261
-
`df_log` is more than just a pretty logger. It's a complete instrumentation framework that encourages you to treat events in your app as structured data. By adopting it, you get:
247
+
It’s for the developer who finds themselves littering their code with `print('--- HERE 1 ---')` and wishes it was just a little bit… better. It’s for adding semantic, colorful, filterable breadcrumbs to trace the flow of an application. It's for centralizing your app's event-based logic, like analytics and crash reporting, through a single, clean API.
262
248
263
-
- **Clarity:** Know exactly where every log comes from.
264
-
- **Organization:** Use categories and tags to make your console readable and filterable.
265
-
- **Power:** Use callbacks to drive crash reporting, analytics, and performance monitoring from a single, clean source of truth.
249
+
The goal is to be **pragmatic**: to provide a massive step up from `print()` without the cognitive overhead of a full-fledged logging framework. It's a simple tool for a common, multifaceted problem.
266
250
267
-
It's a small change to your workflow that pays massive dividends in productivity and code quality.
251
+
If that sounds like something that could clean up your debug console and your codebase, give it a try.
268
252
269
-
This is an open-source project actively maintained by **[Robert Mollentze](https://github.com/robert-mollentze)** and contributors. If you find it valuable, give the [GitHub repo](https://github.com/dev-cetera/df_log) a star, and consider [buying the author a coffee](https://www.buymeacoffee.com/dev_cetera) to support future development. Happy logging!
253
+
This is an open-source project. If you find it valuable, give the [**GitHub repo**](https://github.com/dev-cetera/df_log) a star, and consider [**buying the author a coffee**](https://www.buymeacoffee.com/dev_cetera) to support future development. Happy logging
0 commit comments