Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

separate application tracer registration from user named tracers #287

Merged
merged 1 commit into from
Oct 8, 2021
Merged
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
7 changes: 1 addition & 6 deletions apps/opentelemetry/include/otel_span.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
%% @end
%%%-------------------------------------------------------------------------

%% Holds information about the instrumentation library specified when
%% getting a Tracer from the TracerProvider.
-record(instrumentation_library, {name :: unicode:unicode_binary() | undefined,
version :: unicode:unicode_binary() | undefined}).

%% The name, version and language of this OpenTelemetry library
-record(telemetry_library, {name :: unicode:unicode_binary() | undefined,
language :: unicode:unicode_binary() | undefined,
Expand Down Expand Up @@ -70,5 +65,5 @@
%% trace flags lowest bit is 1 but simply not propagated.
is_recording :: boolean() | undefined,

instrumentation_library :: #instrumentation_library{} | undefined
instrumentation_library :: opentelemetry:instrumentation_library() | undefined
}).
3 changes: 2 additions & 1 deletion apps/opentelemetry/src/opentelemetry_app.erl
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ register_loaded_application_tracers(Opts) ->
register_loaded_applications_(RegisterLoadedApplications).

register_loaded_applications_(true) ->
%% TODO: filter out OTP apps that will not have any instrumentation
LoadedApplications = application:loaded_applications(),
[opentelemetry:register_application_tracer(Name) || {Name, _, _} <- LoadedApplications],
opentelemetry:register_application_tracers(LoadedApplications),
ok;
register_loaded_applications_(_) ->
ok.
21 changes: 7 additions & 14 deletions apps/opentelemetry/src/otel_tracer_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
-behaviour(otel_tracer_provider).

-export([init/1,
register_tracer/4,
register_tracer/3,
get_tracer/2,
resource/1,
code_change/1]).

Expand Down Expand Up @@ -86,18 +86,11 @@ init(Opts) ->
resource(#state{resource=Resource}) ->
Resource.

register_tracer(Name, Vsn, Modules, #state{shared_tracer=Tracer,
deny_list=DenyList}) ->
%% TODO: support semver constraints in denylist
case proplists:is_defined(Name, DenyList) of
true ->
opentelemetry:set_tracer(Name, {otel_tracer_noop, []});
false ->
InstrumentationLibrary = otel_utils:instrumentation_library(Name, Vsn),
TracerTuple = {Tracer#tracer.module,
Tracer#tracer{instrumentation_library=InstrumentationLibrary}},
[opentelemetry:set_tracer(M, TracerTuple) || M <- Modules]
end.
get_tracer(InstrumentationLibrary, #state{shared_tracer=Tracer,
deny_list=_DenyList}) ->

