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

A reopening of PR #7 because circleci got confused or something #13

Closed
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
23 changes: 6 additions & 17 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2.1

orbs:
rebar3: tsloughter/rebar3@0.7.0
rebar3: tsloughter/rebar3@0.8.1
codecov: circleci/codecov@0.0.3

jobs:
Expand All @@ -18,33 +18,22 @@ jobs:
- codecov/upload:
path: _build/test/covertool/opentelemetry.covertool.xml

erlang21: &erlang21
erlang22: &erlang22
executor:
name: rebar3/erlang
tag: "21"
tag: "22"

erlang22: &erlang22
erlang21: &erlang21
executor:
name: rebar3/erlang
tag: "22"
tag: "21"

workflows:
otp21:
jobs:
- rebar3/compile:
<<: *erlang21
- rebar3/xref:
<<: *erlang21
requires:
- rebar3/compile
- rebar3/dialyzer:
<<: *erlang21
requires:
- rebar3/compile
- rebar3/ct:
<<: *erlang21
requires:
- rebar3/compile

otp22:
jobs:
- rebar3/compile:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ Requires OTP 21.3 of above.

## Design

The [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification) defines a language library as having 2 components, the API and the SDK. The API must not only define the interfaces of any implementation in that language but also be able to function as a minimal implementation. The SDK is the default implementation of the API that must be optional.

In this library the API is defined as the behaviours `ot_tracer`, `ot_span` and `ot_ctx`. It is not a separate Erlang application from the SDK, nor are there subdirectories following the [layout described in the spec](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/library-layout.md). Not using subdirectories as the spec's layout describes is simply because the OTP application structure has all source files directly under `src/`. There is no separation of API and SDK into distinct libraries because a) there is not yet support in rebar3 for using git repos with multiple applications as dependencies b) since Erlang has a flat namespace the same module naming strategy would be used whether they are separate applications or not. Additionally, a release can be configured to drop any part of an application the user chooses. So in the unlikely event there are users who wish to not include the SDK's default implementation it is possible.

### Default Tracer

## Benchmarks

Running benchmarks is done with [benchee](https://github.com/bencheeorg/benchee). Benchmark functions are in modules under `samples/`. To run them open a rebar3 shell in the `bench` profile:
Expand Down
3 changes: 2 additions & 1 deletion src/opentelemetry.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
stdlib,
wts
]},
{env,[]},
{env, [{tracer, {ot_tracer_default, #{span => {ot_span_ets, []},
ctx => {ot_ctx_pdict, []}}}}]},
{modules, []},

{licenses, ["Apache 2.0"]},
Expand Down
8 changes: 7 additions & 1 deletion src/opentelemetry_app.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@

start(_StartType, _StartArgs) ->
Opts = application:get_all_env(opentelemetry),
opentelemetry_sup:start_link(Opts).

%% if the span impl needs to have a process supervised it must be
%% setup after the supervision tree has started.
{tracer, {Tracer, TracerOpts}} = lists:keyfind(tracer, 1, Opts),
Children = ot_tracer:setup(Tracer, TracerOpts),

opentelemetry_sup:start_link(Children, Opts).

stop(_State) ->
ok.
Expand Down
10 changes: 5 additions & 5 deletions src/opentelemetry_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@

-behaviour(supervisor).

-export([start_link/1]).
-export([start_link/2]).

-export([init/1]).

-define(SERVER, ?MODULE).

start_link(Opts) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, [Opts]).
start_link(Children, Opts) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, [Children, Opts]).

init([Opts]) ->
init([Children, Opts]) ->
SupFlags = #{strategy => one_for_one,
intensity => 0,
period => 1},
ChildSpecs = [#{id => ot_span_sup,
start => {ot_span_sup, start_link, [Opts]},
type => supervisor}],
type => supervisor} | Children],
{ok, {SupFlags, ChildSpecs}}.

%% internal functions
23 changes: 0 additions & 23 deletions src/ot_ctx.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,7 @@
%%%-------------------------------------------------------------------------
-module(ot_ctx).

-export([with_value/2,
with_value/3,
get/1,
get/2]).

-callback get(term()) -> term().
-callback get(term(), term()) -> term().
-callback with_value(term(), term()) -> ok.
-callback with_value(term(), term(), fun()) -> ok.

-define(ctx, (persistent_term:get({opentelemetry, ctx}, ot_ctx_pdict))).

-spec get(term()) -> term().
get(Key) ->
?ctx:get(Key).

-spec get(term(), term()) -> term().
get(Key, Default) ->
?ctx:get(Key, Default).

