Add documentation
diff --git a/doc/overview.edoc b/doc/overview.edoc
new file mode 100644
index 0000000..e486117
--- /dev/null
+++ b/doc/overview.edoc
@@ -0,0 +1,42 @@
+@copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+
+@doc Jaeger client library for Erlang
+
+This is an extention of <a href="https://github.com/sile/passage">passage</a>(An OpenTracing library).
+
+=== Examples ===
+
+```
+// Starts Jaeger in the background
+$ docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 jaegertracing/all-in-one:latest
+
+// Starts Erlang Shell
+$ rebar3 shell
+> Context = jaeger_passage_span_context.
+> Sampler = passage_sampler_all:new().
+> {ok, Reporter} = jaeger_passage_reporter:start(example_repoter).
+> ok = passage_tracer_registry:register(example_tracer, Context, Sampler, Reporter).
+
+%% Starts a root span.
+> RootSpan = passage:start_root_span(example_root, example_tracer).
+
+%% Starts a child span.
+> ChildSpan = passage:start_span(example_child, {child_of, RootSpan}).
+
+%% Finishes the spans
+> passage:finish_span(ChildSpan).
+> passage:finish_span(RootSpan).
+
+> q().
+
+// Browses the tracing result
+$ firefox localhost:16686
+'''
+
+=== References ===
+
+<ul>
+  <li><a href="http://opentracing.io/">OpenTracing</a></li>
+  <li><a href="https://uber.github.io/jaeger/">Jaeger</a></li>
+  <li><a href="https://github.com/jaegertracing/jaeger-client-go/blob/v2.9.0/README.md">jaeger-client-go/README.md</a></li>
+</ul>
diff --git a/src/jaeger_passage_app.erl b/src/jaeger_passage_app.erl
index 0e9b763..a07ce4a 100644
--- a/src/jaeger_passage_app.erl
+++ b/src/jaeger_passage_app.erl
@@ -1,9 +1,18 @@
+%% @copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+%%
+%% @private
 -module(jaeger_passage_app).
 
 -behaviour(application).
 
+%%------------------------------------------------------------------------------
+%% 'application' Callback API
+%%------------------------------------------------------------------------------
 -export([start/2, stop/1]).
 
+%%------------------------------------------------------------------------------
+%% 'application' Callback Functions
+%%------------------------------------------------------------------------------
 start(_StartType, _StartArgs) ->
     jaeger_passage_sup:start_link().
 
diff --git a/src/jaeger_passage_local_ns.erl b/src/jaeger_passage_local_ns.erl
index 22d4b62..48cd22f 100644
--- a/src/jaeger_passage_local_ns.erl
+++ b/src/jaeger_passage_local_ns.erl
@@ -1,8 +1,19 @@
+%% @copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+%%
+%% @doc Application Local Name Server
+%%
+%% @private
 -module(jaeger_passage_local_ns).
 
+%%------------------------------------------------------------------------------
+%% Application Internal API
+%%------------------------------------------------------------------------------
 -export([child_spec/0]).
 -export([reporter_name/1]).
 
+%%------------------------------------------------------------------------------
+%% Application Internal Functions
+%%------------------------------------------------------------------------------
 -spec child_spec() -> supervisor:child_spec().
 child_spec() ->
     local:name_server_child_spec(?MODULE).
diff --git a/src/jaeger_passage_reporter.erl b/src/jaeger_passage_reporter.erl
index 8019937..adf97e1 100644
--- a/src/jaeger_passage_reporter.erl
+++ b/src/jaeger_passage_reporter.erl
@@ -1,3 +1,31 @@
+%% @copyright 2017 Takeru Ohta <phjgt308@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).
+%% [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_root_span(example, 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).
 
 -behaviour(passage_reporter).
@@ -49,18 +77,28 @@
 %% 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()}
                       | {service_name, atom()}
                       | {service_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>service_name</b>: The name of the service which reports the spans. The default value is `ReporterId'.</li>
+%%   <li><b>service_tags</b>: The tags of the service. 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) ->
@@ -76,18 +114,29 @@
 start(ReporterId) ->
     start(ReporterId, []).
 
--spec start(reporter_id(), start_options()) -> {ok, passage_reporter:reporter()} | {error, Reason} when
+%% @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().
diff --git a/src/jaeger_passage_reporter_sup.erl b/src/jaeger_passage_reporter_sup.erl
index f60fdb7..529fde3 100644
--- a/src/jaeger_passage_reporter_sup.erl
+++ b/src/jaeger_passage_reporter_sup.erl
@@ -1,21 +1,33 @@
+%% @copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+%%
+%% @private
 -module(jaeger_passage_reporter_sup).
 
 -behaviour(supervisor).
 
