View Source ExDbug (ExDbug v1.2.0)
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"}
]
end
Basic 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
end
Configuration
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()
end
Module 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't
Output Format
Debug messages follow this format:
[Context] Message key1: value1, key2: value2
Examples:
[payment] Processing payment amount: 100, currency: "USD"
[worker] Job completed status: :ok, duration_ms: 1500
Best 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/2
for 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.
Summary
Types
@type debug_opts() :: [ enabled: boolean(), context: atom() | String.t(), max_depth: non_neg_integer(), include_timing: boolean(), include_stack: boolean(), truncate: boolean() | non_neg_integer() ]