Packages
dd_trace_ex
0.1.0
A Datadog APM tracing library for Elixir: Datadog-native spans, per-process trace context, and Phoenix, Ecto and Req integrations.
Current section
Files
Jump to
Current section
Files
dd_trace_ex
README.md
README.md
# dd_trace_ex
A Datadog APM tracing library for Elixir.
`dd_trace_ex` (top-level module `DDTrace`) is written to match what
Datadog's official dd-trace libraries do. It sends traces to the Datadog
agent in the same format they do, so features like 128-bit trace IDs,
numeric metrics, tracing across services, sampling and manual keep or drop
all behave the way Datadog users expect. dd-trace-js and dd-trace-go were
the reference for how things should work on the wire. Tracing context
lives in the process and follows work into other processes, the API is
small and built around a single `trace` call, and Phoenix, Ecto and Req
are supported through `:telemetry`. It is still early, but the core is in
place.
> **Status: `0.1.0` release candidate.** This is a first public release, not
> a mature library: it covers a documented subset of Datadog tracing (see
> [Current limitations](#current-limitations)), and the API may still change
> before `1.0`.
## Installation
Add `dd_trace_ex` to your dependencies:
```elixir
# mix.exs
defp deps do
[
{:dd_trace_ex, "~> 0.1.0"}
]
end
```
Run `mix deps.get`, then configure your service and agent connection:
```elixir
# config/runtime.exs
config :dd_trace_ex,
service: "my_app",
agent_url: "http://localhost:8126"
```
The tracer starts automatically with your application. You need a Datadog
Agent with APM enabled to receive the traces. See the [setup guide](guides/setup.md)
for environment variables and integration setup.
## Trace application code
Wrap work in `DDTrace.trace`. Tags and metrics describe the span being traced:
```elixir
require DDTrace
DDTrace.trace "orders.import" do
DDTrace.set_tag("order.channel", "web")
DDTrace.set_metric("orders.count", length(orders))
MyApp.Orders.import(orders)
end
```
The block returns its result. Nested calls create child spans. Exceptions
that escape the block are recorded on the span and re-raised.
For a function you want to trace on every call, use a decorator:
```elixir
defmodule MyApp.Orders do
use DDTrace.Decorators
@decorate trace(name: "orders.import")
def import(orders) do
DDTrace.set_metric("orders.count", length(orders))
# ...
end
end
```
`DDTrace.with_trace/3` takes a function when that fits better than a block.
## Integrations
Enable Phoenix and Ecto tracing at application startup, before starting
your endpoint and repo:
```elixir
DDTrace.Integrations.Phoenix.setup()
DDTrace.Integrations.Ecto.setup(repo: MyApp.Repo)
```
Phoenix request spans include the route, HTTP status, and incoming trace
context. Ecto query spans include SQL and timing information; bind
parameter values are excluded.
For Req, attach tracing when building the client:
```elixir
req =
Req.new(base_url: "https://inventory.example.com")
|> DDTrace.Integrations.Req.attach()
Req.get!(req, url: "/items")
```
Requests through that client produce spans and carry Datadog trace headers
to the receiving service.
## Trace work across processes
Use `DDTrace.Task` to carry the current trace into tasks. Create spans
inside the task for the work you want to measure:
```elixir
require DDTrace
DDTrace.trace "orders.import" do
orders
|> DDTrace.Task.async_stream(fn order ->
DDTrace.trace "order.process" do
MyApp.Orders.process(order)
end
end)
|> Enum.to_list()
end
```
For messages, GenServers, and other process boundaries, capture the context
with `DDTrace.current_context/0` and pass it to the receiving process. Use
`parent:` when opening its span.
## Sampling and logs
The tracer uses sampling rates supplied by the agent. You can also
configure sampling rules or a fixed rate, and override the decision with
`DDTrace.keep_trace/0` or `DDTrace.drop_trace/0`. Dropped traces still reach
the agent; dropping controls retention.
While a span is open, trace and span IDs are available in `Logger`
metadata. Include these fields in your JSON logs for Datadog log
correlation.
See the [setup guide](guides/setup.md) for configuration and logging examples.
## Testing
Capture spans in ExUnit without running an agent:
```elixir
defmodule MyApp.OrdersTest do
use ExUnit.Case, async: true
use DDTrace.Test
test "imports are traced" do
MyApp.Orders.import([])
assert_span "orders.import"
end
end
```
## Current limitations
- Agent connections support HTTP only; HTTPS and Unix sockets are not supported.
- Sampling applies to whole traces. Keeping individual spans from sampled-out
traces is not supported.
- Sampled-out traces are still sent to the agent. The library does not compute
APM statistics locally.
## License
MIT. See [LICENSE](LICENSE).
`dd_trace_ex` is an independent project. It is not affiliated with,
endorsed by, or sponsored by Datadog, Inc. "Datadog" and "dd-trace" are
trademarks of Datadog, Inc., used here only to describe what this library
interoperates with.