Packages
spandex
1.0.0
3.2.0
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
2.0.0-rc2
2.0.0-rc1
1.6.2
1.6.1
1.6.0
1.5.0
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.6
retired
1.0.0-rc.5
retired
1.0.0-rc.4
retired
1.0.0-rc.3
retired
1.0.0-rc.2
retired
1.0.0-rc.1
retired
0.3.0
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A platform agnostic tracing library. Contributors welcome.
Current section
Files
Jump to
Current section
Files
README.md
# Spandex
[](https://travis-ci.org/zachdaniel/spandex)
[](http://inch-ci.org/github/zachdaniel/spandex)
[](https://coveralls.io/github/zachdaniel/spandex)
[](https://hex.pm/packages/spandex)
[](https://beta.hexfaktor.org/github/zachdaniel/spandex)
[](https://ebertapp.io/github/zachdaniel/spandex)
View the [documentation](https://hexdocs.pm/spandex)
Spandex is a platform agnostic tracing library. Currently there is only a datadog APM adapter, but its designed to be able to have more adapters written for it.
## Installation
```elixir
def deps do
[{:spandex, ~> "1.0.0"}]
end
```
## Configuration
Spandex uses `Confex` under the hood. See the formats usable for declaring values at their [documentation](https://github.com/Nebo15/confex)
```
config :spandex,
service: "my_api", # required
adapter: Spandex.Adapters.Datadog, # required
disabled?: {:system, "DISABLE_SPANDEX", false},
env: {:system, "APM_ENVIRONMENT", "unknown"},
application: :my_app,
ignored_methods: ["OPTIONS"],
ignored_routes: [~r/health_check/],
log_traces?: false # You probably don't want this to be on. This is helpful for debugging though.
config :spandex, :datadog,
host: {:system, "DATADOG_HOST", "localhost"},
port: {:system, "DATADOG_PORT", 8126},
services: [ # We create these services in datadog on application startup
ecto: :sql,
my_app: :web,
my_cache: :cache
]
```
## Phoenix Plugs
There are 3 plugs provided for usage w/ Phoenix:
* `Spandex.Plug.StartTrace`
* `Spandex.Plug.AddContext`
* `Spandex.Plug.EndTrace`
Ensure that `Spandex.Plug.EndTrace` goes *after* your router. This is important because we want rendering the response to be included in the tracing/timing. Put `Spandex.Plug.StartTrace` as early as is reasonable in your pipeline. Put `Spandex.Plug.AddContext` either after router or inside a pipeline in router.
## General Usage
In general, the nicest interface is to use function decorators.
Span function decorators take an optional argument which is the attributes to update the span with.
```
defmodule TracedModule do
use Spandex.TraceDecorator
@decorate trace(service: :my_app, type: :web)
def trace_me() do
span_1()
end
@decorate span()
def span_1() do
inner_span_1()
end
@decorate span()
def inner_span_1() do
_ = ThirdPartyApi.different_service_call()
inner_span_2()
end
@decorate span()
def inner_span_2() do
"this produces the span stack you would expect"
end
end
defmodule ThirdPartyApi do
use Spandex.TraceDecorator
@decorate span(service: :third_party, type: :cache)
def different_service_call() do
end
end
```
There is also a few ways to manually start spans.
```
defmodule ManuallyTraced do
require Spandex
# Does not handle exceptions for you.
def trace_me() do
_ = Spandex.start_trace("my_trace") #also opens a span
_ = Spandex.update_span(%{service: :my_app, type: :db})
result = span_me()
_ = Spandex.finish_trace()
result
end
# Does not handle exceptions for you.
def span_me() do
_ = Spandex.start_span("this_span")
_ = Spandex.update_span(%{service: :my_app, type: :web})
result = span_me_also()
_ = Spandex.finish_span()
end
# Handles exception at the span level. Trace still must be reported.
def span_me_also() do
Spandex.span("span_me_also) do
...
end
end
end
```
## Asynchronous Processes
Tasks are supported by using `Spandex.Task`
```
Spandex.Task.async("foo", fn -> do_work() end)
```
Managing your own asynchronous work:
The current trace_id and span_id can be retrieved with `Spandex.current_trace_id()` and `Spandex.current_span_id()`. This can then be used as `Spandex.continue_trace("new_trace", trace_id, span_id)`. New spans can then be logged from there and will be sent in a separate batch.