Merge `start_root_span` into `start_span`
diff --git a/README.md b/README.md
index feed3d2..d165a25 100644
--- a/README.md
+++ b/README.md
@@ -21,10 +21,10 @@
 ok = passage_tracer_registry:register(tracer, Context, Sampler, Reporter),
 
 %% Starts a root span
-RootSpan = passage:start_root_span(example_root, tracer),
+RootSpan = passage:start_span(example_root, [{tracer, tracer}]),
 
 %% Starts a child span
-ChildSpan = passage:start_span(example_child, {child_of, RootSpan}),
+ChildSpan = passage:start_span(example_child, [{child_of, RootSpan}]),
 
 %% Finishes spans
 passage:finish_span(ChildSpan),
@@ -45,7 +45,7 @@
 ok = passage_tracer_registry:register(tracer, Context, Sampler, Reporter),
 
 %% Starts a root span
-ok = passage_pd:start_root_span(example_root, tracer),
+ok = passage_pd:start_span(example_root, [{tracer, tracer}]),
 
 %% Starts a child span
 ok = passage_pd:start_span(example_child),
diff --git a/src/passage.erl b/src/passage.erl
index bcf3926..f7dde8b 100644
--- a/src/passage.erl
+++ b/src/passage.erl
@@ -15,10 +15,10 @@
 %% ok = passage_tracer_registry:register(tracer, Context, Sampler, Reporter),
 %%
 %% %% Starts a root span
-%% RootSpan = passage:start_root_span(example_root, tracer),
+%% RootSpan = passage:start_span(example_root, [{tracer, tracer}]),
 %%
 %% %% Starts a child span
-%% ChildSpan = passage:start_span(example_child, {child_of, RootSpan}),
+%% ChildSpan = passage:start_span(example_child, [{child_of, RootSpan}]),
 %%
 %% %% Finishes spans
 %% passage:finish_span(ChildSpan),
@@ -35,8 +35,7 @@
 %%------------------------------------------------------------------------------
 %% Exported API
 %%------------------------------------------------------------------------------
--export([start_root_span/2, start_root_span/3]).
--export([start_span/2, start_span/3]).
+-export([start_span/1, start_span/2]).
 -export([finish_span/1, finish_span/2]).
 -export([set_operation_name/2]).
 -export([set_tags/2]).
@@ -48,7 +47,6 @@
 -export_type([tracer_id/0]).
 -export_type([maybe_span/0]).
 -export_type([operation_name/0]).
--export_type([start_root_span_option/0, start_root_span_options/0]).
 -export_type([start_span_option/0, start_span_options/0]).
 -export_type([finish_span_option/0, finish_span_options/0]).
 -export_type([tags/0, tag_name/0, tag_value/0]).
@@ -74,9 +72,12 @@
 -type refs() :: [ref()].
 %% Span references.
 
--type ref() :: {ref_type(), maybe_span()}.
+-type ref() :: {ref_type(), passage_span:span()}.
 %% Span reference.
 %%
+%% Note that the values of tags, references and logs of a reference are set to empty
+%% when the associated span is created.
+%%
 %% See also: <a href="https://github.com/opentracing/specification/blob/1.1/specification.md#references-between-spans">References between Spans (The OpenTracing Semantic Specification)</a>
 
 -type ref_type() :: child_of | follows_from.
@@ -115,23 +116,18 @@
 -type log_field_value() :: term().
 %% Log field value.
 
--type start_root_span_options() :: [start_root_span_option()].
-%% Options for {@link start_root_span/3}.
-
--type start_root_span_option() :: {time, erlang:timestamp()}
-                                | {tags, tags()}.
-%% <ul>
-%%  <li><b>time</b>: Start timestamp of the span. The default value is `erlang:timestamp()'.</li>
-%%  <li><b>tags</b>: Tags associated to the span. The default value is `#{}'.</li>
-%% </ul>
-
 -type start_span_options() :: [start_span_option()].
-%% Options for {@link start_span/3}.
+%% Options for {@link start_span/2}.
 
--type start_span_option() :: {refs, refs()}
-                           | start_root_span_option().
+-type start_span_option() :: {tracer, tracer_id()}
+                           | {tags, tags()}
+                           | {ref_type(), maybe_span()}
+                           | {time, erlang:timestamp()}.
 %% <ul>
