README.md

# ExDbug

[![Hex.pm](https://img.shields.io/hexpm/v/ex_dbug.svg)](https://hex.pm/packages/ex_dbug)
[![Docs](https://img.shields.io/badge/hex-docs-blue.svg)](https://hexdocs.pm/ex_dbug)

Debug utility for Elixir applications, inspired by the Node.js 'debug' package. 
Version 2.0 introduces decorator-based function tracing while maintaining compatibility with 1.x style debugging.

## Features

* 🎯 **Decorator-based function tracing** - Zero-cost, compile-time instrumentation
* 🔄 **1.x Compatibility Mode** - Seamless upgrade path from earlier versions
* 🔍 **Namespace-based filtering** - Filter debug output by context
* 📊 **Rich metadata support** - Attach and format detailed debug information
* ⚡ **Zero runtime cost when disabled** - Compile-time optimization
* 🌍 **Environment variable-based filtering** - Easy runtime control
* 📝 **Automatic metadata truncation** - Smart handling of large values
* 🔧 **Hierarchical configuration** - Global, module, and function-level settings
* 📈 **Value tracking** - Monitor values through pipelines
* ⏱️ **Optional timing and stack traces** - Deep insights when needed

## Installation

Add `ex_dbug` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:ex_dbug, "~> 2.0"}
  ]
end
```

## Usage (2.0 Style)

The new decorator-based approach makes debugging more elegant and maintainable:

```elixir
defmodule MyApp.Worker do
  use ExDbug, enabled: true

  # Simple debug trace
  @decorate dbug()
  def process(data) do
    # Implementation
  end

  # Configured debug trace
  @decorate dbug(context: :important)
  def process_important(data) do
    # Implementation
  end

  # Debug all functions in module
  @decorate_all dbug()
  
  def bulk_1(arg), do: arg
  def bulk_2(arg), do: arg
end
```

## Compatibility Mode (1.x Style)

For existing projects or gradual migration, use compatibility mode:

```elixir
defmodule MyApp.LegacyWorker do
  use ExDbug, compatibility_mode: true

  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`:

```elixir
config :ex_dbug,
  enabled: true,
  config: [
    max_depth: 3,
    include_timing: true,
    include_stack: true,
    truncate: 100,
    levels: [:debug, :error]
  ]
```

### Module-Level Configuration

```elixir
use ExDbug,
  enabled: true,
  max_depth: 5,
  include_timing: true,
  include_stack: false,
  levels: [:debug, :error]
```

### Function-Level Configuration (2.0)

```elixir
@decorate dbug(
  context: :important,
  include_timing: true,
  include_stack: true
)
def critical_function(arg) do
  # Implementation
end
```

### Runtime Configuration

Control debug output using the `DEBUG` environment variable:

```bash
# 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
```

## Migrating from 1.x to 2.0

### Option 1: Direct Upgrade (Recommended)

Replace debug calls with decorators:
```elixir
# Before (1.x)
def process(arg) do
  dbug("Processing", value: arg)
  # Implementation
end

# After (2.0)
@decorate dbug()
def process(arg) do
  # Implementation
end
```

### Option 2: Compatibility Mode

For gradual migration, enable compatibility mode:

```elixir
use ExDbug, compatibility_mode: true
# All 1.x code continues to work
```

### Configuration Updates

Update your configuration to use the new hierarchical structure:

```elixir
# Before (1.x)
config :ex_dbug, enabled: true

# After (2.0)
config :ex_dbug,
  enabled: true,
  config: [
    max_depth: 3,
    include_timing: true
  ]
```

## Best Practices

1. Use descriptive context names matching your application structure
2. Prefer decorator-based debugging for new code
3. Use compatibility mode for gradual migration
4. Set appropriate DEBUG patterns for different environments
5. Configure hierarchically (global → module → function)
6. Disable in production for zero overhead

## 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

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

## License

MIT License - see LICENSE.md for details.