Packages

Implements an interface for recording traces and sending them to a Zipkin server.

Retired package: Release invalid - Document link not working

Current section

Files

Jump to
tapper lib tapper.ex
Raw

lib/tapper.ex

defmodule Tapper do
@moduledoc """
Client API for Tapper.
## Example
```
# start new trace (and span)
id = Tapper.start(name: "main", type: :client, debug: true, annotations: [Tapper.tag("a", "b")])
# or join an existing one
# id = Trapper.join(trace_id, span_id, parent_id, sample, debug, name: "main")
# start child span
id = Tapper.start_span(id, name: "call-out", annotations: [
Tapper.wire_send(),
Tapper.http_path("/resource/1234")
])
# do something
...
# tag current span with some additional metadata, e.g. when available
Tapper.update_span(id, [
Tapper.tag("userId", 12)
])
...
# end child span
id = Tapper.finish_span(child_id, annotations: [
Tapper.http_status(200)
])
Tapper.finish(span_id) # end trace
```
"""
@behaviour Tapper.Tracer.Api
@binary_annotation_types [:string, :bool, :i16, :i32, :i64, :double, :bytes]
alias Tapper.Tracer
@doc """
start a new root trace, e.g. on originating a request, e.g.:
```
id = Tapper.Tracer.start(name: "request resource", type: :client, remote: remote_endpoint)
```
### Options
* `name` - the name of the span.
* `sample` - boolean, whether to sample this trace or not.
* `debug` - boolean, enabled debug.
* `type` - the type of the span, i.e.. `:client`, `:server`; defaults to `:client`. See notes below.
* `annotations` (list) - a list of annotations, specified by `Tapper.http_host/2` etc.
* `remote` (`%Tapper.Endpoint{}`) - the remote Endpoint: automatically creates a "sa" (client) or "ca" (server) binary annotation on this span, see also `Tapper.server_address/1`.
* `ttl` - how long this span should live before automatically finishing it
(useful for long-running async operations); milliseconds (default 30,000 ms)
* `endpoint` - sets the endpoint for the annotation created by `type`, defaults to one derived from Tapper configuration (see `Tapper.Application.start/2`).
* `reporter` - override the configured reporter for this trace; useful for testing.
#### Notes
* If neither `sample` nor `debug` are set, all operations on this trace become a no-op.
* `type` determines the type of an automatically created `sr` (`:server`) or `cs` (`:client`) annotation, see also `Tapper.client_send/0` and `Tapper.server_receive/0`.
"""
defdelegate start(opts \\ []), to: Tracer
@doc """
join an existing trace, e.g. server recieving an annotated request.
```
id = Tapper.Tracer.join(trace_id, span_id, parent_id, sampled, debug, name: "receive request")
```
NB Probably called by an integration (e.g. [`tapper_plug`](https://github.com/Financial-Times/tapper_plug)) with name, annotations etc.
added in the service code, so the name is optional here, see `name/1`.
### Arguments
* `trace_id` - the trace id, as `Tapper.TraceId.t`.
* `span_id` - the current span id, as `Tapper.SpanId.t`.
* `parent_span_id` - the parent span id, as `Tapper.SpanId.t` or `:root` if root trace.
* `sample` is the incoming sampling status; `true` implies trace has been sampled, and
down-stream spans should be sampled also, `false` that it will not be sampled,
and down-stream spans should not be sampled either.
* `debug` is the debugging flag, if `true` this turns sampling for this trace on, regardless of
the value of `sampled`.
### Options
* `name` (String) - name of span
* `type` - the type of the span, i.e.. `:client`, `:server`; defaults to `:server`. See notes below.
* `annotations` (list) - a list of annotations, specified by `Tapper.tag/3` etc.
* `remote` (`Tapper.Endpoint`) - the remote endpoint: automatically creates a "sa" (`:client`) or "ca" (`:server`) binary annotation on this span, see also `Tapper.server_address/1`.
* `ttl` (integer) - how long this span should live between operations before automatically finishing it (useful for long-running async operations);
milliseconds, defaults to 30,000 ms.
* `endpoint` - sets the endpoint for the initial `cr` or `sr` annotation, defaults to one derived from Tapper configuration (see `Tapper.Application.start/2`).
* `reporter` - override the configured reporter for this trace; useful for testing.
#### Notes
* If neither `sample` nor `debug` are set, all operations on this trace become a no-op.
* `type` determines the type of an automatically created `sr` (`:server`) or `cs` (`:client`) annotation, see also `Tapper.client_send/0` and `Tapper.server_receive/0`.
"""
defdelegate join(trace_id, span_id, parent_id, sample, debug, opts \\ []), to: Tracer
@doc """
Finishes the trace.
For `async` processes (where spans persist in another process), call
`finish/2` when done with the main span, passing the `async` option, and finish
child spans as normal using `finish_span/2`. When the trace times out, spans will
be sent to the server, marking any unfinished spans with a `timeout` annotation.
## Options
* `async` - mark the trace as asynchronous, allowing child spans to finish within the TTL.
* `annotations` (list) - a list of annotations to attach to the span.
## See also
* `Tapper.Tracer.Timeout` - timeout behaviour.
* `async/0` annotation.
"""
defdelegate finish(id, opts \\ []), to: Tracer
@doc """
Starts a child span, returning an updated `Tapper.Id`.
## Arguments
* `id` - Tapper id.
## Options
* `name` (string) - name the span.
* `local` (string) - provide a local span context name (via a `lc` binary annotation).
* `annotations` (list) - a list of annotations to attach to the span.
```
id = start_span(id, name: "foo", local: "do foo", annotations: [Tapper.sql_query("select * from foo")])
```
"""
defdelegate start_span(id, opts \\ []), to: Tracer
@doc """
Finish a nested child span, returning an updated `Tapper.Id`.
## Arguments
* `id` - Tapper id.
## Options
* `annotations` (list) - a list of annotations to attach the the span.
```
id = Tapper.finish_span(id, annotations: [Tapper.http_status_code(202)])
```
"""
defdelegate finish_span(id, opts \\ []), to: Tracer
@doc """
Commit annotations to a span; returns the same `Tapper.Id`.
Use with annotation helper functions:
```
id = Tapper.start_span(id)
Tapper.update_span(id, [
Tapper.async(),
Tapper.name("child"),
Tapper.http_path("/server/x"),
Tapper.tag("x", 101)
])
```
"""
defdelegate update_span(id, deltas, opts \\[]), to: Tracer
@doc "Annotation helper: name (or rename) the current span."
def name(name), do: Tracer.name_delta(name)
@doc """
Annotation helper: marks the span as asynchronous, adding an `async` annotation.
This is semantically equivalent to calling `finish/2` with the `async` option, and
has the same time-out behaviour, but annotates individual spans as being asynchronous.
You can call this for every asynchronous span.
Ensure that child spans, and the whole trace, are finished as normal.
## See also
* `Tapper.Tracer.Timeout`
* `Tapper.finish/2`
"""
def async, do: Tracer.async_delta()
@doc "Annotation helper: mark a server_receive event (`sr` annotation); see also `:server` option on `Tapper.start/1`."
def server_receive, do: Tracer.annotation_delta(:sr)
@doc "Annotation helper: mark a server_send event (`ss` annotation)."
def server_send, do: Tracer.annotation_delta(:ss)
@doc "Annotation helper: mark a client_send event (`cs` annotation); see also `:client` option on `Tapper.start/1`."
def client_send, do: Tracer.annotation_delta(:cs)
@doc "Annotation helper: mark a client_receive event (`cr` annotation)."
def client_receive, do: Tracer.annotation_delta(:cr)
@doc "Annotation helper: mark a send event (`ws` annotation)."
def wire_send, do: Tracer.annotation_delta(:ws)
@doc "Annotation helper: mark a receive event (`wr` annotation)."
def wire_receive, do: Tracer.annotation_delta(:wr)
@doc "Annotation helper: mark an error event (`error` annotation)."
def error, do: Tracer.annotation_delta(:error)
@doc "Annotation helper: Tag with the client's address (`ca` binary annotation)."
def client_address(endpoint), do: Tracer.binary_annotation_delta(:bool, :ca, true, endpoint)
@doc "Annotation helper: Tag with the server's address (`sa` binary annotation)."
def server_address(endpoint), do: Tracer.binary_annotation_delta(:bool, :sa, true, endpoint)
@doc "Annotation helper: Tag with HTTP host information (`http.host` binary annotation)."
def http_host(hostname) when is_binary(hostname), do: Tracer.binary_annotation_delta(:string, "http.host", hostname)
@doc "Annotation helper: Tag with HTTP method information (`http.method` binary annotation)."
def http_method(method) when is_binary(method) or is_atom(method), do: Tracer.binary_annotation_delta(:string, "http.method", method)
@doc "Annotation helper: Tag with HTTP path information: should be without query parameters (`http.path` binary annotation)"
def http_path(path) when is_binary(path), do: Tracer.binary_annotation_delta(:string, "http.path", path)
@doc "Annotation helper: Tag with full HTTP URL information (`http.url` binary annotation)"
def http_url(url) when is_binary(url), do: Tracer.binary_annotation_delta(:string, "http.url", url)
@doc "Annotation helper: Tag with an HTTP status code (`http.status_code` binary annotation)"
def http_status_code(code) when is_integer(code), do: Tracer.binary_annotation_delta(:i16, "http.status_code", code)
@doc "Annotation helper: Tag with an HTTP request size (`http.request.size` binary annotation)"
def http_request_size(size) when is_integer(size), do: Tracer.binary_annotation_delta(:i64, "http.request.size", size)
@doc "Annotation helper: Tag with an HTTP reponse size (`http.response.size` binary annotation)"
def http_response_size(size) when is_integer(size), do: Tracer.binary_annotation_delta(:i64, "http.response.size", size)
@doc "Annotation helper: Tag with a database query (`sql.query` binary annotation)"
def sql_query(query) when is_binary(query), do: Tracer.binary_annotation_delta(:string, "sql.query", query)
@doc "Annotation helper: Tag with an error message (`error` binary annotation)"
def error_message(message) when is_binary(message), do: Tracer.binary_annotation_delta(:string, :error, message)
@doc "Annotation helper: Tag with a general (key,value,host) binary annotation, determining type of annotation automatically"
def tag(key, value, endpoint \\ nil)
def tag(key, value, endpoint) when (is_binary(key) or is_atom(key)) and is_binary(value), do: Tracer.binary_annotation_delta(:string, key, value, endpoint)
def tag(key, value, endpoint) when (is_binary(key) or is_atom(key)) and is_boolean(value), do: Tracer.binary_annotation_delta(:bool, key, value, endpoint)
def tag(key, value, endpoint) when (is_binary(key) or is_atom(key)) and is_integer(value), do: Tracer.binary_annotation_delta(:i64, key, value, endpoint)
def tag(key, value, endpoint) when (is_binary(key) or is_atom(key)) and is_float(value), do: Tracer.binary_annotation_delta(:double, key, value, endpoint)
def tag(key, value, endpoint) when (is_binary(key) or is_atom(key)), do: Tracer.binary_annotation_delta(:string, key, inspect(value), endpoint)
@doc "Annotation helper: mark an event (annotation), general interface."
def annotation(value, endpoint \\ nil) when not is_map(value), do: Tracer.annotation_delta(value, endpoint)
@doc """
Annotation helper: tag with a general binary annotation.
```
binary_annotation(id, :i16, "tab", 4)
```
"""
def binary_annotation(type, key, value, endpoint \\ nil) when type in @binary_annotation_types do
Tracer.binary_annotation_delta(type, key, value, endpoint)
end
end