-%%   <li><b>refs</b>: Additional references related to the span. The default value is `[]'. </li>
+%%   <li><b>tracer</b>: The tracer used for tracing the span. If this option is omitted, the span will never be a root span. If the span has any valid references, this option will be ignored.</li>
+%%   <li><b>time</b>: Start timestamp of the span. The default value is `erlang:timestamp()'.</li>
+%%   <li><b>tags</b>: Tags associated to the span. The default value is `#{}'.</li>
+%%   <li><b>child_of|follows_from</b>: Specifies a references related to the span. This option can be presented more than once.</li>
 %% </ul>
 
 -type finish_span_options() :: [finish_span_option()].
@@ -159,37 +155,39 @@
 %%------------------------------------------------------------------------------
 %% Exported Functions
 %%------------------------------------------------------------------------------
-%% @equiv start_root_span(OperationName, Tracer, [])
--spec start_root_span(operation_name(), tracer_id()) -> maybe_span().
-start_root_span(OperationName, Tracer) ->
-    start_root_span(OperationName, Tracer, []).
-
-%% @doc Starts a root span.
-%%
-%% If the sampler associated with `Tracer' does not sample the span,
-%% this function will return `undefined'.
--spec start_root_span(operation_name(), tracer_id(), start_root_span_options()) ->
-                             maybe_span().
-start_root_span(OperationName, Tracer, Options) ->
-    passage_span:start_root(Tracer, OperationName, Options).
-
-%% @equiv start_span(OperationName, PrimaryReference, [])
--spec start_span(operation_name(), ref()) -> maybe_span().
-start_span(OperationName, PrimaryReference) ->
-    start_span(OperationName, PrimaryReference, []).
+%% @equiv start_span(OperationName, [])
+-spec start_span(operation_name()) -> maybe_span().
+start_span(OperationName) ->
+    start_span(OperationName, []).
 
 %% @doc Starts a span.
 %%
-%% If there is no sampled span references, this function will return `undefined'.
--spec start_span(operation_name(), ref(), start_span_options()) -> maybe_span().
-start_span(OperationName, PrimaryReference, Options) ->
-    {Refs1, Options2} =
-        case lists:keytake(refs, 1, Options) of
-            false                            -> {[], Options};
-            {value, {refs, Refs0}, Options1} -> {Refs0, Options1}
-        end,
-    Options3 = [{refs, [PrimaryReference | Refs1]} | Options2],
-    passage_span:start(OperationName, Options3).
+%% If any of the following conditions is matched,
+%% a valid span object (i.e., non `undefined') will be returned.
+%%
+%% <ul>
+%%   <li>1. There are any valid (i.e., non `undefined') span references.</li>
+%%   <li>2. The `sampling.priority' tag exists and the value is a positive integer.</li>
+%%   <li>3. A `tracer' is specified and its sampler has determined to sample next span.</li>
+%% </ul>
+%%
+%% If the first condition matches,
+%% the tracer associated with the first reference will be used for tracing the resulting span.
+-spec start_span(operation_name(), start_span_options()) -> maybe_span().
+start_span(OperationName, Options) ->
+    Result =
+        (fun Recur ([],                        Acc) -> Acc;
+             Recur ([{tracer, T}       | L], error) -> Recur(L, {ok, T});
+             Recur ([{_, undefined}    | L],   Acc) -> Recur(L, Acc);
+             Recur ([{child_of, _}     | _],     _) -> ignore;
+             Recur ([{follows_from, _} | _],     _) -> ignore;
+             Recur ([_                 | L],   Acc) -> Recur(L, Acc)
+         end)(Options, error),
+    case Result of
+        error        -> undefined;
+        ignore       -> passage_span:start(OperationName, Options);
+        {ok, Tracer} -> passage_span:start_root(Tracer, OperationName, Options)
+    end.
 
 %% @equiv finish_span(Span, [])
 -spec finish_span(maybe_span()) -> ok.
diff --git a/src/passage_pd.erl b/src/passage_pd.erl
index f3fe195..3d753fe 100644
--- a/src/passage_pd.erl
+++ b/src/passage_pd.erl
@@ -15,7 +15,7 @@
 %% ok = passage_tracer_registry:register(tracer, Context, Sampler, Reporter),
 %%
 %% %% Starts a root span
-%% ok = passage_pd:start_root_span(example_root, tracer),
+%% ok = passage_pd:start_span(example_root, [{tracer, tracer}]),
 %%
 %% %% Starts a child span
 %% ok = passage_pd:start_span(example_child),
@@ -33,10 +33,8 @@
 %%------------------------------------------------------------------------------
 %% Exported API
 %%------------------------------------------------------------------------------
--export([start_root_span/2, start_root_span/3]).
 -export([start_span/1, start_span/2]).
 -export([finish_span/0, finish_span/1]).
--export([with_root_span/3, with_root_span/4]).
 -export([with_span/2, with_span/3]).
 -export([current_span/0]).
 -export([set_operation_name/1]).
@@ -53,23 +51,6 @@
 %%------------------------------------------------------------------------------
 %% Exported Functions
 %%------------------------------------------------------------------------------
-%% @equiv start_root_span(OperationName, Tracer, [])
--spec start_root_span(passage:operation_name(), passage:tracer_id()) -> ok.
-start_root_span(OperationName, Tracer) ->
-    start_root_span(OperationName, Tracer, []).
-
-%% @doc Starts a root span.
-%%
-%% The started span will be pushed to the process dictionary of the calling process.
-%%
-%% If the sampler associated with `Tracer' does not sample the span,
-%% the value of span will be `undefined'.
--spec start_root_span(passage:operation_name(), passage:tracer_id(),
-                      passage:start_root_span_options()) -> ok.
-start_root_span(OperationName, Tracer, Options) ->
-    Span = passage:start_root_span(OperationName, Tracer, Options),
-    put_ancestors([Span | get_ancestors()]).
-
 %% @equiv start_span(OperationName, [])
 -spec start_span(passage:operation_name()) -> ok.
 start_span(OperationName) ->
@@ -86,11 +67,9 @@
     Options1 =
         case Ancestors of
             []           -> Options;
-            [Parent | _] ->
-                Refs = proplists:get_value(refs, Options, []),
-                [{refs, [{child_of, Parent} | Refs]} | Options]
+            [Parent | _] -> [{child_of, Parent} | Options]
         end,
-    Span = passage_span:start(OperationName, Options1),
+    Span = passage:start_span(OperationName, Options1),
     put_ancestors([Span | Ancestors]).
 
 %% @equiv finish_span([])
@@ -109,26 +88,6 @@
         Span      -> passage:finish_span(Span, Options)
     end.
 
-%% @equiv with_root_span(OperationName, Tracer, [], Fun)
--spec with_root_span(passage:operation_name(), passage:tracer_id(), Fun) -> Result when
-      Fun :: fun (() -> Result),
-      Result :: term().
-with_root_span(OperationName, Tracer, Fun) ->
-    with_root_span(OperationName, Tracer, [], Fun).
-
-%% @doc Starts a root span enclosing `Fun'.
--spec with_root_span(passage:operation_name(), passage:tracer_id(),
-                     passage:start_span_options(), Fun) -> Result when
-      Fun :: fun (() -> Result),
-      Result :: term().
-with_root_span(OperationName, Tracer, Options, Fun) ->
-    try
-        start_root_span(OperationName, Tracer, Options),
-        Fun()
-    after
-        finish_span()
-    end.
-
 %% @equiv with_span(OperationName, [], Fun)
 -spec with_span(passage:operation_name(), Fun) -> Result when
       Fun :: fun (() -> Result),
diff --git a/src/passage_span.erl b/src/passage_span.erl
index 48e40fa..3e899af 100644
--- a/src/passage_span.erl
+++ b/src/passage_span.erl
@@ -33,7 +33,7 @@
 %% ok = passage_tracer_registry:register(tracer, Context, Sampler, Reporter),
 %%
 %% %% Starts a span
-%% MaybeSpan = passage:start_root_span(example, tracer),
+%% MaybeSpan = passage:start_span(example, [{tracer, tracer}]),
 %% case MaybeSpan of
 %%     undefined -> ok;
 %%     Span      -> example = passage_span:get_operation_name(Span)
@@ -58,7 +58,6 @@
 -export([get_context/1]).
 
 -export_type([span/0]).
--export_type([normalized_refs/0, normalized_ref/0]).
 -export_type([log/0]).
 
 %%------------------------------------------------------------------------------
@@ -85,7 +84,7 @@
           operation_name          :: passage:operation_name(),
           start_time              :: erlang:timestamp(),
           finish_time = undefined :: erlang:timestamp() | undefined,
-          refs        = []        :: normalized_refs(),
+          refs        = []        :: passage:refs(),
           tags        = #{}       :: passage:tags(),
           logs        = []        :: [log()],
           context                 :: passage_span_context:context()
@@ -97,17 +96,6 @@
 -opaque span() :: #?SPAN{}.
 %% Span.
 
--type normalized_refs() :: [normalized_ref()].
-%% Normalized span references.
-%%
-%% Unlike `passage:refs/0', this cannot contain unsampled (i.e., `undefined') spans.
-
--type normalized_ref() :: {passage:ref_type(), span()}.
-%% Normalized span reference.
-%%
-%% Note that the values of tags, references and logs are set to empty
-%% when the span is created.
-
 -type log() :: {passage:log_fields(), erlang:timestamp()}.
 %% Timestamped span log fields.
 
