Add modules
diff --git a/src/jaegerl.erl b/src/jaegerl.erl
new file mode 100644
index 0000000..814515b
--- /dev/null
+++ b/src/jaegerl.erl
@@ -0,0 +1,94 @@
+-module(jaegerl).
+
+-export([start_span/1, start_span/2]).
+-export([finish_span/0, finish_span/1]).
+-export([current_span/0]).
+-export([log/1, log/2]).
+-export([set_tags/1]).
+
+-export_type([tracer_id/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]).
+-export_type([span_reference/0, span_reference_type/0]).
+-export_type([span/0]).
+-export_type([operation_name/0]).
+-export_type([log_fields/0, log_field_name/0, log_field_value/0]).
+
+-type tracer_id() :: atom().
+
+-type start_span_options() :: [start_span_option()].
+
+-type start_span_option() :: {tracer, tracer_id()}
+                           | {start_time, erlang:timestamp()}
+                           | {refs, [span_reference()]}
+                           | {tags, tags()}.
+
+-type finish_span_options() :: [finish_span_option()].
+
+-type finish_span_option() :: {finish_time, erlang:timestamp()}
+                            | {owner, pid()}.
+
+-type tags() :: #{tag_name() => tag_value()}.
+-type tag_name() :: atom() | binary().
+-type tag_value() :: atom() | binary() | number() | boolean().
+
+-type span_reference() :: {span_reference_type(), span()}.
+-type span_reference_type() :: child_of | follows_from.
+
+-type span() :: jaegerl_span:maybe_span().
+
+-type operation_name() :: atom() | binary().
+
+-type log_fields() :: #{log_field_name() => log_field_value()}.
+-type log_field_name() :: atom() | binary().
+-type log_field_value() :: atom() | binary() | number() | boolean().
+
+-spec start_span(operation_name()) -> span().
+start_span(OperationName) ->
+    start_span(OperationName, []).
+
+-spec start_span(operation_name(), start_span_options()) -> ok.
+start_span(OperationName, Options) ->
+    Ancestors = get_ancestors(),
+    Span = jaegerl_span:start_span(OperationName, Options),
+    put_ancestors([Span | Ancestors]).
+
+-spec set_tags(tags()) -> ok.
+set_tags(Tags) ->
+    error(unimplemented, [Tags]).
+
+-spec log(log_fields()) -> ok.
+log(Log) ->
+    log(Log, os:timestamp()).
+
+-spec log(log_fields(), erlang:timestamp()) -> ok.
+log(Log, Time) ->
+    error(unimplemented, [Log, Time]).
+
+-spec finish_span() -> ok.
+finish_span() ->
+    finish_span([]).
+
+-spec finish_span(finish_span_options()) -> ok.
+finish_span(Options) ->
+    error(unimplemented, [Options]).
+
+-spec current_span() -> span().
+current_span() ->
+    case get(jaegerl_ancestors) of
+        undefined  -> undefined;
+        [Span | _] -> Span
+    end.
+
+-spec get_ancestors() -> [span()].
+get_ancestors() ->
+    case get(jaegerl_ancestors) of
+        undefined -> [];
+        Ancestors -> Ancestors
+    end.
+
+-spec put_ancestors([span()]) -> ok.
+put_ancestors(Ancestors) ->
+    put(jaegerl_ancestors, Ancestors),
+    ok.
diff --git a/src/jaegerl_local_ns.erl b/src/jaegerl_local_ns.erl
new file mode 100644
index 0000000..7078584
--- /dev/null
+++ b/src/jaegerl_local_ns.erl
@@ -0,0 +1,12 @@
+-module(jaegerl_local_ns).
+
+-export([child_spec/0]).
+-export([tracer_name/1]).
+
+-spec child_spec() -> supervisor:child_spec().
+child_spec() ->
+    local:name_server_child_spec(?MODULE).
+
+-spec tracer_name(jaegerl:tracer_id()) -> local:otp_name().
+tracer_name(TracerId) ->
+    local:otp_name({?MODULE, {tracer, TracerId}}).
diff --git a/src/jaegerl_reporter.erl b/src/jaegerl_reporter.erl
new file mode 100644
index 0000000..0dce7ed
--- /dev/null
+++ b/src/jaegerl_reporter.erl
@@ -0,0 +1 @@
+-module(jaegerl_reporter).
diff --git a/src/jaegerl_sampler.erl b/src/jaegerl_sampler.erl
new file mode 100644
index 0000000..0192c90
--- /dev/null
+++ b/src/jaegerl_sampler.erl
@@ -0,0 +1 @@
+-module(jaegerl_sampler).
diff --git a/src/jaegerl_span.erl b/src/jaegerl_span.erl
new file mode 100644
index 0000000..503106b
--- /dev/null
+++ b/src/jaegerl_span.erl
@@ -0,0 +1,29 @@
+-module(jaegerl_span).
+
+-export([start_span/2]).
+
+-export_type([span/0, maybe_span/0]).
+
+-define(SPAN, ?MODULE).
+
+-record(?SPAN,
+        {
+          tracer :: jaegerl:tracer_id(),
+          operation_name :: jaegerl:operation_name(),
+          start_time :: erlang:timestamp(),
+          tags :: jaegerl:tags(),
+          refs :: [jaegerl:span_reference()],
+          baggage_items :: #{},
+          trace_id :: integer(), % 128-bit
+          span_id :: integer(), % 64-bit
+          parent_span_id :: integer(), % 64-bit
+          flags :: non_neg_integer(), % 32-bit
+          debug_id :: binary() | undefined
+        }).
+
+-opaque span() :: #?SPAN{}.
+-type maybe_span() :: span() | undefined.
+
+-spec start_span(jaegerl:operation_name(), jaegerl:start_span_options()) -> maybe_span().
+start_span(OperationName, Options) ->
+    error(unimplemented, [OperationName, Options]).
diff --git a/src/jaegerl_sup.erl b/src/jaegerl_sup.erl
index 67bd0e2..14d5dd4 100644
--- a/src/jaegerl_sup.erl
+++ b/src/jaegerl_sup.erl
@@ -12,9 +12,15 @@
     supervisor:start_link({local, ?SERVER}, ?MODULE, []).
 
 init([]) ->
