Merge pull request #3 from iilyak/add-http-reporter
Add HTTP reporter
diff --git a/README.md b/README.md
index ddfd2a6..078eee6 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,23 @@
$ firefox http://localhost:16686/
```
+Selecting reporter
+------------------
+
+By default 'compact' jaeger.thrift over UDP reporter is used. However it is
+possible to select different reporter. Bellow is a configuration matrics for
+available options:
+
+| protocol | thrift_protocol | jaeger port | description |
+|----------|-----------------|-------------|----------------------------------|
+| udp | compact | 6831 | accept jaeger.thrift over compact thrift protocol (default) |
+| udp | binary | 6832 | accept jaeger.thrift over binary thrift protocol |
+| http | N/A | 14268 | accept jaeger.thrift directly from clients |
+
+The HTTP version is beneficial if you don't have jaeger agents deployed or your
+spans are greater than max udp packet size (65Kb).
+Otherwise it is better to use default.
+
References
-----------
@@ -52,3 +69,4 @@
- [Jaeger](https://uber.github.io/jaeger/)
- [jaeger-client-go/README.md](https://github.com/jaegertracing/jaeger-client-go/blob/v2.9.0/README.md)
- [Jaeger Client Library](https://github.com/jaegertracing/jaeger/blob/master/docs/client_libraries.md)
+- [Jaeger default ports](https://www.jaegertracing.io/docs/1.8/getting-started/)
\ No newline at end of file
diff --git a/rebar.config.script b/rebar.config.script
index 4454cdc..74eb314 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -5,7 +5,7 @@
[
{local, ".*", {git, "https://github.com/sile/local.git", {tag, "0.2.1"}}},
{passage, ".*", {git, "https://github.com/sile/passage.git", {tag, "0.2.6"}}},
- {thrift_protocol, ".*", {git, "https://github.com/sile/thrift_protocol.git", {tag, "0.1.3"}}}
+ {thrift_protocol, ".*", {git, "https://github.com/sile/thrift_protocol.git", {tag, "0.1.5"}}}
],
case IsRebar3 of
diff --git a/rebar.lock b/rebar.lock
index c9ba4ec..9d5110a 100644
--- a/rebar.lock
+++ b/rebar.lock
@@ -1,10 +1,10 @@
{"1.1.0",
[{<<"local">>,{pkg,<<"local">>,<<"0.2.1">>},0},
{<<"passage">>,{pkg,<<"passage">>,<<"0.2.6">>},0},
- {<<"thrift_protocol">>,{pkg,<<"thrift_protocol">>,<<"0.1.3">>},0}]}.
+ {<<"thrift_protocol">>,{pkg,<<"thrift_protocol">>,<<"0.1.5">>},0}]}.
[
{pkg_hash,[
{<<"local">>, <<"F82483CD6DB6A39B0E4C59B37C2FCCCF5B96D90A746AFC3D79A81D31E3D40963">>},
{<<"passage">>, <<"7B0A6F0A6806B056DC3323A6A0243503642E6425F45E33B87277EA0BE88BD130">>},
- {<<"thrift_protocol">>, <<"CDD0C06BFC235159D789353CBB4F01F9FF04592F30329CB3DF2C77E28D92CCC0">>}]}
+ {<<"thrift_protocol">>, <<"300DB7CA06BED397406A4680AD3DD3A0212AC7BEABDC81FA03C3C3DADEA13673">>}]}
].
diff --git a/src/jaeger_passage.erl b/src/jaeger_passage.erl
index 50c5aa5..cf27120 100644
--- a/src/jaeger_passage.erl
+++ b/src/jaeger_passage.erl
@@ -33,7 +33,7 @@
Tracer :: passage:tracer_id(),
Sampler :: passage_sampler:sampler().
start_tracer(Tracer, Sampler) ->
- start_tracer(Tracer, Sampler, []).
+ start_tracer(Tracer, Sampler, [{protocol, udp}]).
%% @doc Starts a tracer for Jaeger.
%%
diff --git a/src/jaeger_passage_reporter.erl b/src/jaeger_passage_reporter.erl
index 32f537e..1287f48 100644
--- a/src/jaeger_passage_reporter.erl
+++ b/src/jaeger_passage_reporter.erl
@@ -29,7 +29,6 @@
-module(jaeger_passage_reporter).
-behaviour(passage_reporter).
--behaviour(gen_server).
-include("constants.hrl").
@@ -45,36 +44,11 @@
-export_type([start_option/0, start_options/0]).
%%------------------------------------------------------------------------------
-%% Application Internal API
-%%------------------------------------------------------------------------------
--export([start_link/2]).
-
-%%------------------------------------------------------------------------------
%% 'passage_reporter' Callback API
%%------------------------------------------------------------------------------
-export([report/2]).
%%------------------------------------------------------------------------------
-%% 'gen_server' Callback API
-%%------------------------------------------------------------------------------
--export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-
-%%------------------------------------------------------------------------------
-%% Macros & Records
-%%------------------------------------------------------------------------------
--define(STATE, ?MODULE).
-
--record(?STATE,
- {
- socket :: gen_udp:socket(),
- thrift_format :: thrift_protocol:format(),
- agent_host :: inet:hostname(),
- agent_port :: inet:port_number(),
- default_service_name :: atom(),
- process_tags :: passage:tags()
- }).
-
-%%------------------------------------------------------------------------------
%% Exported Types
%%------------------------------------------------------------------------------
-type reporter_id() :: atom().
@@ -83,28 +57,28 @@
-type start_options() :: [start_option()].
%% Options for {@link start/2}.
--type start_option() :: {thrift_format, thrift_protocol:format()}
- | {agent_host, inet:hostname()}
- | {agent_port, inet:port_number()}
+-type start_option() :: jaeger_passage_reporter_udp:start_option()
+ | jaeger_passage_reporter_http:start_option()
+ | {protocol, udp | http}
| {default_service_name, atom()}
| {process_tags, passage:tags()}.
+
+%% Common reporter options
+%% <ul>
+%% <li><b>protocol</b>: Communication protocol used to connect to jaeger. The value is used to select reporter module. Possible values are: `udp' | `http'. The default value is `udp'.</li>
+%% <li><b>default_service_name</b>: The default service name. If a reporting span has `location.application' tag, the value is used as the service name instead of this. The default value is `ReporterId'.</li>
+%% <li><b>process_tags</b>: The tags of the reporting process. The default value is `#{}'.</li>
+%% </ul>
+%% UDP reporter specific options
%% <ul>
%% <li><b>thrift_format</b>: The format for encoding thrift messages. The default value is `compact'.</li>
%% <li><b>agent_host</b>: The hostname of the jaeger agent. The default value is `"127.0.0.1"'.</li>
%% <li><b>agent_port</b>: The port of the jaeger agent. The default values for the thrift format `compact' and `binary' are `6831' and `6832' respectively.</li>
-%% <li><b>default_service_name</b>: The default service name. If a reporting span has `location.application' tag, the value is used as the service name instead of this. The default value is `ReporterId'.</li>
-%% <li><b>process_tags</b>: The tags of the reporting process. The default value is `#{}'.</li>
%% </ul>
-
-%%------------------------------------------------------------------------------
-%% Application Internal Functions
-%%------------------------------------------------------------------------------
-%% @private
--spec start_link(reporter_id(), start_options()) -> {ok, pid()} | {error, Reason} when
- Reason :: {already_started, pid()} | term().
-start_link(ReporterId, Options) ->
- Name = jaeger_passage_local_ns:reporter_name(ReporterId),
- gen_server:start_link(Name, ?MODULE, {ReporterId, Options}, []).
+%% HTTP reporter specific options
+%% <ul>
+%% <li><b>endpoint</b>: The jaeger endpoint URL for sending thrift messages. The default value is `http://127.0.0.1:14268'.</li>
+%% </ul>
%%------------------------------------------------------------------------------
%% Exported Functions
@@ -113,7 +87,7 @@
-spec start(reporter_id()) -> {ok, passage_reporter:reporter()} | {error, Reason} when
Reason :: {already_started, pid()} | term().
start(ReporterId) ->
- start(ReporterId, []).
+ start(ReporterId, [{protocol, udp}]).
%% @doc Starts a reporter process.
-spec start(reporter_id(), start_options()) -> {ok, Reporter} | {error, Reason} when
@@ -123,8 +97,13 @@
Args = [ReporterId, Options],
is_atom(ReporterId) orelse error(badarg, Args),
is_list(Options) orelse error(badarg, Args),
-
- case jaeger_passage_reporter_sup:start_child(ReporterId, Options) of
+ ReporterModule = case proplists:get_value(protocol, Options, udp) of
+ udp -> jaeger_passage_reporter_udp;
+ http -> jaeger_passage_reporter_http;
+ _ -> error(badarg, Args)
+ end,
+ ReporterOptions = proplists:delete(protocol, Options),
+ case jaeger_passage_reporter_sup:start_child(ReporterId, ReporterModule, ReporterOptions) of
{error, Reason} -> {error, Reason};
{ok, _Pid} -> {ok, passage_reporter:new(?MODULE, ReporterId)}
end.
@@ -158,74 +137,3 @@
report(ReporterId, Span) ->
Server = jaeger_passage_local_ns:reporter_name(ReporterId),
gen_server:cast(Server, {report, Span}).
-
-%%------------------------------------------------------------------------------
-%% 'gen_server' Callback Functions
-%%------------------------------------------------------------------------------
-%% @private
-init({ReporterId, Options}) ->
- Format = proplists:get_value(thrift_format, Options, compact),
- DefaultPort =
- case Format of
- compact -> 6831;
- binary -> 6832
- end,
- AgentHost = proplists:get_value(agent_host, Options, "127.0.0.1"),
- AgentPort = proplists:get_value(agent_port, Options, DefaultPort),
- DefaultServiceName = proplists:get_value(default_service_name, Options, ReporterId),
- Tags0 = proplists:get_value(process_tags, Options, #{}),
-
- {ok, Hostname} = inet:gethostname(),
- {ok, Version} = application:get_key(vsn),
- Tags1 =
- maps:merge(
- Tags0,
- #{
- ?JAEGER_CLIENT_VERSION_TAG_KEY => list_to_binary(["jaeger_passage-", Version]),
- ?TRACER_HOSTNAME_TAG_KEY => list_to_binary(Hostname),
- 'erlang.node' => node()
- }),
- {ok, Socket} = gen_udp:open(0),
- State =
- #?STATE{
- socket = Socket,
- thrift_format = Format,
- agent_host = AgentHost,
- agent_port = AgentPort,
- default_service_name = DefaultServiceName,
- process_tags = Tags1
- },
- {ok, State}.
-
-%% @private
-handle_call(_Request, _From, State) ->
- {noreply, State}.
-
-%% @private
-handle_cast({report, Span}, State) ->
- handle_report(Span, State);
-handle_cast(_Request, State) ->
- {noreply, State}.
-
-%% @private
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%% @private
-terminate(_Reason, _State) ->
- ok.
-
-%% @private
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%------------------------------------------------------------------------------
-%% Internal Functions
-%%------------------------------------------------------------------------------
--spec handle_report(passage_span:span(), #?STATE{}) -> {noreply, #?STATE{}}.
-handle_report(Span, State = #?STATE{default_service_name = DefaultName, process_tags = Tags}) ->
- Name = maps:get('location.application', passage_span:get_tags(Span), DefaultName),
- Message = jaeger_passage_thrift:make_emit_batch_message(Name, Tags, [Span]),
- Encoded = thrift_protocol:encode_message(Message, State#?STATE.thrift_format),
- ok = gen_udp:send(State#?STATE.socket, State#?STATE.agent_host, State#?STATE.agent_port, Encoded),
- {noreply, State}.
diff --git a/src/jaeger_passage_reporter_http.erl b/src/jaeger_passage_reporter_http.erl
new file mode 100644
index 0000000..0b0097c
--- /dev/null
+++ b/src/jaeger_passage_reporter_http.erl
@@ -0,0 +1,185 @@
+%% @doc A reporter that sends the spans to an jaeger agent
+%%
+%% === Examples ===
+%%
+%% ```
+%% %% Starts `example_reporter'
+%% {ok, Reporter} = jaeger_passage_reporter:start(example_reporter, [{protocol, http}]).
+%% [example_reporter] = jaeger_passage_reporter:which_reporters().
+%%
+%% %% Registers `example_tracer'
+%% Context = jaeger_passage_span_context.
+%% Sampler = passage_sampler_all:new().
+%% ok = passage_tracer_registry:register(example_tracer, Context, Sampler, Reporter).
+%%
+%% %% Starts and finishes a span
+%% Span = passage:start_span(example, [{tracer, example_tracer}]).
+%%
+%% passage:finish_span(Span). % The span will send to the jaeger agent on the localhost
+%% '''
+%%
+%% === Refereces ===
+%%
+%% <ul>
+%% <li><a href="http://jaeger.readthedocs.io/en/latest/architecture/#agent">Jaeger - Architecture - Agent</a></li>
+%% <li><a href="http://jaeger.readthedocs.io/en/latest/deployment/#agent">Jaeger - Deployment - Agent</a></li>
+%% </ul>
+-module(jaeger_passage_reporter_http).
+
+-behaviour(gen_server).
+
+-include("constants.hrl").
+
+%%------------------------------------------------------------------------------
+%% Exported API
+%%------------------------------------------------------------------------------
+-export_type([start_option/0, start_options/0]).
+
+%%------------------------------------------------------------------------------
+%% Application Internal API
+%%------------------------------------------------------------------------------
+-export([start_link/2]).
+
+%%------------------------------------------------------------------------------
+%% 'gen_server' Callback API
+%%------------------------------------------------------------------------------
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+%%------------------------------------------------------------------------------
+%% Macros & Records
+%%------------------------------------------------------------------------------
+-define(STATE, ?MODULE).
+
+-record(?STATE,
+ {
+ endpoint :: string(),
+ options :: start_options(),
+ http_client :: http_client(),
+ default_service_name :: atom(),
+ process_tags :: passage:tags()
+ }).
+
+-define(CONTENT_TYPE, {"Content-Type", "application/x-thrift"}).
+
+%%------------------------------------------------------------------------------
+%% Exported Types
+%%------------------------------------------------------------------------------
+
+-type start_options() :: [start_option()].
+%% Options for {@link start/2}.
+
+-type start_option() :: {endpoint, string()}
+ | {http_client, http_client()}
+ | {default_service_name, atom()}
+ | {process_tags, passage:tags()}.
+%% <ul>
+%% <li><b>endpoint</b>: The jaeger endpoint URL for sending thrift messages. The default value is `http://127.0.0.1:14268'.</li>
+%% <li><b>http_client</b>: The callback to call to send span to jaeger. The httpc client is used by default.</li>
+%% <li><b>default_service_name</b>: The default service name. If a reporting span has `location.application' tag, the value is used as the service name instead of this. The default value is `ReporterId'.</li>
+%% <li><b>process_tags</b>: The tags of the reporting process. The default value is `#{}'.</li>
+%% </ul>
+%% Example of a http_client calback
+%% Client = fun(Url, Method, Headers, Body, ReporterOptions) ->
+%% User = proplists:get_value(user, ReporterOptions),
+%% Password = proplists:get_value(password, ReporterOptions),
+%% ibrowse:send_req(Url, Headers, Method, Body, [{basic_auth, {User, Password}}])
+%% end.
+
+
+-type http_client() :: fun((
+ Url :: string(),
+ Method :: post,
+ Headers :: [{string(), string()}],
+ Body :: string() | binary(),
+ ReporterOptions :: start_options()) ->
+ ok).
+
+%%------------------------------------------------------------------------------
+%% Application Internal Functions
+%%------------------------------------------------------------------------------
+%% @private
+-spec start_link(jaeger_passage_reporter:reporter_id(), start_options()) -> {ok, pid()} | {error, Reason} when
+ Reason :: {already_started, pid()} | term().
+start_link(ReporterId, Options) ->
+ Name = jaeger_passage_local_ns:reporter_name(ReporterId),
+ gen_server:start_link(Name, ?MODULE, {ReporterId, Options}, []).
+
+%%------------------------------------------------------------------------------
+%% 'gen_server' Callback Functions
+%%------------------------------------------------------------------------------
+%% @private
+init({ReporterId, Options}) ->
+ Endpoint = proplists:get_value(endpoint, Options, "http://127.0.0.1:14268"),
+ EndpointURL = Endpoint ++ "/api/traces",
+
+ HttpClient = proplists:get_value(http_client, Options, fun httpc_client/5),
+ is_function(HttpClient, 5) orelse error(badarg, [ReporterId, Options]),
+
+ DefaultServiceName = proplists:get_value(default_service_name, Options, ReporterId),
+ Tags0 = proplists:get_value(process_tags, Options, #{}),
+
+ {ok, Hostname} = inet:gethostname(),
+ {ok, Version} = application:get_key(vsn),
+ Tags1 =
+ maps:merge(
+ Tags0,
+ #{
+ ?JAEGER_CLIENT_VERSION_TAG_KEY => list_to_binary(["jaeger_passage-", Version]),
+ ?TRACER_HOSTNAME_TAG_KEY => list_to_binary(Hostname),
+ 'erlang.node' => node()
+ }),
+ State =
+ #?STATE{
+ endpoint = EndpointURL,
+ http_client = HttpClient,
+ options = Options,
+ default_service_name = DefaultServiceName,
+ process_tags = Tags1
+ },
+ {ok, State}.
+
+%% @private
+handle_call(_Request, _From, State) ->
+ {noreply, State}.
+
+%% @private
+handle_cast({report, Span}, State) ->
+ handle_report(Span, State);
+handle_cast(_Request, State) ->
+ {noreply, State}.
+
+%% @private
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%% @private
+terminate(_Reason, _State) ->
+ ok.
+
+%% @private
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%------------------------------------------------------------------------------
+%% Internal Functions
+%%------------------------------------------------------------------------------
+-spec handle_report(passage_span:span(), #?STATE{}) -> {noreply, #?STATE{}}.
+handle_report(Span, State = #?STATE{default_service_name = DefaultName, process_tags = Tags, endpoint = URI, http_client = HttpClient, options = Options}) ->
+ Name = maps:get('location.application', passage_span:get_tags(Span), DefaultName),
+ Message = jaeger_passage_thrift:make_batch(Name, Tags, [Span]),
+ Encoded = thrift_protocol:encode_struct(Message, binary),
+ Headers = [?CONTENT_TYPE],
+ HttpClient(URI, post, Headers, Encoded, Options),
+ {noreply, State}.
+
+-spec httpc_client(
+ Url :: string(),
+ Method :: post,
+ Headers :: [{string(), string()}],
+ Body :: string() | binary(),
+ ReporterOptions :: start_options()) ->
+ ok.
+
+httpc_client(Url, Method, _Headers, Body, _ReporterOptions) ->
+ httpc:request(Method, {Url, [], "application/x-thrift", Body}, [], []),
+ ok.
diff --git a/src/jaeger_passage_reporter_sup.erl b/src/jaeger_passage_reporter_sup.erl
index 529fde3..77f23ba 100644
--- a/src/jaeger_passage_reporter_sup.erl
+++ b/src/jaeger_passage_reporter_sup.erl
@@ -9,7 +9,7 @@
%% Application Internal API
%%------------------------------------------------------------------------------
-export([start_link/0]).
--export([start_child/2]).
+-export([start_child/3]).
-export([stop_child/1]).
-export([which_children/0]).
@@ -25,14 +25,15 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
--spec start_child(ReporterId, Options) -> {ok, pid()} | {error, Reason} when
+-spec start_child(ReporterId, ReporterModule, Options) -> {ok, pid()} | {error, Reason} when
ReporterId :: jaeger_passage_reporter:reporter_id(),
+ ReporterModule :: module(),
Options :: jaeger_passage_reporter:start_options(),
Reason :: {already_started, pid()} | term().
-start_child(ReporterId, Options) ->
+start_child(ReporterId, ReporterModule, Options) ->
Child = #{
id => ReporterId,
- start => {jaeger_passage_reporter, start_link, [ReporterId, Options]},
+ start => {ReporterModule, start_link, [ReporterId, Options]},
restart => permanent
},
supervisor:start_child(?MODULE, Child).
diff --git a/src/jaeger_passage_reporter_udp.erl b/src/jaeger_passage_reporter_udp.erl
new file mode 100644
index 0000000..485c258
--- /dev/null
+++ b/src/jaeger_passage_reporter_udp.erl
@@ -0,0 +1,160 @@
+%% @doc A reporter that sends the spans to an jaeger agent
+%%
+%% === Examples ===
+%%
+%% ```
+%% %% Starts `example_reporter'
+%% {ok, Reporter} = jaeger_passage_reporter:start(example_reporter, [{protocol, udp}]).
+%% [example_reporter] = jaeger_passage_reporter:which_reporters().
+%%
+%% %% Registers `example_tracer'
+%% Context = jaeger_passage_span_context.
+%% Sampler = passage_sampler_all:new().
+%% ok = passage_tracer_registry:register(example_tracer, Context, Sampler, Reporter).
+%%
+%% %% Starts and finishes a span
+%% Span = passage:start_span(example, [{tracer, example_tracer}]).
+%%
+%% passage:finish_span(Span). % The span will send to the jaeger agent on the localhost
+%% '''
+%%
+%% === Refereces ===
+%%
+%% <ul>
+%% <li><a href="http://jaeger.readthedocs.io/en/latest/architecture/#agent">Jaeger - Architecture - Agent</a></li>
+%% <li><a href="http://jaeger.readthedocs.io/en/latest/deployment/#agent">Jaeger - Deployment - Agent</a></li>
+%% </ul>
+-module(jaeger_passage_reporter_udp).
+
+-behaviour(gen_server).
+
+-include("constants.hrl").
+
+%%------------------------------------------------------------------------------
+%% Exported API
+%%------------------------------------------------------------------------------
+-export_type([start_option/0, start_options/0]).
+
+%%------------------------------------------------------------------------------
+%% Application Internal API
+%%------------------------------------------------------------------------------
+-export([start_link/2]).
+
+%%------------------------------------------------------------------------------
+%% 'gen_server' Callback API
+%%------------------------------------------------------------------------------
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+%%------------------------------------------------------------------------------
+%% Macros & Records
+%%------------------------------------------------------------------------------
+-define(STATE, ?MODULE).
+
+-record(?STATE,
+ {
+ socket :: gen_udp:socket(),
+ thrift_format :: thrift_protocol:format(),
+ agent_host :: inet:hostname(),
+ agent_port :: inet:port_number(),
+ default_service_name :: atom(),
+ process_tags :: passage:tags()
+ }).
+
+%%------------------------------------------------------------------------------
+%% Exported Types
+%%------------------------------------------------------------------------------
+
+-type start_options() :: [start_option()].
+%% Options for {@link start/2}.
+
+-type start_option() :: {thrift_format, thrift_protocol:format()}
+ | {agent_host, inet:hostname()}
+ | {agent_port, inet:port_number()}.
+%% <ul>
+%% <li><b>thrift_format</b>: The format for encoding thrift messages. The default value is `compact'.</li>
+%% <li><b>agent_host</b>: The hostname of the jaeger agent. The default value is `"127.0.0.1"'.</li>
+%% <li><b>agent_port</b>: The port of the jaeger agent. The default values for the thrift format `compact' and `binary' are `6831' and `6832' respectively.</li>
+%% <li><b>default_service_name</b>: The default service name. If a reporting span has `location.application' tag, the value is used as the service name instead of this. The default value is `ReporterId'.</li>
+%% <li><b>process_tags</b>: The tags of the reporting process. The default value is `#{}'.</li>
+%% </ul>
+
+%%------------------------------------------------------------------------------
+%% Application Internal Functions
+%%------------------------------------------------------------------------------
+%% @private
+-spec start_link(jaeger_passage_reporter:reporter_id(), start_options()) -> {ok, pid()} | {error, Reason} when
+ Reason :: {already_started, pid()} | term().
+start_link(ReporterId, Options) ->
+ Name = jaeger_passage_local_ns:reporter_name(ReporterId),
+ gen_server:start_link(Name, ?MODULE, {ReporterId, Options}, []).
+
+%%------------------------------------------------------------------------------
+%% 'gen_server' Callback Functions
+%%------------------------------------------------------------------------------
+%% @private
+init({ReporterId, Options}) ->
+ Format = proplists:get_value(thrift_format, Options, compact),
+ DefaultPort =
+ case Format of
+ compact -> 6831;
+ binary -> 6832
+ end,
+ AgentHost = proplists:get_value(agent_host, Options, "127.0.0.1"),
+ AgentPort = proplists:get_value(agent_port, Options, DefaultPort),
+ DefaultServiceName = proplists:get_value(default_service_name, Options, ReporterId),
+ Tags0 = proplists:get_value(process_tags, Options, #{}),
+
+ {ok, Hostname} = inet:gethostname(),
+ {ok, Version} = application:get_key(vsn),
+ Tags1 =
+ maps:merge(
+ Tags0,
+ #{
+ ?JAEGER_CLIENT_VERSION_TAG_KEY => list_to_binary(["jaeger_passage-", Version]),
+ ?TRACER_HOSTNAME_TAG_KEY => list_to_binary(Hostname),
+ 'erlang.node' => node()
+ }),
+ {ok, Socket} = gen_udp:open(0),
+ State =
+ #?STATE{
+ socket = Socket,
+ thrift_format = Format,
+ agent_host = AgentHost,
+ agent_port = AgentPort,
+ default_service_name = DefaultServiceName,
+ process_tags = Tags1
+ },
+ {ok, State}.
+
+%% @private
+handle_call(_Request, _From, State) ->
+ {noreply, State}.
+
+%% @private
+handle_cast({report, Span}, State) ->
+ handle_report(Span, State);
+handle_cast(_Request, State) ->
+ {noreply, State}.
+
+%% @private
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%% @private
+terminate(_Reason, _State) ->
+ ok.
+
+%% @private
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%------------------------------------------------------------------------------
+%% Internal Functions
+%%------------------------------------------------------------------------------
+-spec handle_report(passage_span:span(), #?STATE{}) -> {noreply, #?STATE{}}.
+handle_report(Span, State = #?STATE{default_service_name = DefaultName, process_tags = Tags}) ->
+ Name = maps:get('location.application', passage_span:get_tags(Span), DefaultName),
+ Message = jaeger_passage_thrift:make_emit_batch_message(Name, Tags, [Span]),
+ Encoded = thrift_protocol:encode_message(Message, State#?STATE.thrift_format),
+ ok = gen_udp:send(State#?STATE.socket, State#?STATE.agent_host, State#?STATE.agent_port, Encoded),
+ {noreply, State}.
diff --git a/src/jaeger_passage_thrift.erl b/src/jaeger_passage_thrift.erl
index 28537fd..d8d81da 100644
--- a/src/jaeger_passage_thrift.erl
+++ b/src/jaeger_passage_thrift.erl
@@ -15,7 +15,7 @@
%%------------------------------------------------------------------------------
%% Application Internal API
%%------------------------------------------------------------------------------
--export([make_emit_batch_message/3]).
+-export([make_emit_batch_message/3, make_batch/3]).
%%------------------------------------------------------------------------------
%% Macros
@@ -49,6 +49,12 @@
body = ?STRUCT(Batch)
}.
+-spec make_batch(atom(), passage:tags(), [passage_span:span()]) ->
+ thrift_protocol:struct().
+make_batch(ServiceName, ServiceTags, Spans) ->
+ Process = make_process(ServiceName, ServiceTags),
+ ?STRUCT(Process, make_spans(Spans)).
+
%%------------------------------------------------------------------------------
%% Internal Functions
%%------------------------------------------------------------------------------
diff --git a/test/jaeger_passage_repoter_tests.erl b/test/jaeger_passage_repoter_tests.erl
index 7aa1dd0..cdc25a5 100644
--- a/test/jaeger_passage_repoter_tests.erl
+++ b/test/jaeger_passage_repoter_tests.erl
@@ -6,27 +6,73 @@
%%------------------------------------------------------------------------------
%% Test Cases
%%------------------------------------------------------------------------------
-basic_test() ->
+basic_udp_test() ->
{ok, _} = application:ensure_all_started(jaeger_passage),
- %% Starts `test_reporter'
- {ok, Reporter} = jaeger_passage_reporter:start(test_reporter),
- [test_reporter] = jaeger_passage_reporter:which_reporters(),
+ %% Starts `udp_reporter'
+ {ok, Reporter} = jaeger_passage_reporter:start(udp_reporter),
+ [udp_reporter] = jaeger_passage_reporter:which_reporters(),
%% Registers `test_tracer'
Context = jaeger_passage_span_context,
Sampler = passage_sampler_all:new(),
- ok = passage_tracer_registry:register(test_tracer, Context, Sampler, Reporter),
+ ok = passage_tracer_registry:register(udp_tracer, Context, Sampler, Reporter),
%% Starts and finishes spans
- passage_pd:start_span(test_root, [{tracer, test_tracer}]),
+ passage_pd:start_span(test_root, [{tracer, udp_tracer}]),
passage_pd:start_span(test_child),
passage_pd:log(#{message => "Hello World"}),
passage_pd:finish_span(),
passage_pd:finish_span(),
timer:sleep(50),
- ok = jaeger_passage_reporter:stop(test_reporter),
+ ok = jaeger_passage_reporter:stop(udp_reporter),
[] = jaeger_passage_reporter:which_reporters(),
ok = application:stop(jaeger_passage).
+
+basic_http_test() ->
+ {ok, _} = application:ensure_all_started(jaeger_passage),
+
+ %% Starts `http_reporter'
+ {ok, Reporter} = jaeger_passage_reporter:start(http_reporter, [
+ {protocol, http},
+ {http_client, fun http_client/5}
+ ]),
+ [http_reporter] = jaeger_passage_reporter:which_reporters(),
+
+ %% Registers `test_tracer'
+ Context = jaeger_passage_span_context,
+ Sampler = passage_sampler_all:new(),
+ ok = passage_tracer_registry:register(http_tracer, Context, Sampler, Reporter),
+
+ %% Starts and finishes spans
+ passage_pd:start_span(test_root, [{tracer, http_tracer}]),
+ passage_pd:start_span(test_child),
+ passage_pd:log(#{message => "Hello World"}),
+ passage_pd:finish_span(),
+ passage_pd:finish_span(),
+ timer:sleep(50),
+
+ ok = jaeger_passage_reporter:stop(http_reporter),
+ [] = jaeger_passage_reporter:which_reporters(),
+
+ ok = application:stop(jaeger_passage).
+
+error_http_test() ->
+ {ok, _} = application:ensure_all_started(jaeger_passage),
+
+ %% Starts `http_reporter'
+ ?assertMatch({error, {{badarg, _}, _}}, jaeger_passage_reporter:start(http_reporter, [
+ {protocol, http},
+ {http_client, undefined}
+ ])),
+
+ %% Starts `http_reporter'
+ ?assertError(badarg, jaeger_passage_reporter:start(http_reporter, [
+ {protocol, undefined}
+ ])).
+
+
+http_client(_URI, _Method, _Headers, _Encoded, _Options) ->
+ ok.
\ No newline at end of file