@@ -125,7 +113,7 @@
     Span#?SPAN.tags.
 
 %% @doc Returns the references of `Span'.
--spec get_refs(span()) -> normalized_refs().
+-spec get_refs(span()) -> passage:refs().
 get_refs(Span) ->
     Span#?SPAN.refs.
 
@@ -169,7 +157,7 @@
 %% @private
 -spec start_root(passage:tracer_id(), passage:operation_name(), Options) ->
                         passage:maybe_span() when
-      Options :: passage:start_root_span_options().
+      Options :: passage:start_span_options().
 start_root(Tracer, OperationName, Options) ->
     Tags = proplists:get_value(tags, Options, #{}),
     case is_sampled(Tracer, OperationName, Tags) of
@@ -192,7 +180,7 @@
 %% @private
 -spec start(passage:operation_name(), passage:start_span_options()) -> passage:maybe_span().
 start(OperationName, Options) ->
-    Refs = normalize_refs(proplists:get_value(refs, Options, [])),
+    Refs = collect_valid_refs(Options),
     case Refs of
         []                 -> undefined;
         [{_, Primary} | _] ->
@@ -279,7 +267,7 @@
         {_, Time} -> Time
     end.
 
--spec make_span_context(passage:tracer_id(), passage_span:normalized_refs()) ->
+-spec make_span_context(passage:tracer_id(), passage:refs()) ->
                                {ok, passage_span_context:context()} | error.
 make_span_context(Tracer, Refs) ->
     case passage_tracer_registry:get_span_context_module(Tracer) of
@@ -287,12 +275,11 @@
         {ok, Module} -> {ok, passage_span_context:from_refs(Module, Refs)}
     end.
 
--spec normalize_refs([passage:maybe_span()]) -> normalized_refs().
-normalize_refs(Refs) ->
-    lists:filtermap(
-      fun ({_, undefined}) -> false;
-          ({Type, Span0})  ->
-              Span1 = Span0#?SPAN{refs = [], tags = #{}, logs = []},
-              {true, {Type, Span1}}
-      end,
-      Refs).
+-spec collect_valid_refs(passage:start_span_options()) -> passage:refs().
+collect_valid_refs(Options) ->
+    lists:filter(fun ({_, undefined})    -> false;
+                     ({child_of, _})     -> true;
+                     ({follows_from, _}) -> true;
+                     (_)                 -> false
+                 end,
+                 Options).
diff --git a/src/passage_span_context.erl b/src/passage_span_context.erl
index 432995e..bae566a 100644
--- a/src/passage_span_context.erl
+++ b/src/passage_span_context.erl
@@ -19,7 +19,7 @@
 %%
 %% ```
 %% %% @doc Creates the state of a span context from the given references.
