Packages

OpenTracing Toolkit for ERlang

Current section

Files

Jump to
otter src otter_span_id_api.erl
Raw

src/otter_span_id_api.erl

%%%-------------------------------------------------------------------
%%% Licensed to the Apache Software Foundation (ASF) under one
%%% or more contributor license agreements. See the NOTICE file
%%% distributed with this work for additional information
%%% regarding copyright ownership. The ASF licenses this file
%%% to you under the Apache License, Version 2.0 (the
%%% "License"); you may not use this file except in compliance
%%% with the License. You may obtain a copy of the License at
%%%
%%% http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Unless required by applicable law or agreed to in writing,
%%% software distributed under the License is distributed on an
%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%%% KIND, either express or implied. See the License for the
%%% specific language governing permissions and limitations
%%% under the License.
%%%
%%% @doc
%%% This API uses a separate process to collect information of a span. The
%%% idea behind this is to provide a static ID which can be used to refer
%%% to the span. This is more convenient to integrate than the basic
%%% functional API is not limited by process boundaries as with the process
%%% dictionary APIs. The API also supports pre filtering with the
%%% start_with_tags functions.
%%% @end
%%%-------------------------------------------------------------------
-module(otter_span_id_api).
-export([
start/1, start/2, start/3,
start_with_tags/2, start_with_tags/3, start_with_tags/4,
finish/1,
ids/1,
log/2, log/3,
tag/3, tag/4
]).
-include_lib("otter_lib/src/otter.hrl").
%%----------------------------------------------------------------------
%% @doc Start a new span collection process
%% @end
%%----------------------------------------------------------------------
-spec start(Name :: info()) -> pid().
start(Name) ->
span_process(otter_lib_span:start(Name)).
%%----------------------------------------------------------------------
%% @doc Start a new span collection process with an existing trace id or
%% parent span
%% @end
%%----------------------------------------------------------------------
-spec start(Name :: info(), TraceId :: trace_id()) -> pid();
(Name :: info(), ParentSpan :: span()) -> pid().
start(Name, #span{trace_id = TraceId, id = ParentId}) ->
span_process(otter_lib_span:start(Name, TraceId, ParentId));
start(Name, TraceId) when is_integer(TraceId) ->
span_process(otter_lib_span:start(Name, TraceId)).
%%----------------------------------------------------------------------
%% @doc Start a new span collection process with an existing trace id and
%% parent span id
%% @end
%%----------------------------------------------------------------------
-spec start(Name :: info(), TraceId :: trace_id(), ParentId :: integer()) -> pid().
start(Name, TraceId, ParentId) when is_integer(TraceId), is_integer(ParentId) ->
span_process(otter_lib_span:start(Name, TraceId, ParentId)).
%%----------------------------------------------------------------------
%% @doc Start a new span with a list of tags and pass it to pre filtering.
%% If the span is active then start a span collection process. For inactive
%% span the atom `undefined' is returned instead of the PID.
%% @end
%%----------------------------------------------------------------------
-spec start_with_tags(Name :: info(), Tags :: [tag()]) -> pid() | undefined.
start_with_tags(Name, Tags) ->
Span = otter_lib_span:start_with_tags(Name, Tags),
case otter_filter:pre_span(Span) of
NewSpan when ?is_span_active(NewSpan) ->
span_process(NewSpan);
_ ->
undefined
end.
%%----------------------------------------------------------------------
%% @doc Start a new span with a list of tags and a trace id or parent span
%% and pass it to pre filtering.
%% If the span is active then start a span collection process. For inactive
%% span the atom `undefined' is returned instead of the PID.
%% @end
%%----------------------------------------------------------------------
-spec start_with_tags(Name :: info(), Tags :: [tag()], TraceId :: trace_id()) -> pid() | undefined;
(Name :: info(), Tags :: [tag()], ParentSpan :: span()) -> pid() | undefined.
start_with_tags(Name, Tags, #span{trace_id = TraceId, id = ParentId}) ->
Span = otter_lib_span:start_with_tags(Name, Tags, TraceId, ParentId),
case otter_filter:pre_span(Span) of
NewSpan when ?is_span_active(NewSpan) ->
span_process(NewSpan);
_ ->
undefined
end;
start_with_tags(Name, Tags, TraceId) when is_integer(TraceId) ->
Span = otter_lib_span:start_with_tags(Name, Tags, TraceId),
case otter_filter:pre_span(Span) of
NewSpan when ?is_span_active(NewSpan) ->
span_process(NewSpan);
_ ->
undefined
end.
%%----------------------------------------------------------------------
%% @doc Start a new span with a list of tags, a trace id and parent span id
%% then pass it to pre filtering.
%% If the span is active then start a span collection process. For inactive
%% span the atom `undefined' is returned instead of the PID.
%% @end
%%----------------------------------------------------------------------
-spec start_with_tags(Name :: info(), Tags :: [tag()], TraceId :: trace_id(), ParentId :: span_id()) -> pid() | undefined.
start_with_tags(Name, Tags, TraceId, ParentId) when is_integer(TraceId), is_integer(ParentId) ->
Span = otter_lib_span:start_with_tags(Name, Tags, TraceId, ParentId),
case otter_filter:pre_span(Span) of
NewSpan when ?is_span_active(NewSpan) ->
span_process(NewSpan);
_ ->
undefined
end.
%%----------------------------------------------------------------------
%% @doc Add a tag to the span
%% @end
%%----------------------------------------------------------------------
-spec tag(Pid :: pid()|undefined, Key :: info(), Value :: info()) -> ok.
tag(undefined, _Key, _Value) ->
ok;
tag(Pid, Key, Value) ->
Pid ! {tag, Key, Value},
ok.
%%----------------------------------------------------------------------
%% @doc Add a tag to the span with specific service information
%% @end
%%----------------------------------------------------------------------
-spec tag(Pid :: pid()|undefined, Key :: info(), Value :: info(), Service :: service()) -> ok.
tag(undefined, _Key, _Value, _Service) ->
ok;
tag(Pid, Key, Value, Service) ->
Pid ! {tag, Key, Value, Service},
ok.
%%----------------------------------------------------------------------
%% @doc Add a log to the span
%% @end
%%----------------------------------------------------------------------
-spec log(Pid :: pid()|undefined, Text :: info()) -> ok.
log(undefined, _Text) ->
ok;
log(Pid, Text) ->
Pid ! {log, Text},
ok.
%%----------------------------------------------------------------------
%% @doc Add a log to the span with specific service information
%% @end
%%----------------------------------------------------------------------
-spec log(Pid :: pid()|undefined, Text :: info(), Service :: service()) -> ok.
log(undefined, _Text, _Service) ->
ok;
log(Pid, Text, Service) ->
Pid ! {log, Text, Service},
ok.
%%----------------------------------------------------------------------
%% @doc Finish the span and pass it to filtering if it is active
%% @end
%%----------------------------------------------------------------------
-spec finish(Pid :: pid()|undefined) -> ok.
finish(undefined) ->
ok;
finish(Pid) ->
Pid ! finish,
ok.
%%----------------------------------------------------------------------
%% @doc Get the trace id and span id from a span. If the span is inactive
%% it returns the tuple `{0,0}'
%% @end
%%----------------------------------------------------------------------
-spec ids(Pid :: pid()|undefined) -> {trace_id(), span_id()}.
ids(undefined) ->
{0, 0};
ids(Pid) ->
Pid ! {get_ids, self()},
receive
{otter_span_ids, Ids} -> Ids
after
%% Actually I should in general (re)consider the error handling
%% of otter : probably we'd be better off crashing in the span
%% encoding phase due to silly data, generated by errors, than
%% crashing the request handling process we are tracing ...
%% So considering this we'll return {0, 0} and perhaps we should
%% add a counter to keep track of these errors
300 ->
otter_lib_snapshot_count:snapshot(otter_span_mpdict_api_get_id_timeout, []),
{0, 0}
end.
%%----------------------------------------------------------------------
%% Internal helper
%%----------------------------------------------------------------------
span_process(Span) ->
Timeout = otter_config:read(span_id_api_process_timeout, 30000),
spawn(fun() -> span_process(Span, Timeout) end).
span_process(Span, Timeout) ->
receive
{tag, Key, Value} ->
span_process(otter_lib_span:tag(Span, Key, Value), Timeout);
{tag, Key, Value, Service} ->
span_process(otter_lib_span:tag(Span, Key, Value, Service), Timeout);
{log, Text} ->
span_process(otter_lib_span:log(Span, Text), Timeout);
{log, Text, Service} ->
span_process(otter_lib_span:log(Span, Text, Service), Timeout);
{get_ids, Pid} ->
Pid ! {otter_span_ids, otter_lib_span:get_ids(Span)},
span_process(Span, Timeout);
finish ->
otter_filter:span(otter_lib_span:finish(Span))
after
Timeout ->
ok
end.