Add opentelemetry integration to Oban (#6)
By default a new trace is automatically started when a job is processed
by monitoring these events:
* `[:oban, :job, :start]` — at the point a job is fetched from the database and will execute
* `[:oban, :job, :stop]` — after a job succeeds and the success is recorded in the database
* `[:oban, :job, :exception]` — after a job fails and the failure is recorded in the database
To also record a span when a job is created and to link traces together
`Oban.insert/2` has to be replaced by `OpentelemetryOban.insert/2`.
Before:
```elixir
%{id: 1, in_the: "business", of_doing: "business"}
|> MyApp.Business.new()
|> Oban.insert()
```
After:
```elixir
%{id: 1, in_the: "business", of_doing: "business"}
|> MyApp.Business.new()
|> OpentelemetryOban.insert()
```
Co-authored-by: Tristan Sloughter <t@crashfast.com>
2021-12-08 15:41:36 +00:00
|
|
|
defmodule OpentelemetryOban.PluginHandlerTest do
|
|
|
|
use DataCase
|
|
|
|
|
|
|
|
require OpenTelemetry.Tracer
|
|
|
|
require OpenTelemetry.Span
|
|
|
|
require Record
|
|
|
|
|
|
|
|
for {name, spec} <- Record.extract_all(from_lib: "opentelemetry/include/otel_span.hrl") do
|
|
|
|
Record.defrecord(name, spec)
|
|
|
|
end
|
|
|
|
|
|
|
|
for {name, spec} <- Record.extract_all(from_lib: "opentelemetry_api/include/opentelemetry.hrl") do
|
|
|
|
Record.defrecord(name, spec)
|
|
|
|
end
|
|
|
|
|
|
|
|
setup do
|
|
|
|
:application.stop(:opentelemetry)
|
|
|
|
:application.set_env(:opentelemetry, :tracer, :otel_tracer_default)
|
|
|
|
|
|
|
|
:application.set_env(:opentelemetry, :processors, [
|
|
|
|
{:otel_batch_processor, %{scheduled_delay_ms: 1, exporter: {:otel_exporter_pid, self()}}}
|
|
|
|
])
|
|
|
|
|
|
|
|
:application.start(:opentelemetry)
|
|
|
|
|
|
|
|
TestHelpers.remove_oban_handlers()
|
|
|
|
OpentelemetryOban.setup()
|
|
|
|
|
|
|
|
:ok
|
|
|
|
end
|
|
|
|
|
|
|
|
test "does not create spans when tracing plugins is disabled" do
|
|
|
|
TestHelpers.remove_oban_handlers()
|
|
|
|
OpentelemetryOban.setup(trace: [:jobs])
|
|
|
|
|
|
|
|
:telemetry.execute(
|
|
|
|
[:oban, :plugin, :start],
|
|
|
|
%{system_time: System.system_time()},
|
|
|
|
%{plugin: Elixir.Oban.Plugins.Stager}
|
|
|
|
)
|
|
|
|
|
|
|
|
:telemetry.execute(
|
|
|
|
[:oban, :plugin, :stop],
|
|
|
|
%{duration: 444},
|
|
|
|
%{plugin: Elixir.Oban.Plugins.Stager}
|
|
|
|
)
|
|
|
|
|
|
|
|
refute_receive {:span, span(name: "Elixir.Oban.Plugins.Stager process")}
|
|
|
|
end
|
|
|
|
|
|
|
|
test "records span on plugin execution" do
|
|
|
|
:telemetry.execute(
|
|
|
|
[:oban, :plugin, :start],
|
|
|
|
%{system_time: System.system_time()},
|
|
|
|
%{plugin: Elixir.Oban.Plugins.Stager}
|
|
|
|
)
|
|
|
|
|
|
|
|
:telemetry.execute(
|
|
|
|
[:oban, :plugin, :stop],
|
|
|
|
%{duration: 444},
|
|
|
|
%{plugin: Elixir.Oban.Plugins.Stager}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert_receive {:span, span(name: "Elixir.Oban.Plugins.Stager process")}
|
|
|
|
end
|
|
|
|
|
|
|
|
test "records span on plugin error" do
|
|
|
|
:telemetry.execute(
|
|
|
|
[:oban, :plugin, :start],
|
|
|
|
%{system_time: System.system_time()},
|
|
|
|
%{plugin: Elixir.Oban.Plugins.Stager}
|
|
|
|
)
|
|
|
|
|
|
|
|
:telemetry.execute(
|
|
|
|
[:oban, :plugin, :exception],
|
|
|
|
%{duration: 444},
|
|
|
|
%{
|
|
|
|
plugin: Elixir.Oban.Plugins.Stager,
|
|
|
|
kind: :error,
|
|
|
|
stacktrace: [
|
|
|
|
{Some, :error, [], []}
|
|
|
|
],
|
|
|
|
error: %UndefinedFunctionError{
|
|
|
|
arity: 0,
|
|
|
|
function: :error,
|
|
|
|
message: nil,
|
|
|
|
module: Some,
|
|
|
|
reason: nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
expected_status = OpenTelemetry.status(:error, "")
|
|
|
|
|
|
|
|
assert_receive {:span,
|
|
|
|
span(
|
|
|
|
name: "Elixir.Oban.Plugins.Stager process",
|
2021-12-28 23:39:06 +00:00
|
|
|
events: events,
|
Add opentelemetry integration to Oban (#6)
By default a new trace is automatically started when a job is processed
by monitoring these events:
* `[:oban, :job, :start]` — at the point a job is fetched from the database and will execute
* `[:oban, :job, :stop]` — after a job succeeds and the success is recorded in the database
* `[:oban, :job, :exception]` — after a job fails and the failure is recorded in the database
To also record a span when a job is created and to link traces together
`Oban.insert/2` has to be replaced by `OpentelemetryOban.insert/2`.
Before:
```elixir
%{id: 1, in_the: "business", of_doing: "business"}
|> MyApp.Business.new()
|> Oban.insert()
```
After:
```elixir
%{id: 1, in_the: "business", of_doing: "business"}
|> MyApp.Business.new()
|> OpentelemetryOban.insert()
```
Co-authored-by: Tristan Sloughter <t@crashfast.com>
2021-12-08 15:41:36 +00:00
|
|
|
status: ^expected_status
|
|
|
|
)}
|
2021-12-28 23:39:06 +00:00
|
|
|
|
|
|
|
[
|
|
|
|
event(
|
|
|
|
name: "exception",
|
|
|
|
attributes: event_attributes
|
|
|
|
)
|
|
|
|
] = :otel_events.list(events)
|
|
|
|
|
|
|
|
assert ["exception.message", "exception.stacktrace", "exception.type"] ==
|
|
|
|
Map.keys(:otel_attributes.map(event_attributes))
|
Add opentelemetry integration to Oban (#6)
By default a new trace is automatically started when a job is processed
by monitoring these events:
* `[:oban, :job, :start]` — at the point a job is fetched from the database and will execute
* `[:oban, :job, :stop]` — after a job succeeds and the success is recorded in the database
* `[:oban, :job, :exception]` — after a job fails and the failure is recorded in the database
To also record a span when a job is created and to link traces together
`Oban.insert/2` has to be replaced by `OpentelemetryOban.insert/2`.
Before:
```elixir
%{id: 1, in_the: "business", of_doing: "business"}
|> MyApp.Business.new()
|> Oban.insert()
```
After:
```elixir
%{id: 1, in_the: "business", of_doing: "business"}
|> MyApp.Business.new()
|> OpentelemetryOban.insert()
```
Co-authored-by: Tristan Sloughter <t@crashfast.com>
2021-12-08 15:41:36 +00:00
|
|
|
end
|
|
|
|
end
|