+%%------------------------------------------------------------------------------
+%% Application Internal API
+%%------------------------------------------------------------------------------
 -export([start_link/0]).
 -export([start_child/2]).
 -export([stop_child/1]).
 -export([which_children/0]).
 
+%%------------------------------------------------------------------------------
+%% 'supervisor' Callback API
+%%------------------------------------------------------------------------------
 -export([init/1]).
 
--define(SERVER, ?MODULE).
-
+%%------------------------------------------------------------------------------
+%% Application Internal Functions
+%%------------------------------------------------------------------------------
+-spec start_link() -> {ok, pid()} | {error, Reason :: term()}.
 start_link() ->
-    supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
 
--spec start_child(jaeger_passage_reporter:reporter_id(), jaeger_passage_reporter:start_options()) ->
-                         {ok, pid()} | {error, Reason} when
+-spec start_child(ReporterId, Options) -> {ok, pid()} | {error, Reason} when
+      ReporterId :: jaeger_passage_reporter:reporter_id(),
+      Options :: jaeger_passage_reporter:start_options(),
       Reason :: {already_started, pid()} | term().
 start_child(ReporterId, Options) ->
     Child = #{
@@ -35,5 +47,8 @@
 which_children() ->
     [Id || {Id, _, _, _} <- supervisor:which_children(?MODULE)].
 
