Ot
Opentracing for elixir applications.
- Prerequisites
- Installation
- Quick start
- Plug
- Module overview and functions
- Contributing
- Code of conduct (CoC)
- About SumUp
Prerequisites
- You will need a general understanding of opentracing's concepts. You can find a good starting point here
- Install Elixir v1.9 or higher
- This project depends on tesla. Check out their documentation to learn more about Tesla and how middlewares work there.
- Throughout the examples of this readme we have used excerpts of a sample Phoenix web app, it is a good idea to get familiar with it first.
Installation
Add this line to your mix.exs:
defp deps do
[{:ot, "~> 3.0"}]
end
Then run mix deps.get and you are good to go!
Quick start
# See "Configuration" section
Ot.start_link(config)
# See "Module overview and functions" section
Ot.start_span("my-test-span", nil) # <- span is initialized
Ot.tag("my-tag", "tag-value") #
Ot.log("log message") #
Ot.end_span() # <- span will be sent to jaegerExample usage in a Phoenix app
In config/dev.exs:
# See "Configuration" section
config :my_app, :ot_config,
service_name: "my-app",
collectors: [
jaeger: [
url: "http://127.0.0.1:9411/api/v2/spans",
adapter: Tesla.Adapter.Hackney,
stringify_tags: true
]
]
In application.ex:
defmodule MyApp.Application do
def start(_type, _args) do
children = [
{Ot, Application.fetch_env!(:my_app, :ot_config)}
# ... other children
In endpoint.ex:
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
# See "Plug" section
plug Ot.Plug
# ... other plugsConfiguration
Example with all supported configuration options:
# Tesla adapter to use in collectors (can be different for each collector)
# If you use this one, you must add :hackney to your deps
adapter = {Tesla.Adapter.Hackney, connect_timeout: 5000, recv_timeout: 5000}
ot_config = [
service_name: "my-app", # (required)
ignored_exceptions: [ # (optional) don't set "error=true" for these
Phoenix.Router.NoRouteError
],
plug: [ # (optional) config for Ot.Plug
paths: ["/v0.1/*"], # (optional) paths to work with; default: ["*"]
response_body_tag: "http.response_body", # (optional) tag resp body as "http.resp_body"; default: nil (no tag)
conn_private_tags: [ # (optional) list of conn-private fields to tag; default: []
req_body: "http.request_body", # tag conn.private.req_body as "http.request_body"
req_id: "http.request_id" # tag conn.private.req_id as "http.request_id"
]
],
collectors: [
jaeger: [
url: "...", # (required) span endpoint (Zipkin JSON v2 format)
adapter: tesla_adapter, # (required) tesla adapter to use
flush_interval: 500, # (optional) buffer flush interval in ms; default: 1000
flush_retries: 1, # (optional) flush retry attempts; default: 5 *
stringify_tags: true, # (optional) convert tag values to strings (required for jaeger)
middlewares: [] # (optional) Tesla middlewares; default: []
],
newrelic: [
url: "https://trace-api.newrelic.com/trace/v1",
adapter: tesla_adapter,
middlewares: [
Tesla.Middleware.Logger,
{Tesla.Middleware.Headers, [
{"api-key", "..."},
{"data-format", "zipkin"},
{"data-format-version", "2"}
]}
]
]
]
]* tracing data is stored in a local buffer and sent to the tracing backends (jaeger, zipkin, etc.) in a batch, every X ms. On failure, the buffer is preserved and continues to accumulate spans till the next flush (retry). If the retry limit is exceeded, the buffer is discarded to prevent memory leaks.
Plug
Web applications can use Ot.Plug to automatically have a span created for each incoming request.
Let's take a simple ping-pong web app and try this simple request:
curl 'http://localhost:4000/v0.1/ping?player=just_me'The controller:
def MyAppWeb.MyController do
def ping(conn, params) do
Ot.tag("opponent", params["player"])
send_resp(conn, 200, "pong")
end
endwill produce this span, sent to the collector(s):
{
"annotations": [],
"duration": 1375,
"id": "d98f95a2d087a665",
"kind": "SERVER",
"localEndpoint":
{
"ipv4": "127.0.0.1",
"port": 0,
"serviceName": "my-app"
},
"name": "request",
"parentId": null,
"tags":
{
"component": "my-app",
"author": "just_me",
"http.method": "GET",
"http.path": "/v0.1/ping",
"http.query_string": "player=just_me",
"http.status_code": "200"
},
"timestamp": 1628150108323753,
"traceId": "0a922fbb7df193916b283610bcc516ff"
}
Note that the values of ipv4 and port are hard-coded (could be made configurable in a later release).
Module overview and functions
Check out the Module overview docs.
Contributing
Check out CONTRIBUTING.md
Code of conduct (CoC)
We want to foster an inclusive and friendly community around our Open Source efforts. Like all SumUp Open Source projects, this project follows the Contributor Covenant Code of Conduct. Please, read it and follow it.
If you feel another member of the community violated our CoC or you are experiencing problems participating in our community because of another individual's behavior, please get in touch with our maintainers. We will enforce the CoC.
About SumUp
It is our mission to make easy and fast card payments a reality across the entire world. You can pay with SumUp in more than 30 countries, already. Our engineers work in Berlin, Cologne, Sofia and Sāo Paulo. They write code in JavaScript, Swift, Ruby, Go, Java, Erlang, Elixir and more. Want to come work with us? Head to our careers page to find out more.