# TeleDec
Zero-dependency Elixir library for declarative telemetry instrumentation using compile-time decorators.
TeleDec provides a clean, efficient way to add telemetry events to your functions with minimal boilerplate. Simply add `@telemetry` attributes to your functions, and the library handles all the instrumentation at compile-time with negligible runtime overhead.
## Features
- **Zero Dependencies** - Only requires the standard `:telemetry` library
- **Compile-Time Code Generation** - All instrumentation happens at compile-time with no runtime reflection
- **Auto-Inferred Event Names** - Automatically generate event names from module and function names
- **Multiple Modes** - Choose between full span tracking or fast one-shot events
- **Performance Optimized** - Minimal overhead (~700ns for span mode, ~300ns for one-shot mode)
- **Flexible Configuration** - Global and per-function configuration options
- **Selective Metadata** - Capture only the arguments and variables you need
## Installation
Add `tele_dec` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:tele_dec, "~> 0.1.0"}
]
end
```
## Quick Start
### Basic Usage with Auto-Inferred Names
```elixir
# config/config.exs
config :tele_dec, app: :my_app
# lib/my_app/user_service.ex
defmodule MyApp.UserService do
use TeleDec
@telemetry_service :user_service
@telemetry true
def create_user(attrs) do
# Your implementation
# Emits: [:my_app, :user_service, :create_user, :start/:stop/:exception]
end
@telemetry include: [:user_count]
def list_users() do
users = fetch_users()
user_count = length(users) # This will be included in telemetry metadata
users
end
end
```
### Explicit Event Names
```elixir
defmodule MyApp.Service do
use TeleDec
@telemetry {[:my_app, :service, :process], []}
def process(data) do
# Implementation
# Emits: [:my_app, :service, :process, :start/:stop/:exception]
end
end
```
## Configuration
### Global Configuration
Set in `config/config.exs`:
```elixir
config :tele_dec,
app: :my_app, # Application name prefix for auto-inferred events
enabled: true # Global enable/disable flag (default: true)
```
### Module Configuration
```elixir
defmodule MyApp.Service do
use TeleDec
# Set service name for auto-inferred event names
@telemetry_service :service_name
# Functions...
end
```
### Function Options
```elixir
# Auto-infer event name
@telemetry true
# Auto-infer with options
@telemetry include: [:computed_value]
# Explicit event name
@telemetry {[:custom, :event], [include: [:var1]]}
# Available options:
# - mode: :span (default) or :one_shot
# - include: list of variables to include in stop event metadata
# - args: list of specific arguments to capture (default: all)
# - metadata: set to false to skip all metadata capture
# - enabled: set to false to disable at compile-time
```
## Performance Modes
### Span Mode (default)
Full telemetry span with start, stop, and exception events:
```elixir
@telemetry true
def process(data) do
# ~700ns overhead
end
```
### One-Shot Mode
Single event on completion, approximately 2x faster:
```elixir
@telemetry mode: :one_shot
def fast_operation(x, y) do
# ~300ns overhead
# No start event, no exception tracking
end
```
### Metadata-Free Mode
Maximum performance, no metadata capture:
```elixir
@telemetry metadata: false
def high_frequency_operation() do
# Minimal overhead
end
```
## Performance Characteristics
TeleDec is designed for minimal overhead:
- **Baseline** function call: ~27ns
- **Disabled** telemetry (`enabled: false`): ~32ns (5ns overhead)
- **One-shot mode**: ~300ns
- **Span mode** (full instrumentation): ~700ns
All metadata capture happens at compile-time via direct map construction, avoiding runtime reflection and `Kernel.binding()` calls.
## Event Structure
### Span Mode Events
- `event_name ++ [:start]` - Emitted when function starts
- Measurements: `%{monotonic_time: integer}`
- Metadata: Function arguments
- `event_name ++ [:stop]` - Emitted when function completes successfully
- Measurements: `%{duration: integer}`
- Metadata: Arguments + result + included variables
- `event_name ++ [:exception]` - Emitted when function raises
- Measurements: `%{duration: integer}`
- Metadata: Arguments + error info (kind, reason, stacktrace)
### One-Shot Mode Events
- `event_name` - Single event emitted on completion
- Measurements: `%{duration: integer}`
- Metadata: Arguments + result + included variables
- No exception tracking
## Attaching Handlers
Use standard `:telemetry` functions to attach handlers:
```elixir
:telemetry.attach_many(
"my-handler",
[
[:my_app, :user_service, :create_user, :start],
[:my_app, :user_service, :create_user, :stop],
[:my_app, :user_service, :create_user, :exception]
],
fn event, measurements, metadata, config ->
# Handle event
end,
%{some: :config}
)
```
## Documentation
Full documentation is available on [HexDocs](https://hexdocs.pm/tele_dec).
## License
MIT License - see [LICENSE](LICENSE) for details.
## Contributing
Issues and pull requests are welcome on [GitHub](https://github.com/viragecloud/tele_dec).