You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ii...@apache.org on 2020/01/23 14:39:17 UTC

[couchdb-jaeger-passage] 02/09: Add HTTP reporter

This is an automated email from the ASF dual-hosted git repository.

iilyak pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-jaeger-passage.git

commit c4edcbf558e939e3279dc88fc7beb528befa2be0
Author: ILYA Khlopotov <ii...@apache.org>
AuthorDate: Wed Jan 15 08:13:07 2020 -0800

    Add HTTP reporter
    
    The reporter can be configured using the following:
    
    ```
    % Define http client callback
    Client = fun(Url, Method, Headers, Body, ReporterOptions) ->
        ibrowse:send_req(Url, Headers, Method, Body, [])
    end.
    
    [
        {protocol, http},
        {endpoint, "http://127.0.0.1:14268"},
        {http_client, HttpClient}
    ]
    ```
---
 README.md                                          |  18 +++
 src/jaeger_passage.erl                             |   2 +-
 src/jaeger_passage_reporter.erl                    | 138 ++++----------------
 ...porter.erl => jaeger_passage_reporter_http.erl} | 142 ++++++---------------
 src/jaeger_passage_reporter_sup.erl                |   9 +-
 ...eporter.erl => jaeger_passage_reporter_udp.erl} |  79 +-----------
 src/jaeger_passage_thrift.erl                      |   8 +-
 7 files changed, 100 insertions(+), 296 deletions(-)

