View Source ExDbug (ExDbug v2.1.0)

ExDbug

Hex.pm Docs

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

  1. Use descriptive context names matching your application structure
  2. Include relevant metadata for better debugging context
  3. Set appropriate DEBUG patterns for different environments
  4. Disable in production for zero overhead
  5. 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

debug_opts()

@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()
]

Functions

dbug(message, metadata \\ [])

(macro)

error(message, metadata \\ [])

(macro)

format_output(message, context, metadata, opts \\ %{})

track(value, name)

(macro)