View Source ExDbug
Debug utility for Elixir applications, inspired by the Node.js 'debug' package. Provides namespace-based filtering, rich metadata support, and compile-time optimization.
Features
- 🔍 Namespace-based debug output filtering
- 📊 Rich metadata support with customizable formatting
- ⚡ Zero runtime cost when disabled (compile-time optimization)
- 🌍 Environment variable-based filtering
- 📝 Automatic metadata truncation for large values
- 🔧 Configurable debug levels and context-based filtering
- 📈 Value tracking through pipelines
- ⏱️ Optional timing and stack trace information
Installation
Add ex_dbug to your list of dependencies in mix.exs:
def deps do
[
{:ex_dbug, "~> 1.0"}
]
endBasic Usage
Add use ExDbug to your module and use the dbug/1,2,3 or error/1,2,3 macros:
defmodule MyApp.Worker do
use ExDbug, context: :worker
def process(data) do
dbug("Processing data", size: byte_size(data))
# ... processing logic
dbug("Completed processing", status: :ok)
end
endConfiguration
Compile-Time Configuration
In your config.exs:
config :ex_dbug,
enabled: true, # Set to false to compile out all debug calls
config: [ # Default options for all ExDbug uses
max_length: 500,
truncate_threshold: 100,
include_timing: true,
include_stack: true,
max_depth: 3,
levels: [:debug, :error]
]Runtime Configuration
Set the DEBUG environment variable to control which namespaces are logged:
# Enable all debug output
DEBUG="*" mix run
# Enable specific namespace
DEBUG="myapp:worker" mix run
# Enable multiple patterns
DEBUG="myapp:*,other:thing" mix run
# Enable all except specific namespace
DEBUG="*,-myapp:secret" mix run
Advanced Usage
Metadata Support
All debug macros accept metadata as keyword lists:
dbug("User login",
user_id: 123,
ip: "192.168.1.1",
timestamp: DateTime.utc_now()
)Long metadata values are automatically truncated based on configuration:
# With default config (truncate_threshold: 100, max_length: 500)
dbug("Big data", data: String.duplicate("x", 1000))
# Output: [context] Big data data: "xxxxx... (truncated)"Value Tracking
Debug values in pipelines without breaking the flow:
def process_payment(amount) do
amount
|> track("initial_amount")
|> apply_fees()
|> track("with_fees")
|> complete_transaction()
endModule Configuration
Configure ExDbug behavior per module:
use ExDbug,
context: :payment_processor,
max_length: 1000,
truncate_threshold: 200,
include_timing: true,
include_stack: false,
levels: [:debug, :error]Debug Levels
Control which log levels are enabled:
# Only show error messages
use ExDbug,
context: :critical_system,
levels: [:error]
# Later in code
error("Critical failure", error: err) # This shows
dbug("Processing") # This doesn'tOutput Format
Debug messages follow this format:
[Context] Message key1: value1, key2: value2Examples:
[payment] Processing payment amount: 100, currency: "USD"
[worker] Job completed status: :ok, duration_ms: 1500Best Practices
- Use descriptive context names matching your application structure
- Include relevant metadata for better debugging context
- Set appropriate DEBUG patterns for different environments
- Disable in production for zero overhead
- Use
track/2for debugging pipeline transformations
Production Use
While ExDbug has minimal overhead when disabled, it's recommended to set
config :ex_dbug, enabled: false in production unless debugging is specifically
needed. This ensures zero runtime cost as debug calls are compiled out completely.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request
License
MIT License - see LICENSE.md for details.