diff --git a/README.md b/README.md
index ddfd2a6..078eee6 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,23 @@ Browses the tracing result:
 $ 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 @@ References
 - [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/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 @@ start_link(ReporterId, Options) ->
 -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 @@ start(ReporterId, Options) ->
     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 @@ get_id(Reporter) ->
 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.erl b/src/jaeger_passage_reporter_http.erl
similarity index 53%
copy from src/jaeger_passage_reporter.erl
copy to src/jaeger_passage_reporter_http.erl
index 32f537e..095f3a1 100644
--- a/src/jaeger_passage_reporter.erl
+++ b/src/jaeger_passage_reporter_http.erl
@@ -1,12 +1,10 @@
-%% @copyright 2017 Takeru Ohta <ph...@gmail.com>
-%%
 %% @doc A reporter that sends the spans to an jaeger agent
 %%
 %% === Examples ===
 %%
 %% ```
 %% %% Starts `example_reporter'
-%% {ok, Reporter} = jaeger_passage_reporter:start(example_reporter).
+%% {ok, Reporter} = jaeger_passage_reporter:start(example_reporter, [{protocol, http}]).
 %% [example_reporter] = jaeger_passage_reporter:which_reporters().
 %%
 %% %% Registers `example_tracer'
@@ -26,9 +24,8 @@
 %% <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).
+-module(jaeger_passage_reporter_http).
 
--behaviour(passage_reporter).
 -behaviour(gen_server).
 
 -include("constants.hrl").
@@ -36,12 +33,6 @@
 %%------------------------------------------------------------------------------
 %% Exported API
 %%------------------------------------------------------------------------------
--export([start/1, start/2]).
--export([stop/1]).
--export([which_reporters/0]).
--export([get_id/1]).
-
--export_type([reporter_id/0]).
 -export_type([start_option/0, start_options/0]).
 
 %%------------------------------------------------------------------------------
@@ -50,11 +41,6 @@
 -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]).
@@ -66,112 +52,69 @@
 
 -record(?STATE,
         {
-          socket               :: gen_udp:socket(),
-          thrift_format        :: thrift_protocol:format(),
-          agent_host           :: inet:hostname(),
-          agent_port           :: inet:port_number(),
+          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 reporter_id() :: atom().
-%% Reporter identifier.
 
 -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() :: {endpoint, string()}
+                      | {http_client, http_client()}
                       | {default_service_name, atom()}
                       | {process_tags, passage:tags()}.
 %% <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>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.</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(reporter_id(), start_options()) -> {ok, pid()} | {error, Reason} when
+-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}, []).
 
 %%------------------------------------------------------------------------------
-%% Exported Functions
-%%------------------------------------------------------------------------------
-%% @equiv start(ReporterId, [])
--spec start(reporter_id()) -> {ok, passage_reporter:reporter()} | {error, Reason} when
-      Reason :: {already_started, pid()} | term().
-start(ReporterId) ->
-    start(ReporterId, []).
-
-%% @doc Starts a reporter process.
--spec start(reporter_id(), start_options()) -> {ok, Reporter} | {error, Reason} when
-      Reporter :: passage_reporter:reporter(),
-      Reason :: {already_started, pid()} | term().
-start(ReporterId, Options) ->
-    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
-        {error, Reason} -> {error, Reason};
-        {ok, _Pid}      -> {ok, passage_reporter:new(?MODULE, ReporterId)}
-    end.
-
-%% @doc Stops the reporter process.
-%%
-%% If the reporter which has the identifier `ReporterId' has not been started,
-%% it will be simply ignored.
--spec stop(reporter_id()) -> ok.
-stop(ReporterId) ->
-    jaeger_passage_reporter_sup:stop_child(ReporterId).
-
-%% @doc Returns the list of the running reporters.
--spec which_reporters() -> [reporter_id()].
-which_reporters() ->
-    jaeger_passage_reporter_sup:which_children().
-
-%% @doc Returns the identifier of `Reporter'.
-%%
-%% Note that if `Reporter' is one which has not been created by {@link start/2},
-%% this function will crash.
--spec get_id(passage_reporter:reporter()) -> reporter_id().
-get_id(Reporter) ->
-    ?MODULE = passage_reporter:get_module(Reporter),
-    passage_reporter:get_state(Reporter).
-
-%%------------------------------------------------------------------------------
-%% 'passage_reporter' Callback Functions
-%%------------------------------------------------------------------------------
-%% @private
-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),
+    Endpoint = proplists:get_value(endpoint, Options, "http://127.0.0.1:14268"),
+    EndpointURL = Endpoint ++ "/api/traces",
+
+    HttpClient = proplists:get_value(http_client, Options),
+    HttpClient =/= undefined orelse error(badarg, [ReporterId, Options]),
+
     DefaultServiceName = proplists:get_value(default_service_name, Options, ReporterId),
     Tags0 = proplists:get_value(process_tags, Options, #{}),
 
@@ -185,15 +128,13 @@ init({ReporterId, Options}) ->
             ?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,
+            endpoint              = EndpointURL,
+            http_client           = HttpClient,
+            options               = Options,
             default_service_name  = DefaultServiceName,
-            process_tags  = Tags1
+            process_tags          = Tags1
            },
     {ok, State}.
 
@@ -223,9 +164,10 @@ code_change(_OldVsn, State, _Extra) ->
 %% Internal Functions
 %%------------------------------------------------------------------------------
 -spec handle_report(passage_span:span(), #?STATE{}) -> {noreply, #?STATE{}}.
-handle_report(Span, State = #?STATE{default_service_name = DefaultName, process_tags = Tags}) ->
+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_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),
+    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}.
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.erl b/src/jaeger_passage_reporter_udp.erl
similarity index 68%
copy from src/jaeger_passage_reporter.erl
copy to src/jaeger_passage_reporter_udp.erl
index 32f537e..485c258 100644
--- a/src/jaeger_passage_reporter.erl
+++ b/src/jaeger_passage_reporter_udp.erl
@@ -1,12 +1,10 @@
-%% @copyright 2017 Takeru Ohta <ph...@gmail.com>
-%%
 %% @doc A reporter that sends the spans to an jaeger agent
 %%
 %% === Examples ===
 %%
 %% ```
 %% %% Starts `example_reporter'