-%% -callback make_span_context_state(passage_span:normalized_refs()) ->
+%% -callback make_span_context_state(passage:refs()) ->
 %%     state().
 %%
 %% %% @doc Injects the span context into the carrier by the specified format.
@@ -59,7 +59,7 @@
 %%------------------------------------------------------------------------------
 %% Callback API
 %%------------------------------------------------------------------------------
--callback make_span_context_state(passage_span:normalized_refs()) -> state().
+-callback make_span_context_state(passage:refs()) -> state().
 
 -callback inject_span_context(context(), format(), inject_fun(), carrier()) -> carrier().
 
@@ -147,7 +147,7 @@
 %% Application Internal Functions
 %%------------------------------------------------------------------------------
 %% @private
--spec from_refs(implementation_module(), passage_span:normalized_refs()) -> context().
+-spec from_refs(implementation_module(), passage:refs()) -> context().
 from_refs(Module, Refs) ->
     State = Module:make_span_context_state(Refs),
     BaggageItems =
diff --git a/src/passage_transform.erl b/src/passage_transform.erl
index f000098..bc1f3ea 100644
--- a/src/passage_transform.erl
+++ b/src/passage_transform.erl
@@ -49,19 +49,60 @@
 -export([parse_transform/2]).
 
 -export_type([passage_trace_option/0]).
