This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
df_log is a standalone Dart package published to pub.dev (https://pub.dev/packages/df_log). It is part of the df_* ecosystem by dev-cetera and is consumed by external apps as well as by the parent compledo monorepo it currently sits inside.
It has no Flutter dependency. Pure Dart, runs anywhere Dart runs (VM, web, isolates). Don't add Flutter imports.
The README (README.md) is the user-facing docs and is regenerated from _README_CONTENT.md by CI — edit _README_CONTENT.md for content changes between the <!-- BEGIN _README_CONTENT --> markers, never the README directly.
# From the package root (/packages/df_log/):
# Run the full test suite
dart test
# Run a single test file
dart test test/df_log_test.dart
# Run a single test by name
dart test test/df_log_test.dart -n "Log.info stores a log item"
# Format / fix / analyze (CI runs format + fix + analyze on release)
dart format .
dart fix --apply
dart analyze
# Run the example
dart run example/example.dart
# Custom lints (df_safer_dart_lints) run via custom_lint
dart run custom_lintThe whole package is three files in lib/src/, exported through a generated barrel:
log.dart— theLogfinal class. All-static, never instantiated. Holds global state (activeTags,itemsqueue,callbacks, styling/storage flags,context) and the category methods (info,err,ok,alert,start,stop,trace,ignore,message) plus theprintRed/printGreen/… color helpers. Every category method funnels intoLog.log(...)→_printLog(...).log_item.dart—LogItem, the immutable record of one log call. Carriesid,timestamp,frame,location,icon,message,metadata,tags,context,internalIndex. Knows how to render itself (toConsoleString,toStyledConsoleString,toMap,toJson).ansi_styled_string.dart—AnsiStylevalue object plus aString.withAnsiStyle(...)extension. Styles compose with+.
Three structural details that are easy to miss:
-
Logs are stripped from release builds by default.
Log.logwraps the print path inassert(() { ... return true; }()). In AOT/release the assert is gone, so nothing prints unlessLog.enableReleaseAsserts = true. When you add a new logging entry point, follow the existing pattern inlog.dart— don't bypass the assert wrapper. -
All
Logstatic state is per-isolate. Dart statics aren't shared across isolates, soLog.context,Log.items,Log.activeTags,Log.callbacks, etc. are independent in each isolate.Log.contextexists specifically so log lines from different isolates can be told apart in the shared stdout. Don't introduce cross-isolate shared state — the design depends on this isolation. -
Call-site location comes from
df_safer_dart'sHere(...), not a rawStackTrace. Each public entry point passesinitialStackLevel + Ndown into_printLog, whereNaccounts for the inlined hops. Adding a new wrapper method means picking the rightinitialStackLeveloffset — copy from a sibling method (Log.info, etc.) and verify the printed[file/method #line]points at the caller, not atlog.dart.
lib/src/_src.g.dart is regenerated by df_generate_dart_indexes and re-exports everything in lib/src/. Add a new file to lib/src/, then regenerate the barrel — never hand-edit _src.g.dart. lib/df_log.dart is the public entry point and only re-exports the barrel; lib/_common.dart is an internal-only barrel of third-party imports used inside the package (Queue, JsonEncoder, max, Here, Frame, Uuid, visibleForTesting) and is the import path for files in lib/src/ (import '/_common.dart';).
- Categorized logging is the public surface (
Log.info,Log.err,Log.ok,Log.alert,Log.trace,Log.start,Log.stop,Log.message,Log.ignore). Each one auto-applies a category tag (e.g.#info,#err) so users can filter viaactiveTags. - Enum names use UPPER_SNAKE_CASE (e.g.
_IconCategory.TRACE) — the analyzer ruleconstant_identifier_namesis intentionally disabled inanalysis_options.yamlto allow this. Don't "fix" the casing. - Single quotes, trailing commas,
constconstructors,prefer_relative_imports— enforced byanalysis_options.yaml. Violations are errors, not warnings. - The
@visibleForTesting int initialStackLevel = 0parameter on every public log entry exists so tests can inject the right stack offset. Don't remove it. - Tests reset all
Logstatic state insetUp(seetest/df_log_test.dart). New tests must do the same — global state leaks between tests otherwise.
Releases are driven entirely by commit messages on main, handled by .github/workflows/process-package.yml:
- Commit starting with
+→ CI runsdart format,dart fix, regenerates README + CHANGELOG, bumps version, creates a git tag. - Commit starting with
++→ same as above, plus a full release (the publish step is currently commented out in the workflow but the prepare step is live). - The release-notes line in
CHANGELOG.mdcomes from the commit message after stripping the leading+/++.
So: a normal commit does nothing special; a commit like +Add isolate support triggers the version-bump pipeline. Never bump the version in pubspec.yaml by hand — let CI do it.