-%% {ok, Reporter} = jaeger_passage_reporter:start(example_reporter).
+%% {ok, Reporter} = jaeger_passage_reporter:start(example_reporter, [{protocol, udp}]).
 %% [example_reporter] = jaeger_passage_reporter:which_reporters().
 %%
 %% %% Registers `example_tracer'
@@ -26,9 +24,8 @@
 %% <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).
+-module(jaeger_passage_reporter_udp).
 
--behaviour(passage_reporter).
 -behaviour(gen_server).
 
 -include("constants.hrl").
@@ -36,12 +33,6 @@
 %%------------------------------------------------------------------------------
 %% Exported API
 %%------------------------------------------------------------------------------
--export([start/1, start/2]).
--export([stop/1]).
--export([which_reporters/0]).
--export([get_id/1]).
-
--export_type([reporter_id/0]).
 -export_type([start_option/0, start_options/0]).
 
 %%------------------------------------------------------------------------------
@@ -50,11 +41,6 @@
 -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]).
@@ -77,17 +63,13 @@
 %%------------------------------------------------------------------------------
 %% Exported Types
 %%------------------------------------------------------------------------------
--type reporter_id() :: atom().
-%% Reporter identifier.
 
 -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()}
-                      | {default_service_name, atom()}
-                      | {process_tags, passage:tags()}.
+                      | {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>
@@ -100,66 +82,13 @@
 %% Application Internal Functions
 %%------------------------------------------------------------------------------
 %% @private
--spec start_link(reporter_id(), start_options()) -> {ok, pid()} | {error, Reason} when
+-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}, []).
 
 %%------------------------------------------------------------------------------
-%% Exported Functions
-%%------------------------------------------------------------------------------
-%% @equiv start(ReporterId, [])
--spec start(reporter_id()) -> {ok, passage_reporter:reporter()} | {error, Reason} when
-      Reason :: {already_started, pid()} | term().
-start(ReporterId) ->
-    start(ReporterId, []).
-
-%% @doc Starts a reporter process.
--spec start(reporter_id(), start_options()) -> {ok, Reporter} | {error, Reason} when
-      Reporter :: passage_reporter:reporter(),
-      Reason :: {already_started, pid()} | term().
-start(ReporterId, Options) ->
-    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
-        {error, Reason} -> {error, Reason};
-        {ok, _Pid}      -> {ok, passage_reporter:new(?MODULE, ReporterId)}
-    end.
-
-%% @doc Stops the reporter process.
-%%
-%% If the reporter which has the identifier `ReporterId' has not been started,
-%% it will be simply ignored.
--spec stop(reporter_id()) -> ok.
-stop(ReporterId) ->
-    jaeger_passage_reporter_sup:stop_child(ReporterId).
-
-%% @doc Returns the list of the running reporters.
--spec which_reporters() -> [reporter_id()].
-which_reporters() ->
-    jaeger_passage_reporter_sup:which_children().
-
-%% @doc Returns the identifier of `Reporter'.
-%%
-%% Note that if `Reporter' is one which has not been created by {@link start/2},
-%% this function will crash.
--spec get_id(passage_reporter:reporter()) -> reporter_id().
-get_id(Reporter) ->
-    ?MODULE = passage_reporter:get_module(Reporter),
-    passage_reporter:get_state(Reporter).
-
-%%------------------------------------------------------------------------------
-%% 'passage_reporter' Callback Functions
-%%------------------------------------------------------------------------------
-%% @private
-report(ReporterId, Span) ->
-    Server = jaeger_passage_local_ns:reporter_name(ReporterId),
-    gen_server:cast(Server, {report, Span}).
-
-%%------------------------------------------------------------------------------
 %% 'gen_server' Callback Functions
 %%------------------------------------------------------------------------------
 %% @private
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 @@ make_emit_batch_message(ServiceName, ServiceTags, Spans) ->
        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
 %%------------------------------------------------------------------------------