{Tracer#tracer.module,
Tracer#tracer{instrumentation_library=InstrumentationLibrary}}.

register_tracer(Name, Vsn, #state{shared_tracer=Tracer,
deny_list=DenyList}) ->
Expand All @@ -106,7 +99,7 @@ register_tracer(Name, Vsn, #state{shared_tracer=Tracer,
true ->
opentelemetry:set_tracer(Name, {otel_tracer_noop, []});
false ->
InstrumentationLibrary = otel_utils:instrumentation_library(Name, Vsn),
InstrumentationLibrary = opentelemetry:instrumentation_library(Name, Vsn),
TracerTuple = {Tracer#tracer.module,
Tracer#tracer{instrumentation_library=InstrumentationLibrary}},
opentelemetry:set_tracer(Name, TracerTuple)
Expand Down
29 changes: 0 additions & 29 deletions apps/opentelemetry/src/otel_utils.erl

This file was deleted.

10 changes: 8 additions & 2 deletions apps/opentelemetry/test/opentelemetry_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,25 @@ end_per_testcase(_, _Config) ->
ok.

disable_auto_registration(_Config) ->
{_, #tracer{instrumentation_library=Library}} = opentelemetry:get_tracer(kernel),
{_, #tracer{instrumentation_library=Library}} = opentelemetry:get_application_tracer(kernel),
?assertEqual(undefined, Library),
ok.

registered_tracers(_Config) ->
{_, #tracer{instrumentation_library=Library}} = opentelemetry:get_tracer(kernel),
{_, #tracer{instrumentation_library=Library}} = opentelemetry:get_application_tracer(kernel),
?assertEqual(<<"kernel">>, Library#instrumentation_library.name),

%% register a new tracer with the same name but different version
opentelemetry:register_tracer(kernel, <<"fake-version">>),
{_, #tracer{instrumentation_library=NewLibrary}} = opentelemetry:get_tracer(kernel),
?assertEqual(<<"kernel">>, NewLibrary#instrumentation_library.name),
?assertEqual(<<"fake-version">>, NewLibrary#instrumentation_library.version),

%% tracer registered on startup for a particular application is the same
{_, #tracer{instrumentation_library=Library1}} = opentelemetry:get_application_tracer(kernel),
?assertEqual(<<"kernel">>, Library1#instrumentation_library.name),
?assertNotEqual(<<"fake-version">>, Library1#instrumentation_library.version),

ok.

propagator_configuration(_Config) ->
Expand Down
60 changes: 4 additions & 56 deletions apps/opentelemetry_api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,64 +30,12 @@ def deps do
end
```

### Registering and Using Tracers Directly

If it is a runnable application then this registration should happen in `start/2`, example below is adding `Tracer` registration to the Postgres library [pgo](https://github.com/erleans/pgo):

``` erlang
start(_StartType, _StartArgs) ->
_ = opentelemetry:register_application_tracer(pgo),
...
```

Or for an Elixir Application named `MyApp`:

``` elixir
defmodule MyApp do
use Application

def start(_type, _args) do
_ = OpenTelemetry.register_application_tracer(:my_app)
...
end
end
```

Then when the spans are started and finished in the application's code the `Tracer` is fetched with `get_tracer/1` and passed to `with_span/3` or `start_span/3`:

``` erlang
Tracer = opentelemetry:get_tracer(pgo),
otel_tracer:with_span(Tracer, <<"pgo:query/3">>, fun() -> ... end).
```

A `Tracer` variable can be passed through your Application's calls so `get_tracer` only has to be called once, it is safe to store it in the state of a `gen_server` and to pass across process boundaries.

If the application does not have a `start/2` there may be another function that is always called before the library would create any spans. For example, the [Elli](https://github.com/elli-lib/elli) middleware for OpenTelemetry instrumentation registers the `Tracer` during Elli startup:

``` erlang
handle_event(elli_startup, _Args, _Config) ->
_ = opentelemetry:register_application_tracer(opentelemetry_elli),
ok;
```

When there is no startup of any kind to hook into in the library itself it should export a function `register_application_tracer/0` to be used by any application that depends on it to do the registration:

``` erlang
-module(mylib).

-export([register_tracer/0]).

register_tracer() ->
_ = opentelemetry:register_application_tracer(mylib),
ok.
```

Not registering does not cause any issues or crashes, OpenTelemetry simply will fallback to the default `Tracer` if `get_tracer/1` is called with a name that is not registered.


### Helper Macros for Application Tracers

When `register_application_tracer/1` is used to register a Tracer there are both Erlang and Elixir macros that make use of the current module's name to lookup the Tracer for you and can be used for Trace and Span operations:
There are both Erlang and Elixir macros that make use of the current module's
name to lookup a Named Tracer -- a Named Tracer is created for each Application
loaded in the system at start time -- for you and can be used for Trace and Span
operations:

``` erlang
-include_lib("opentelemetry_api/include/otel_tracer.hrl").
Expand Down
5 changes: 5 additions & 0 deletions apps/opentelemetry_api/include/opentelemetry.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
-define(OTEL_STATUS_OK, ok).
-define(OTEL_STATUS_ERROR, error).

%% Holds information about the instrumentation library specified when
%% getting a Tracer from the TracerProvider.
-record(instrumentation_library, {name :: unicode:unicode_binary() | undefined,
version :: unicode:unicode_binary() | undefined}).

-record(span_ctx, {
%% 128 bit int trace id
trace_id :: opentelemetry:trace_id(),
Expand Down
2 changes: 1 addition & 1 deletion apps/opentelemetry_api/include/otel_tracer.hrl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%% macros for tracing
%% register a tracer for an application with opentelemetry:register_application_tracer(AppName)

-define(current_tracer, opentelemetry:get_tracer(?MODULE)).
-define(current_tracer, opentelemetry:get_application_tracer(?MODULE)).
-define(current_span_ctx, otel_tracer:current_span_ctx()).

-define(start_span(SpanName),
Expand Down
13 changes: 0 additions & 13 deletions apps/opentelemetry_api/lib/open_telemetry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ defmodule OpenTelemetry do
require OpenTelemetry.Tracer
require OpenTelemetry.Span

OpenTelemetry.register_application_tracer(:this_otp_app)

Tracer.start_span("some-span")
...
event = "ecto.query"
Expand Down Expand Up @@ -118,17 +116,6 @@ defmodule OpenTelemetry do
"""
@type status() :: :opentelemetry.status()

@doc """
Registering a [Named Tracer](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/api-tracing.md#obtaining-a-tracer) with the name of an OTP Application enables each module in
the Application to be mapped to the Named Tracer, named for the Application and using the
version of the currently loaded Application by that name.

Macros in `OpenTelemetry.Tracer` use the name of the module they are being used in in order
to lookup the Named Tracer registered for that module and using it for trace operations.
"""
@spec register_application_tracer(atom()) :: boolean()
defdelegate register_application_tracer(otp_app), to: :opentelemetry

defdelegate get_tracer(name), to: :opentelemetry
defdelegate register_tracer(name, vsn), to: :opentelemetry
defdelegate set_default_tracer(t), to: :opentelemetry
Expand Down
5 changes: 2 additions & 3 deletions apps/opentelemetry_api/lib/open_telemetry/tracer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ defmodule OpenTelemetry.Tracer do
a different Span to be the current Span by passing the Span's context, end a Span or run a code
block within the context of a newly started span that is ended when the code block completes.

The macros use the Tracer registered to the Application the module using the macro is included in,
assuming `OpenTelemetry.register_application_tracer/1` has been called for the Application. If
not then the default Tracer is used.
The macros `start_span` and `with_span` use the Tracer registered to the Application the module
is included in. These Tracers are created at boot time for each loaded Application.

require OpenTelemetry.Tracer

Expand Down
Loading