-spec with_value(term(), term()) -> ok.
with_value(Key, Value) ->
?ctx:with_value(Key, Value).

-spec with_value(term(), term(), fun()) -> ok.
with_value(Key, Value, Fun) ->
?ctx:with_value(Key, Value, Fun).
90 changes: 3 additions & 87 deletions src/ot_span.erl
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,11 @@
%% limitations under the License.
%%
%% @doc
%% Functional interface for span record and callbacks for implementations of
%% span storage to follow.
%% Span behaviour.
%% @end
%%%-------------------------------------------------------------------------
-module(ot_span).

-export([start_span/1,
start_span/2,
end_span/1]).

-include("opentelemetry.hrl").

-type start_opts() :: #{parent => undefined | opentelemetry:span() | opentelemetry:span_ctx(),
sampler => module(),
links => opentelemetry:links(),
Expand All @@ -33,90 +26,13 @@

-export_type([start_opts/0]).

-callback start_span(opentelemetry:span_name(), start_opts()) -> opentelemetry:span().
-callback start_span(opentelemetry:span_name(), start_opts()) -> opentelemetry:span_ctx().
-callback finish_span(opentelemetry:span_ctx()) -> ok.
-callback get_ctx(opentelemetry:span()) -> opentelemetry:span_ctx().
-callback is_recording_events(opentelemetry:span_ctx()) -> boolean().
-callback set_attributes(opentelemetry:span_ctx(), opentelemetry:attributes()) -> ok.
-callback add_events(opentelemetry:span_ctx(), opentelemetry:time_events()) -> ok.
-callback add_links(opentelemetry:span_ctx(), opentelemetry:links()) -> ok.
-callback set_status(opentelemetry:span_ctx(), opentelemetry:status()) -> ok.
-callback update_name(opentelemetry:span_ctx(), opentelemetry:span_name()) -> ok.
-callback finish_span(opentelemetry:span_ctx()) -> ok.

%% sampling bit is the first bit in 8-bit trace options
-define(IS_ENABLED(X), (X band 1) =/= 0).

