Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions instrumentation/opentelemetry_monitor/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
26 changes: 26 additions & 0 deletions instrumentation/opentelemetry_monitor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
opentelemetry_monitor-*.tar

# Temporary files, for example, from tests.
/tmp/
39 changes: 39 additions & 0 deletions instrumentation/opentelemetry_monitor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# OpentelemetryMonitor

This library makes it possible to monitor a process, and close its spans when it has died.

Without this, a crashed process can result in missing spans.

To use, add the process to your supervision tree:

```elixir
children = [
OpentelemetryMonitor
]
```

Then, call `OpentelemetryMonitor.monitor(span_ctx)` as appropriate.

Example:

```elixir
OpentelemetryMonitor.monitor(OpenTelemetry.Tracer.current_span_ctx())
```

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `opentelemetry_monitor` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:opentelemetry_monitor, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/opentelemetry_monitor>.

56 changes: 56 additions & 0 deletions instrumentation/opentelemetry_monitor/lib/opentelemetry_monitor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
defmodule OpentelemetryMonitor do
use GenServer

def start_link(_arg) do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end

def init(nil) do
_table_id = :ets.new(__MODULE__, [:bag, :public, {:write_concurrency, true}, :named_table])
{:ok, nil}
end

def handle_call({:monitor, pid}, _from, state) do
Process.monitor(pid)
{:reply, :ok, state}
end

def handle_info({:DOWN, _ref, :process, pid, :normal}, state) do
:ets.take(__MODULE__, pid)
|> Enum.each(fn {_pid, ctx} ->
_span_ctx = OpenTelemetry.Tracer.set_current_span(ctx)
_ = OpenTelemetry.Tracer.end_span()
end)

{:noreply, state}
end

def handle_info({:DOWN, _ref, :process, pid, {:shutdown, _}}, state) do
:ets.take(__MODULE__, pid)
|> Enum.each(fn {_pid, ctx} ->
_span_ctx = OpenTelemetry.Tracer.set_current_span(ctx)
_ = OpenTelemetry.Tracer.end_span()
end)

{:noreply, state}
end

def handle_info({:DOWN, _ref, :process, pid, reason}, state) do
:ets.take(__MODULE__, pid)
|> Enum.each(fn {_pid, ctx} ->
_span_ctx = OpenTelemetry.Tracer.set_current_span(ctx)
_ = OpenTelemetry.Tracer.add_event("Process died", [{"reason", inspect(reason)}])
_ = OpenTelemetry.Tracer.end_span()
end)

{:noreply, state}
end

def monitor(span_ctx) do
if Application.fetch_env!(:opentelemetry, :processors) != [] do
# monitor first, because the monitor is necessary to clean the ets table.
:ok = GenServer.call(__MODULE__, {:monitor, self()})
true = :ets.insert(__MODULE__, {self(), span_ctx})
end
end
end
44 changes: 44 additions & 0 deletions instrumentation/opentelemetry_monitor/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
defmodule OpentelemetryMonitor.MixProject do
use Mix.Project

def project do
[
app: :opentelemetry_monitor,
version: "0.1.0",
elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
package: package(),
deps: deps(),
source_url:
"https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/instrumentation/opentelemetry_monitor"
]
end

def application do
[
extra_applications: [:logger]
]
end

defp package() do
[
description: "Enables closing otel spans of processes that die",
licenses: ["Apache-2.0"],
links: %{
"GitHub" =>
"https://github.com/open-telemetry/opentelemetry-erlang-contrib/instrumentation/opentelemetry_monitor",
"OpenTelemetry Erlang" => "https://github.com/open-telemetry/opentelemetry-erlang",
"OpenTelemetry Erlang Contrib" =>
"https://github.com/open-telemetry/opentelemetry-erlang-contrib",
"OpenTelemetry.io" => "https://opentelemetry.io"
}
]
end

defp deps do
[
{:ex_doc, "~> 0.28", only: :dev, runtime: false},
{:opentelemetry_api, "~> 1.0"}
]
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule OpentelemetryMonitorTest do
use ExUnit.Case
doctest OpentelemetryMonitor
end
1 change: 1 addition & 0 deletions instrumentation/opentelemetry_monitor/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()