+-export_type([expr_string/0]).
 
 %%------------------------------------------------------------------------------
 %% Exported Types
 %%------------------------------------------------------------------------------
 -type passage_trace_option() :: {tracer, passage:tracer_id()} |
                                 {tags, passage:tags()} |
-                                {eval_tags, #{passage:tag_name() => string()}} |
-                                {child_of, string()} |
-                                {follows_from, string()} |
-                                {error_if, string()} |
+                                {eval_tags, #{passage:tag_name() => expr_string()}} |
+                                {child_of, expr_string()} |
+                                {follows_from, expr_string()} |
+                                {error_if, expr_string()} |
                                 error_if_exception.
-%% TODO: doc
-%% TODO: warnings unknown options
+%% <ul>
+%% <li><b>tracer</b>: See {@link passage:start_span/2}</li>
+%% <li><b>tags</b>: See {@link passage:start_span/2}</li>
+%% <li><b>eval_tags</b>: This is the same as `tags' except the values are dynamically evaluated in the transforming phase.</li>
+%% <li><b>child_of</b>: See {@link passage:start_span/2}</li>
+%% <li><b>follows_from</b>: See {@link passage:start_span/2}</li>
+%% <li><b>error_if</b>
+%% ```
+%% %% {error_if, ErrorPattern}
+%% case Body of
+%%   ErrorPattern = Error ->
+%%     passage_pd:log(#{message, Result}, [error]),
+%%     Error;
+%%   Ok -> Ok
+%% end.
+%% '''
+%% </li>
+%% <li><b>error_if_exception</b>:
+%% ```
+%% try
+%%   Body
+%% catch
+%%   Class:Error ->
+%%     passage_pd:log(#{'error.kind' => class,
+%%                      'message' => Error,
+%%                      'stack' => erlang:get_stacktrace()},
+%%                    [error]),
+%%     erlang:raise(Class, Error, erlang:get_stacktrace())
+%% end.
+%% '''
+%% </li>
+%% </ul>
+
+-type expr_string() :: string().
+%% The textual representation of an expression.
+%%
+%% When used, it will be converted to an AST representation as follows:
+%%
+%% ```
+%% {ok, Tokens, _} = erl_scan:string(ExprString ++ "."),
+%% {ok, [Expr]} = erl_parse:parse_exprs(Tokens).
+%% '''
 
 %%------------------------------------------------------------------------------
 %% Types & Records
diff --git a/test/passage_pd_tests.erl b/test/passage_pd_tests.erl
index 772d043..0f6c068 100644
--- a/test/passage_pd_tests.erl
+++ b/test/passage_pd_tests.erl
@@ -14,7 +14,7 @@
       {"basic test",
        fun () ->
                ok = start_test_tracer(),
-               ok = passage_pd:start_root_span(basic_test, test_tracer),
+               ok = passage_pd:start_span(basic_test, [{tracer, test_tracer}]),
                ok = passage_pd:finish_span(),
 
                [FinishedSpan] = finished_spans(),
@@ -28,7 +28,7 @@
        fun () ->
                ok = start_test_tracer(),
 
-               ok = passage_pd:start_root_span(root, test_tracer),
+               ok = passage_pd:start_span(root, [{tracer, test_tracer}]),
                ok = passage_pd:start_span(child),
                ok = passage_pd:finish_span(),
                ok = passage_pd:finish_span(),
@@ -44,8 +44,8 @@
       {"with span",
        fun () ->
                ok = start_test_tracer(),
-               passage_pd:with_root_span(
-                 root, test_tracer,
+               passage_pd:with_span(
+                 root, [{tracer, test_tracer}],
                  fun () ->
                          passage_pd:with_span(child, fun () -> ok end)
                  end),
@@ -61,7 +61,7 @@
       {"operation name",
        fun () ->
                ok = start_test_tracer(),
-               ok = passage_pd:start_root_span(root, test_tracer),
+               ok = passage_pd:start_span(root, [{tracer, test_tracer}]),
                ok = passage_pd:set_operation_name(foo),
 
                passage_pd:finish_span(),
@@ -71,8 +71,8 @@
       {"tag",
        fun () ->
                ok = start_test_tracer(),
-               ok = passage_pd:start_root_span(
-                      root, test_tracer, [{tags, #{foo => bar, 111 => 222}}]),
+               ok = passage_pd:start_span(
+                      root, [{tracer, test_tracer}, {tags, #{foo => bar, 111 => 222}}]),
                ok = passage_pd:set_tags(#{baz => qux, 111 => 333}),
 
                ok = passage_pd:finish_span(),
@@ -83,7 +83,7 @@
       {"baggage item",
        fun () ->
                ok = start_test_tracer(),
-               ok = passage_pd:start_root_span(root, test_tracer),
+               ok = passage_pd:start_span(root, [{tracer, test_tracer}]),
                ok = passage_pd:set_baggage_items(#{<<"foo">> => <<"bar">>}),
 
                ok = passage_pd:start_span(child),
@@ -96,7 +96,7 @@
       {"log",
        fun () ->
                ok = start_test_tracer(),
-               ok = passage_pd:start_root_span(root, test_tracer),
+               ok = passage_pd:start_span(root, [{tracer, test_tracer}]),
                ok = passage_pd:log(#{hello => world}, [{time, {1, 2, 3}}]),
                ok = passage_pd:log(#{foo => bar}),
 
@@ -109,7 +109,7 @@
       {"error log",
        fun () ->
                ok = start_test_tracer(),
-               ok = passage_pd:start_root_span(root, test_tracer),
+               ok = passage_pd:start_span(root, [{tracer, test_tracer}]),
                ok = passage_pd:log(#{message => "Hello World", kind => greeting}, [error]),
 
                ok = passage_pd:finish_span(),
@@ -124,8 +124,9 @@
        fun () ->
                ok = start_test_tracer(),
 
-               ok = passage_pd:start_root_span(
-                      basic_test, test_tracer, [{tags, #{'sampling.priority' => 0}}]),
+               ok = passage_pd:start_span(
+                      basic_test,
+                      [{tracer, test_tracer}, {tags, #{'sampling.priority' => 0}}]),
                ok = passage_pd:finish_span(),
                ?assertEqual([], finished_spans())
        end},
@@ -137,8 +138,10 @@
                ok = passage_tracer_registry:register(
                       test_tracer, Context, Sampler, Reporter),
 
-               ok = passage_pd:start_root_span(
-                      basic_test, test_tracer, [{tags, #{'sampling.priority' => 1}}]),
+               ok = passage_pd:start_span(
+                      basic_test,
+                      [{tracer, test_tracer},
+                       {tags, #{'sampling.priority' => 1}}]),
                ok = passage_pd:finish_span(),
                ?assertMatch([_Span], finished_spans())
        end},
@@ -156,9 +159,9 @@
       {"additional references",
        fun () ->
                ok = start_test_tracer(),
-               RootSpan = passage:start_root_span(root, test_tracer),
+               RootSpan = passage:start_span(root, [{tracer, test_tracer}]),
 
-               ok = passage_pd:start_span(child, [{refs, [{follows_from, RootSpan}]}]),
+               ok = passage_pd:start_span(child, [{follows_from, RootSpan}]),
                ok = passage_pd:finish_span(),
                ?assertMatch([_Span], finished_spans())
        end}
diff --git a/test/passage_reporter_null_tests.erl b/test/passage_reporter_null_tests.erl
index 2dad04f..d3486ac 100644
--- a/test/passage_reporter_null_tests.erl
+++ b/test/passage_reporter_null_tests.erl
@@ -18,7 +18,7 @@
                Reporter = passage_reporter_null:new(),
                ok = passage_tracer_registry:register(test_tracer, Context, Sampler, Reporter),
 
-               RootSpan = passage:start_root_span(reporter_null_test, test_tracer),
+               RootSpan = passage:start_span(reporter_null_test, [{tracer, test_tracer}]),
                ?assertNotEqual(undefined, RootSpan),
 
                passage:finish_span(RootSpan)
diff --git a/test/passage_sampler_null_tests.erl b/test/passage_sampler_null_tests.erl
index cece638..66dc830 100644
--- a/test/passage_sampler_null_tests.erl
+++ b/test/passage_sampler_null_tests.erl
@@ -18,7 +18,7 @@
                Reporter = passage_reporter_null:new(),
                ok = passage_tracer_registry:register(test_tracer, Context, Sampler, Reporter),
 
-               RootSpan = passage:start_root_span(reporter_null_test, test_tracer),
+               RootSpan = passage:start_span(reporter_null_test, [{tracer, test_tracer}]),
                ?assertEqual(undefined, RootSpan)
        end}
      ]}.
diff --git a/test/passage_sampler_probabilistic_tests.erl b/test/passage_sampler_probabilistic_tests.erl
index a446198..835e2f7 100644
--- a/test/passage_sampler_probabilistic_tests.erl
+++ b/test/passage_sampler_probabilistic_tests.erl
@@ -18,7 +18,7 @@
                Reporter = passage_reporter_null:new(),
                ok = passage_tracer_registry:register(test_tracer, Context, Sampler, Reporter),
 
-               RootSpan = passage:start_root_span(reporter_null_test, test_tracer),
+               RootSpan = passage:start_span(reporter_null_test, [{tracer, test_tracer}]),
                ?assertEqual(undefined, RootSpan)
        end},
       {"All spans are sampled",
@@ -28,7 +28,7 @@
                Reporter = passage_reporter_null:new(),
                ok = passage_tracer_registry:register(test_tracer, Context, Sampler, Reporter),
 
-               RootSpan = passage:start_root_span(reporter_null_test, test_tracer),
+               RootSpan = passage:start_span(reporter_null_test, [{tracer, test_tracer}]),
                ?assertNotEqual(undefined, RootSpan)
        end},
       {"Wrong argument",
diff --git a/test/passage_tests.erl b/test/passage_tests.erl
index 45d890b..044d1fd 100644
--- a/test/passage_tests.erl
+++ b/test/passage_tests.erl
@@ -16,7 +16,7 @@
                ok = start_test_tracer(),
                ?assertEqual([test_tracer], passage_tracer_registry:which_tracers()),
 
-               RootSpan = passage:start_root_span(basic_test, test_tracer),
+               RootSpan = passage:start_span(basic_test, [{tracer, test_tracer}]),
                passage:finish_span(RootSpan),
 
                [FinishedSpan] = finished_spans(),
@@ -30,8 +30,8 @@
        fun () ->
                ok = start_test_tracer(),
 
-               RootSpan = passage:start_root_span(root, test_tracer),
-               ChildSpan = passage:start_span(child, {child_of, RootSpan}),
+               RootSpan = passage:start_span(root, [{tracer, test_tracer}]),
+               ChildSpan = passage:start_span(child, [{child_of, RootSpan}]),
                passage:finish_span(ChildSpan),
                passage:finish_span(RootSpan),
 
@@ -46,7 +46,7 @@
       {"operation name",
        fun () ->
                ok = start_test_tracer(),
-               Span0 = passage:start_root_span(root, test_tracer),
+               Span0 = passage:start_span(root, [{tracer, test_tracer}]),
                Span1 = passage:set_operation_name(Span0, foo),
 
                passage:finish_span(Span1),
@@ -57,8 +57,8 @@
        fun () ->
                ok = start_test_tracer(),
                Span0 =
-                   passage:start_root_span(
-                     root, test_tracer, [{tags, #{foo => bar, 111 => 222}}]),
+                   passage:start_span(
+                     root, [{tracer, test_tracer}, {tags, #{foo => bar, 111 => 222}}]),
                Span1 = passage:set_tags(Span0, #{baz => qux, 111 => 333}),
 
                passage:finish_span(Span1),
@@ -69,10 +69,10 @@
       {"baggage item",
        fun () ->
                ok = start_test_tracer(),
-               RootSpan0 = passage:start_root_span(root, test_tracer),
+               RootSpan0 = passage:start_span(root, [{tracer, test_tracer}]),
                RootSpan1 = passage:set_baggage_items(RootSpan0, #{<<"foo">> => <<"bar">>}),
 
-               ChildSpan0 = passage:start_span(child, {child_of, RootSpan1}),
+               ChildSpan0 = passage:start_span(child, [{child_of, RootSpan1}]),
                ?assertEqual(#{<<"foo">> => <<"bar">>},
                             passage:get_baggage_items(ChildSpan0)),
 
@@ -83,7 +83,7 @@
       {"log",
        fun () ->
                ok = start_test_tracer(),
-               Span0 = passage:start_root_span(root, test_tracer),
+               Span0 = passage:start_span(root, [{tracer, test_tracer}]),
                Span1 = passage:log(Span0, #{hello => world}, [{time, {1, 2, 3}}]),
                Span2 = passage:log(Span1, #{foo => bar}),
 
@@ -96,7 +96,7 @@
       {"error log",
        fun () ->
                ok = start_test_tracer(),
-               Span0 = passage:start_root_span(root, test_tracer),
+               Span0 = passage:start_span(root, [{tracer, test_tracer}]),
                Span1 = passage:log(Span0, #{message => "Hello World", kind => greeting}, [error]),
 
                passage:finish_span(Span1),
@@ -112,8 +112,9 @@
                ok = start_test_tracer(),
 
                RootSpan =
-                   passage:start_root_span(
-                     basic_test, test_tracer, [{tags, #{'sampling.priority' => 0}}]),
+                   passage:start_span(
+                     basic_test,
+                     [{tracer, test_tracer}, {tags, #{'sampling.priority' => 0}}]),
                passage:finish_span(RootSpan),
                ?assertEqual([], finished_spans())
        end},
@@ -126,14 +127,15 @@
                       test_tracer, Context, Sampler, Reporter),
 
                RootSpan =
-                   passage:start_root_span(
-                     basic_test, test_tracer, [{tags, #{'sampling.priority' => 1}}]),
+                   passage:start_span(
+                     basic_test,
+                     [{tracer, test_tracer}, {tags, #{'sampling.priority' => 1}}]),
                passage:finish_span(RootSpan),
                ?assertMatch([_Span], finished_spans())
        end},
       {"unsampled parent",
        fun () ->
-               Span0 = passage:start_span(child, {child_of, undefined}),
+               Span0 = passage:start_span(child, [{child_of, undefined}]),
                Span1 = passage:set_operation_name(Span0, foo),
                Span2 = passage:set_tags(Span1, #{111 => 222}),
                Span3 = passage:set_baggage_items(Span2, #{<<"a">> => <<"b">>}),
@@ -145,9 +147,9 @@
       {"additional references",
        fun () ->
                ok = start_test_tracer(),
-               RootSpan = passage:start_root_span(root, test_tracer),
+               RootSpan = passage:start_span(root, [{tracer, test_tracer}]),
                Span = passage:start_span(
-                        child, {child_of, undefined}, [{refs, [{follows_from, RootSpan}]}]),
+                        child, [{child_of, undefined}, {follows_from, RootSpan}]),
 
                passage:finish_span(Span),
                ?assertMatch([_Span], finished_spans())
@@ -155,7 +157,7 @@
       {"injection and extraction (noop)",
        fun () ->
                ok = start_test_tracer(),
-               Span = passage:start_root_span(root, test_tracer),
+               Span = passage:start_span(root, [{tracer, test_tracer}]),
 
                InjectFun = fun (_Key, _Value, Carrier) -> Carrier end,
                ?assertEqual(#{}, passage:inject_span(Span, text_map, InjectFun, #{})),