+    Table = #{
+      id      => jaegerl_table,
+      start   => {jaegerl_table, start_link, []},
+      type    => worker,
+      restart => permanent
+     },
     TracerSup = #{
       id    => jaegerl_tracer_sup,
       start => {jaegerl_tracer_sup, start_link, []},
       type  => supervisor
      },
-    {ok, {#{}, [TracerSup]} }.
+    {ok, {#{strategy => rest_for_one}, [Table, TracerSup]} }.
diff --git a/src/jaegerl_table.erl b/src/jaegerl_table.erl
new file mode 100644
index 0000000..266b1f4
--- /dev/null
+++ b/src/jaegerl_table.erl
@@ -0,0 +1,58 @@
+-module(jaegerl_table).
+
+-export([get_tracer_info/1]).
+
+-export([start_link/0]).
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+-type tracer_info() ::
+        #{
+           pid => pid(),
+           sampler => module()
+         }.
+
+-spec start_link() -> {ok, pid()} | {error, Reason :: term()}.
+start_link() ->
+    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+-define(STATE, ?MODULE).
+
+-record(?STATE,
+        {
+          table :: ets:tab()
+        }).
+
+-spec get_tracer_info(jaegerl:tracer_id()) -> {ok, tracer_info()} | error.
+get_tracer_info(TracerId) ->
+    try ets:lookup(?MODULE, {tracer_info, TracerId}) of
+        [{_, Info}] -> {ok, Info};
+        _           -> error
+    catch
+        error:badarg -> error
+    end.
+
+%% @private
+init([]) ->
+    Table = ets:new(?MODULE, [named_table, protected, {read_concurrency, true}]),
+    {ok, #?STATE{table = Table}}.
+
+%% @private
+handle_call(Request, From, State) ->
+    {stop, {unknown_call, Request, From}, State}.
+
+%% @private
+handle_cast(Request, State) ->
+    {stop, {unknown_cast, Request}, State}.
+
+%% @private
+handle_info(Info, State) ->
+    {stop, {unknown_info, Info}, State}.
+
+%% @private
+terminate(_Reason, _State) ->
+    ok.
+
+%% @private
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
diff --git a/src/jaegerl_tracer.erl b/src/jaegerl_tracer.erl
index 8a69a3a..57c4edc 100644
--- a/src/jaegerl_tracer.erl
+++ b/src/jaegerl_tracer.erl
@@ -1,7 +1,12 @@
+%% @private
 -module(jaegerl_tracer).
 
 -export([start_span/1, start_span/2]).
 
+-export([start_link/1]).
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
 -export_type([tracer/0]).
 -export_type([start_span_option/0, start_span_options/0]).
 
@@ -10,6 +15,18 @@
 -type start_span_options() :: [start_span_option()].
 -type start_span_option() :: {tracer, tracer()}.
 
+-define(STATE, ?MODULE).
+
+-record(?STATE,
+        {
+          watchings = [] :: [Span :: term()],
+          reporters = [] :: [module()]
+        }).
+
+-spec start_link(jaegerl:tracer_id()) -> {ok, pid()} | {error, Reason :: term()}.
+start_link(TracerId) ->
+    gen_server:start_link(jaegerl_local_ns:tracer_name(TracerId), ?MODULE, [], []).
+
 -spec start_span(jaegerl:operation_name()) -> jaegerl_span:span().
 start_span(OperationName) ->
     start_span(OperationName, []).
@@ -17,3 +34,27 @@
 -spec start_span(jaeger:operation_name(), start_span_options()) -> jaegerl_span:span().
 start_span(OperationName, Options) ->
     error(unimplemented, [OperationName, Options]).
+
+%% @private
+init([]) ->
+    {ok, #?STATE{}}.
+
+%% @private
+handle_call(Request, From, State) ->
+    {stop, {unknown_call, Request, From}, State}.
+
+%% @private
+handle_cast(Request, State) ->
+    {stop, {unknown_cast, Request}, State}.
+
+%% @private
+handle_info(Info, State) ->
+    {stop, {unknown_info, Info}, State}.
+
+%% @private
+terminate(_Reason, _State) ->
+    ok.
+
+%% @private
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
diff --git a/src/jaegerl_tracer_sup.erl b/src/jaegerl_tracer_sup.erl
index 0a5832f..3727184 100644
--- a/src/jaegerl_tracer_sup.erl
+++ b/src/jaegerl_tracer_sup.erl
@@ -2,18 +2,26 @@
 
 -behaviour(supervisor).
 
+-export([start_child/1]).
+
 -export([start_link/0]).
 
 -export([init/1]).
 
 -define(SERVER, ?MODULE).
 
+-spec start_child(jaegerl:tracer_id()) -> {ok, pid()} | {error, Reason :: term()}.
+start_child(TracerId) ->
+    Child = #{
+      id      => jaegerl_tracer,
+      start   => {jaegerl_tracer, start_link, [TracerId]},
+      type    => worker,
+      restart => permanent
+     },
+    supervisor:start_child(?MODULE, Child).
+
 start_link() ->
     supervisor:start_link({local, ?SERVER}, ?MODULE, []).
 
 init([]) ->
-    Child = #{
-      id    => jaegerl_tracer,
-      start => {jaegerl_tracer, start_link, []}
-     },
-    {ok, {#{strategy => simple_one_for_one}, [Child]} }.
+    {ok, {#{}, []} }.