diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d0fed7 --- /dev/null +++ b/.gitignore @@ -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_tesla-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..30deb8e --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# OpentelemetryTesla + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `opentelemetry_tesla` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:opentelemetry_tesla, "~> 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_tesla](https://hexdocs.pm/opentelemetry_tesla). + diff --git a/lib/opentelemetry_tesla.ex b/lib/opentelemetry_tesla.ex new file mode 100644 index 0000000..455e756 --- /dev/null +++ b/lib/opentelemetry_tesla.ex @@ -0,0 +1,67 @@ +defmodule OpentelemetryTesla do + @tracer_id :opentelemetry_tesla + + @doc """ + Initializes and configures telemetry handlers. + """ + @spec setup() :: :ok + def setup() do + {:ok, otel_tracer_vsn} = :application.get_key(@tracer_id, :vsn) + OpenTelemetry.register_tracer(@tracer_id, otel_tracer_vsn) + + attach_request_start_handler() + attach_request_stop_handler() + # attach_request_exception_handler() + :ok + end + + def attach_request_start_handler() do + :telemetry.attach( + "#{__MODULE__}.request_start", + [:tesla, :request, :start], + &handle_start/4, + %{} + ) + end + + def attach_request_stop_handler() do + :telemetry.attach( + "#{__MODULE__}.request_stop", + [:tesla, :request, :stop], + &handle_stop/4, + %{} + ) + end + + defp handle_start(_event, _measurements, _metadata, _config) do + OpentelemetryTelemetry.start_telemetry_span( + @tracer_id, + "External HTTP Request", + %{}, + %{kind: :server} + ) + end + + defp handle_stop(_event, %{duration: measurement}, metadata, _config) do + headers_span_args = + metadata + |> Map.get(:env) + |> Map.get(:headers) + |> Enum.map(fn {key, value} -> {:"http.headers.#{key}", value} end) + + span_args = + metadata + |> Map.get(:env) + |> Map.take([:method, :opts, :query, :status, :url]) + |> Enum.map(fn {key, value} -> {:"http.#{key}", value} end) + + ctx = OpentelemetryTelemetry.set_current_telemetry_span(@tracer_id, %{}) + + OpenTelemetry.Span.set_attributes( + ctx, + span_args ++ headers_span_args ++ [measurement: measurement / 1_000_000] + ) + + OpentelemetryTelemetry.end_telemetry_span(@tracer_id, %{}) + end +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..1985993 --- /dev/null +++ b/mix.exs @@ -0,0 +1,39 @@ +defmodule OpentelemetryTesla.MixProject do + use Mix.Project + + def project do + [ + app: :opentelemetry_tesla, + version: "0.1.0", + elixir: "~> 1.12", + start_permanent: Mix.env() == :prod, + deps: deps(), + package: package() + ] + end + + defp package do + [ + maintainers: ["Ricardo Paiva"], + licenses: ["MIT"], + links: %{"GitHub" => "https://github.com/ricardoccpaiva/opentelemetry_tesla"} + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:telemetry, "~> 0.4"}, + {:opentelemetry, "~> 1.0.0-rc.2"}, + {:opentelemetry_telemetry, "~> 1.0.0-beta.2"}, + {:tesla, "~> 1.4"} + ] + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..5de6ea6 --- /dev/null +++ b/mix.lock @@ -0,0 +1,9 @@ +%{ + "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, + "opentelemetry": {:hex, :opentelemetry, "1.0.0-rc.2", "d3e1fd9debfd73e00b0241cac464be7cd6ca6ac2bd38ab2ebe0c92401c76a342", [:rebar3], [{:opentelemetry_api, "~> 1.0.0-rc.2", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}], "hexpm", "2f810e2eed70a9ea0c9b6943969b59e37f96a2f9e10920045a6c7676c2ab8181"}, + "opentelemetry_api": {:hex, :opentelemetry_api, "1.0.0-rc.2", "a0ec5b242bb7ce7563b4891e77dcfa529defc9e42c19a5a702574c5ac3d0c6e7", [:mix, :rebar3], [], "hexpm", "426a969c8ee2afa8ab55b58e6e40e81c1f934c064459a1acb530f54042f9a9a3"}, + "opentelemetry_telemetry": {:hex, :opentelemetry_telemetry, "1.0.0-beta.2", "b840eee9e68307ad7fa4ee316da19db3f8e30763b87737d3304782ca3cc296a2", [:mix, :rebar3], [{:opentelemetry_api, "~> 1.0.0-rc.1", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_registry, "~> 0.2.1", [hex: :telemetry_registry, repo: "hexpm", optional: false]}], "hexpm", "e8b12f42614d0aeb6a49001c75ca035544950f736fdbb240177838674f99e1e2"}, + "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, + "telemetry_registry": {:hex, :telemetry_registry, "0.2.1", "fe648a691f2128e4279d993cd010994c67f282354dc061e697bf070d4b87b480", [:mix, :rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4221cefbcadd0b3e7076960339223742d973f1371bc20f3826af640257bc3690"}, + "tesla": {:hex, :tesla, "1.4.2", "54fc2c989b63c3c9ff675c2f193d824325a802e61575063363eaa97f471af2ed", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "aa3a4130a662a16471a6847fecd4772e2adaf9a4693488f022c612c0bb98c9fd"}, +} diff --git a/test/opentelemetry_tesla_test.exs b/test/opentelemetry_tesla_test.exs new file mode 100644 index 0000000..29d4587 --- /dev/null +++ b/test/opentelemetry_tesla_test.exs @@ -0,0 +1,8 @@ +defmodule OpentelemetryTeslaTest do + use ExUnit.Case + doctest OpentelemetryTesla + + test "greets the world" do + assert OpentelemetryTesla.hello() == :world + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()