-spec start_span(opentelemetry:span_name()) -> {opentelemetry:span_ctx(), opentelemetry:span()}.
start_span(Name) ->
start_span(Name, #{}).

-spec start_span(opentelemetry:span_name(), start_opts())
-> {opentelemetry:span_ctx(), opentelemetry:span() | undefined}.
start_span(Name, Opts) ->
Parent = maps:get(parent, Opts, undefined),
Attributes = maps:get(attributes, Opts, []),
Links = maps:get(links, Opts, []),
Kind = maps:get(kind, Opts, ?SPAN_KIND_UNSPECIFIED),

%% TODO: support overriding the sampler
_Sampler = maps:get(sampler, Opts, undefined),

new_span_(Name, Parent, Kind, Attributes, Links).

%% if parent is undefined, first run sampler
new_span_(Name, undefined, Kind, Attributes, Links) ->
TraceId = opentelemetry:generate_trace_id(),
Span = #span_ctx{trace_id=TraceId,
trace_options=0},
TraceOptions = update_trace_options(should_sample, Span),
new_span_(Name, Span#span_ctx{trace_options=TraceOptions}, Kind, Attributes, Links);
%% if parent is remote, first run sampler
%% new_span_(Name, Span=#span_ctx{}, Kind, Attributes) %% when RemoteParent =:= true
%% ->
%% TraceOptions = update_trace_options(should_sample, Span),
%% new_span_(Name, Span#span_ctx{trace_options=TraceOptions}, Kind, Attributes);
new_span_(Name, Parent=#span_ctx{trace_id=TraceId,
trace_options=TraceOptions,
tracestate=Tracestate,
span_id=ParentSpanId}, Kind, Attributes, Links)
when ?IS_ENABLED(TraceOptions) ->
SpanId = opentelemetry:generate_span_id(),
Span = #span{trace_id=TraceId,
span_id=SpanId,
tracestate=Tracestate,
start_time=wts:timestamp(),
parent_span_id=ParentSpanId,
kind=Kind,
name=Name,
attributes=Attributes,
links=Links},
{Parent#span_ctx{span_id=SpanId}, Span};
new_span_(_Name, Parent, _Kind, _, _) ->
SpanId = opentelemetry:generate_span_id(),
%% since discarded by sampler, create no span
{Parent#span_ctx{span_id=SpanId}, undefined}.

%%
update_trace_options(should_sample, #span_ctx{trace_id=_TraceId,
span_id=_ParentSpanId,
trace_options=_ParentTraceOptions}) ->
1.
%% case oc_sampler:should_sample(TraceId, ParentSpanId, ?IS_ENABLED(ParentTraceOptions)) of
%% true ->
%% 1;
%% false ->
%% 0
%% end.

%%--------------------------------------------------------------------
%% @doc
%% Set the end time for a span if it hasn't been set before.
%% @end
%%--------------------------------------------------------------------
-spec end_span(opentelemetry:span()) -> opentelemetry:span().
end_span(Span=#span{end_time=undefined,
trace_options=TraceOptions}) when ?IS_ENABLED(TraceOptions) ->
EndTime = wts:timestamp(),
Span#span{end_time=EndTime};
end_span(Span) ->
Span.
51 changes: 40 additions & 11 deletions src/ot_span_ets.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,23 @@
%%%-------------------------------------------------------------------------
-module(ot_span_ets).

-behaviour(ot_span).
-behaviour(gen_server).

-export([start_link/1,
init/1,
handle_call/3,
handle_cast/2]).

-export([start_span/1,
start_span/2,
finish_span/1]).
-export([start_span/2,
finish_span/1,
get_ctx/1,
is_recording_events/1,
set_attributes/2,
add_events/2,
add_links/2,
set_status/2,
update_name/2]).

-include("opentelemetry.hrl").

Expand All @@ -39,16 +46,10 @@
start_link(Opts) ->
gen_server:start_link(?MODULE, Opts, []).

%% @equiv start_span(Name, #{})
-spec start_span(opentelemetry:span_name()) -> opentelemetry:span_ctx().
start_span(Name) ->
start_span(Name, #{}).


%% @doc Start a span and insert into the active span ets table.
-spec start_span(opentelemetry:span_name(), ot_span:start_opts()) -> opentelemetry:span_ctx().
start_span(Name, Opts) ->
{SpanCtx, Span} = ot_span:start_span(Name, Opts),
{SpanCtx, Span} = ot_span_utils:start_span(Name, Opts),
_ = storage_insert(Span),
SpanCtx.

Expand All @@ -59,7 +60,7 @@ finish_span(#span_ctx{span_id=SpanId,
trace_options=TraceOptions}) when ?IS_SPAN_ENABLED(TraceOptions) ->
case ets:take(?SPAN_TAB, SpanId) of
[Span] ->
_Span1 = ot_span:end_span(Span#span{tracestate=Tracestate}),
_Span1 = ot_span_utils:end_span(Span#span{tracestate=Tracestate}),
%% oc_reporter:store_span(Span1),
ok;
_ ->
Expand All @@ -68,6 +69,34 @@ finish_span(#span_ctx{span_id=SpanId,
finish_span(_) ->
ok.

-spec get_ctx(opentelemetry:span()) -> opentelemetry:span_ctx().
get_ctx(_Span) ->
#span_ctx{}.

-spec is_recording_events(opentelemetry:span_ctx()) -> boolean().
is_recording_events(_SpanCtx) ->
false.

-spec set_attributes(opentelemetry:span_ctx(), opentelemetry:attributes()) -> ok.
set_attributes(_SpanCtx, _Attributes) ->
ok.

-spec add_events(opentelemetry:span_ctx(), opentelemetry:time_events()) -> ok.
add_events(_SpanCtx, _TimeEvents) ->
ok.

-spec add_links(opentelemetry:span_ctx(), opentelemetry:links()) -> ok.
add_links(_SpanCtx, _Links) ->
ok.

-spec set_status(opentelemetry:span_ctx(), opentelemetry:status()) -> ok.
set_status(_SpanCtx, _Status) ->
ok.

-spec update_name(opentelemetry:span_ctx(), opentelemetry:span_name()) -> ok.
update_name(_SpanCtx, _SpanName) ->
ok.

%%

storage_insert(undefined) ->
Expand Down
11 changes: 7 additions & 4 deletions src/ot_span_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

-behaviour(supervisor).

-export([start_link/1]).
-export([start_link/1,
start_child/1]).

-export([init/1]).

Expand All @@ -28,12 +29,14 @@
start_link(Opts) ->
supervisor:start_link({local, ?SERVER}, ?MODULE, [Opts]).

init([Opts]) ->
start_child(ChildSpec) ->
supervisor:start_child(?SERVER, ChildSpec).

init([_Opts]) ->
SupFlags = #{strategy => one_for_one,
intensity => 0,
period => 1},
ChildSpecs = [#{id => ot_span_ets,
start => {ot_span_ets, start_link, [Opts]}}],
ChildSpecs = [],
{ok, {SupFlags, ChildSpecs}}.

%% internal functions
Loading