+%%------------------------------------------------------------------------------
+%% 'supervisor' Callback Functions
+%%------------------------------------------------------------------------------
 init([]) ->
     {ok, {#{}, []}}.
diff --git a/src/jaeger_passage_span_context.erl b/src/jaeger_passage_span_context.erl
index ec84381..0835f77 100644
--- a/src/jaeger_passage_span_context.erl
+++ b/src/jaeger_passage_span_context.erl
@@ -1,3 +1,15 @@
+%% @copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+%%
+%% @doc Span context for Jaeger
+%%
+%% === References ===
+%%
+%% <ul>
+%% <li><a href="https://github.com/jaegertracing/jaeger-client-go/blob/v2.9.0/README.md">jaeger-client-go/README.md</a></li>
+%% <li><a href="https://github.com/uber/jaeger-client-go/tree/v2.9.0/context.go">context.go</a></li>
+%% <li><a href="https://github.com/uber/jaeger-client-go/tree/v2.9.0/propagation.go">propagation.go</a></li>
+%% </ul>
+
 -module(jaeger_passage_span_context).
 
 -behaviour(passage_span_context).
@@ -7,15 +19,16 @@
 %%------------------------------------------------------------------------------
 %% Exported API
 %%------------------------------------------------------------------------------
+-export_type([state/0]).
+
+%%------------------------------------------------------------------------------
+%% Application Internal API
+%%------------------------------------------------------------------------------
 -export([get_trace_id/1]).
 -export([get_span_id/1]).
 -export([get_debug_id/1]).
 -export([get_flags/1]).
 
--export_type([state/0]).
--export_type([trace_id/0]).
--export_type([span_id/0]).
-
 %%------------------------------------------------------------------------------
 %% 'passage_span_context' Callback API
 %%------------------------------------------------------------------------------
@@ -41,22 +54,39 @@
 %% Exported Types
 %%------------------------------------------------------------------------------
 -opaque state() :: #?STATE{}.
-
--type trace_id() :: 0..16#FFFFFFFFFFFFFFFF.
-
--type span_id() :: 0..16#FFFFFFFF.
+%% The state of a jaeger span context.
 
 %%------------------------------------------------------------------------------
-%% Exported Functions
+%% Types
 %%------------------------------------------------------------------------------
+-type trace_id() :: 0..16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
+%% Tracer identifier (128-bit unsigned integer).
+%%
+%% This represents globally unique ID of the trace.
+%% Usually generated as a random number.
+
+-type span_id() :: 0..16#FFFFFFFFFFFFFFFF.
+%% Span identifier (64-bit unsigned integer).
+%%
+%% This represents span ID that must be unique within its trace,
+%% but does not have to be globally unique.
+%%
+%% Note that the ID `0' is used for representing invalid spans.
+
+%%------------------------------------------------------------------------------
+%% Application Internal Functions
+%%------------------------------------------------------------------------------
+%% @private
 -spec get_trace_id(passage_span_context:context()) -> trace_id().
 get_trace_id(Context) ->
     (passage_span_context:get_state(Context))#?STATE.trace_id.
 
+%% @private
 -spec get_span_id(passage_span_context:context()) -> span_id().
 get_span_id(Context) ->
     (passage_span_context:get_state(Context))#?STATE.span_id.
 
+%% @private
 -spec get_debug_id(passage_span_context:context()) -> {ok, binary()} | eror.
 get_debug_id(Context) ->
     State = passage_span_context:get_state(Context),
@@ -65,6 +95,7 @@
         DebugId   -> {ok, DebugId}
     end.
 
+%% @private
 -spec get_flags(passage_span_context:context()) -> 0..16#FFFFFFFF.
 get_flags(Context) ->
     State = passage_span_context:get_state(Context),
@@ -76,15 +107,15 @@
 %% @private
 make_span_context_state([]) ->
     #?STATE{
-        trace_id   = rand:uniform(16#FFFFFFFFFFFFFFFF),
-        span_id    = rand:uniform(16#FFFFFFFF),
+        trace_id   = rand:uniform(16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF),
+        span_id    = rand:uniform(16#FFFFFFFFFFFFFFFF),
         is_sampled = true
        };
 make_span_context_state([{_, Ref} | _]) ->
     #?STATE{trace_id = TraceId} = passage_span_context:get_state(passage_span:get_context(Ref)),
     #?STATE{
         trace_id   = TraceId,
-        span_id    = rand:uniform(16#FFFFFFFF),
+        span_id    = rand:uniform(16#FFFFFFFFFFFFFFFF),
         is_sampled = true
        }.
 
diff --git a/src/jaeger_passage_sup.erl b/src/jaeger_passage_sup.erl
index 9d51cf1..bbcf339 100644
--- a/src/jaeger_passage_sup.erl
+++ b/src/jaeger_passage_sup.erl
@@ -1,16 +1,30 @@
+%% @copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+%%
+%% @private
 -module(jaeger_passage_sup).
 
 -behaviour(supervisor).
 
+%%------------------------------------------------------------------------------
+%% Application Internal API
+%%------------------------------------------------------------------------------
 -export([start_link/0]).
 
+%%------------------------------------------------------------------------------
+%% 'supervisor' Callback API
+%%------------------------------------------------------------------------------
 -export([init/1]).
 
--define(SERVER, ?MODULE).
-
+%%------------------------------------------------------------------------------
+%% Application Internal Functions
+%%-------------------------------------------------------------------------------
+-spec start_link() -> {ok, pid()} | {error, Reason :: term()}.
 start_link() ->
-    supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
 
+%%------------------------------------------------------------------------------
+%% 'supervisor' Callback Functions
+%%------------------------------------------------------------------------------
 init([]) ->
     NameServer = jaeger_passage_local_ns:child_spec(),
     ReporterSup = #{
diff --git a/src/jaeger_passage_thrift.erl b/src/jaeger_passage_thrift.erl
index 04d53cb..ad71b6c 100644
--- a/src/jaeger_passage_thrift.erl
+++ b/src/jaeger_passage_thrift.erl
@@ -1,12 +1,19 @@
-%% https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/agent.thrift
-%% https://github.com/jaegertracing/jaeger-idl/blob/master/thrift/jaeger.thrift
+%% @copyright 2017 Takeru Ohta <phjgt308@gmail.com>
+%%
+%% @doc Thrift messages for jaeger
+%%
+%% IDL:
+%% - https://github.com/jaegertracing/jaeger-idl/blob/84a83104/thrift/agent.thrift
+%% - https://github.com/jaegertracing/jaeger-idl/blob/84a83104/thrift/jaeger.thrift
+%%
+%% @private
 -module(jaeger_passage_thrift).
 
 -include_lib("thrift_protocol/include/thrift_protocol.hrl").
 -include("constants.hrl").
 
 %%------------------------------------------------------------------------------
-%% Exported API
+%% Application Internal API
 %%------------------------------------------------------------------------------
 -export([make_emit_batch_message/3]).
 
@@ -22,25 +29,24 @@
 -define(REF_TYPE_CHILD_OF, 0).
 -define(REF_TYPE_FOLLOWS_FROM, 1).
 
+-define(STRUCT(F1), #thrift_protocol_struct{fields = #{1 => F1}}).
+-define(STRUCT(F1, F2), #thrift_protocol_struct{fields = #{1 => F1, 2 => F2}}).
+
+-define(LIST(Es), #thrift_protocol_list{element_type = struct, elements = Es}).
+
 %%------------------------------------------------------------------------------
-%% Exported Functions
+%% Application Internal API
 %%------------------------------------------------------------------------------
 -spec make_emit_batch_message(atom(), passage:tags(), [passage_span:span()]) ->
                                      thrift_protocol:message().
 make_emit_batch_message(ServiceName, ServiceTags, Spans) ->
     Process = make_process(ServiceName, ServiceTags),
-    Batch =
-        #thrift_protocol_struct{
-           fields = #{
-             1 => Process,
-             2 => make_spans(Spans)
-            }
-          },
+    Batch = ?STRUCT(Process, make_spans(Spans)),
     #thrift_protocol_message{
-       method_name = <<"emitBatch">>,
+       method_name  = <<"emitBatch">>,
        message_type = oneway,
-       sequence_id = 0,
-       body = #thrift_protocol_struct{fields = #{ 1 => Batch }}
+       sequence_id  = 0,
+       body         = ?STRUCT(Batch)
       }.
 
 %%------------------------------------------------------------------------------
@@ -48,20 +54,12 @@
 %%------------------------------------------------------------------------------
 -spec make_process(atom(), passage:tags()) -> thrift_protocol:struct().
 make_process(ServiceName, ServiceTags) ->
-    #thrift_protocol_struct{
-       fields = #{
-         1 => atom_to_binary(ServiceName, utf8),
-         2 => make_tags(ServiceTags)
-        }
-      }.
+    ?STRUCT(atom_to_binary(ServiceName, utf8), make_tags(ServiceTags)).
 
 -spec make_tags(Tags) -> thrift_protocol:thrift_list() when
       Tags :: #{atom() => term()}.
 make_tags(Tags) ->
-    #thrift_protocol_list{
-       element_type = struct,
-       elements = maps:fold(fun (K, V, Acc) -> [make_tag(K, V) | Acc] end, [], Tags)
-      }.
+    ?LIST(maps:fold(fun (K, V, Acc) -> [make_tag(K, V) | Acc] end, [], Tags)).
 
 -spec make_tag(passage:tag_name(), passage:tag_value()) -> thrift_protocol:struct().
 make_tag(Key, Value) ->
@@ -74,12 +72,15 @@
         }
       }.
 
--spec make_tag_value(term()) -> {non_neg_integer(), thrift_protocol:field_id(), thrift_protocol:data()}.
-make_tag_value(X) when is_boolean(X) -> {?TAG_TYPE_BOOL, 5, X};
-make_tag_value(X) when is_atom(X) -> {?TAG_TYPE_STRING, 3, atom_to_binary(X, utf8)};
-make_tag_value(X) when is_binary(X) -> {?TAG_TYPE_STRING, 3, X};
-make_tag_value(X) when is_float(X) -> {?TAG_TYPE_DOUBLE, 4, X};
-make_tag_value(X) when is_integer(X) -> {?TAG_TYPE_LONG, 6, {i64, X}};
+-spec make_tag_value(term()) -> {ValueType, FieldId, Value} when
+      ValueType :: non_neg_integer(),
+      FieldId   :: thrift_protocol:field_id(),
+      Value     :: thrift_protocol:data().
+make_tag_value(X) when is_boolean(X) -> {?TAG_TYPE_BOOL,   5, X};
+make_tag_value(X) when is_atom(X)    -> {?TAG_TYPE_STRING, 3, atom_to_binary(X, utf8)};
+make_tag_value(X) when is_binary(X)  -> {?TAG_TYPE_STRING, 3, X};
+make_tag_value(X) when is_float(X)   -> {?TAG_TYPE_DOUBLE, 4, X};
+make_tag_value(X) when is_integer(X) -> {?TAG_TYPE_LONG,   6, {i64, X}};
 make_tag_value(X) ->
     try list_to_binary(X) of
         Binary -> {?TAG_TYPE_STRING, 3, Binary}
@@ -91,19 +92,18 @@
 
 -spec make_spans([passage_span:span()]) -> thrift_protocol:thrift_list().
 make_spans(Spans) ->
-    #thrift_protocol_list{
-       element_type = struct,
-       elements = lists:map(fun make_span/1, Spans)
-      }.
+    ?LIST(lists:map(fun make_span/1, Spans)).
 
 -spec make_span(passage_span:span()) -> thrift_protocol:struct().
 make_span(Span) ->
     Context = passage_span:get_context(Span),
     TraceId = jaeger_passage_span_context:get_trace_id(Context),
     ParentSpanId =
-        case lists:filter(fun ({Type, _}) -> Type =:= child_of end, passage_span:get_refs(Span)) of
-            []             -> 0;
-            [{_, Ref} | _] -> jaeger_passage_span_context:get_span_id(passage_span:get_context(Ref))
+        case [Ref || {child_of, Ref} <- passage_span:get_refs(Span)] of
+            []        -> 0;
+            [Ref | _] ->
+                RefContext = passage_span:get_context(Ref),
+                jaeger_passage_span_context:get_span_id(RefContext)
         end,
     Tags0 = passage_span:get_tags(Span),
     Tags1 =
@@ -113,8 +113,8 @@
         end,
     #thrift_protocol_struct{
        fields = #{
-         1 => {i64, TraceId band 16#FFFFFFFF},
-         2 => {i64, TraceId bsr 32},
+         1 => {i64, TraceId band 16#FFFFFFFFFFFFFFFF},
+         2 => {i64, TraceId bsr 64},
          3 => {i64, jaeger_passage_span_context:get_span_id(Context)},
          4 => {i64, ParentSpanId},
          5 => atom_to_binary(passage_span:get_operation_name(Span), utf8),
@@ -127,30 +127,19 @@
         }
       }.
 
--spec timestamp_to_us(erlang:timestamp()) -> non_neg_integer().
-timestamp_to_us(Timestamp) ->
-    timer:now_diff(Timestamp, {0, 0, 0}).
-
--spec get_duration_us(passage_span:span()) -> non_neg_integer().
-get_duration_us(Span) ->
-    Start = passage_span:get_start_time(Span),
-    {ok, Finish} = passage_span:get_finish_time(Span),
-    timer:now_diff(Finish, Start).
-
 -spec make_references(passage_span:normalized_refs()) -> thrift_protocol:thrift_list().
 make_references(Refs) ->
-    #thrift_protocol_list{
-       element_type = struct,
-       elements =
-           lists:map(
-             fun make_reference/1,
-             lists:filter(
-               fun ({_, Span}) ->
-                       Context = passage_span:get_context(Span),
-                       jaeger_passage_span_context:get_trace_id(Context) =/= 0
-               end,
-               Refs))
-      }.
+    Elements =
+        lists:filtermap(
+          fun (Ref = {_, Span}) ->
+                  Context = passage_span:get_context(Span),
+                  case jaeger_passage_span_context:get_span_id(Context) of
+                      0 -> false;
+                      _ -> {true, make_reference(Ref)}
+                  end
+          end,
+          Refs),
+    ?LIST(Elements).
 
 -spec make_reference(passage_span:normalized_ref()) -> thrift_protocol:struct().
 make_reference(Ref) ->
@@ -165,24 +154,26 @@
     #thrift_protocol_struct{
        fields = #{
          1 => {i32, RefType},
-         2 => {i64, TraceId band 16#FFFFFFFF},
-         3 => {i64, TraceId bsr 32},
+         2 => {i64, TraceId band 16#FFFFFFFFFFFFFFFF},
+         3 => {i64, TraceId bsr 64},
          4 => {i64, SpanId}
         }
       }.
 
 -spec make_logs([passage_span:log()]) -> thrift_protocol:thrift_list().
 make_logs(Logs) ->
-    #thrift_protocol_list{
-       element_type = struct,
-       elements = lists:map(fun make_log/1, Logs)
-      }.
+    ?LIST(lists:map(fun make_log/1, Logs)).
 
 -spec make_log(passage_span:log()) -> thrift_protocol:struct().
 make_log({Fields, Time}) ->
-    #thrift_protocol_struct{
-       fields = #{
-         1 => {i64, timestamp_to_us(Time)},
-         2 => make_tags(Fields)
-        }
-      }.
+    ?STRUCT({i64, timestamp_to_us(Time)}, make_tags(Fields)).
+
+-spec timestamp_to_us(erlang:timestamp()) -> non_neg_integer().
+timestamp_to_us(Timestamp) ->
+    timer:now_diff(Timestamp, {0, 0, 0}).
+
+-spec get_duration_us(passage_span:span()) -> non_neg_integer().
+get_duration_us(Span) ->
+    Start = passage_span:get_start_time(Span),
+    {ok, Finish} = passage_span:get_finish_time(Span),
+    timer:now_diff(Finish, Start).