aws_ex_ray v0.1.16 AwsExRay
Preparation
Setup your AWS environment.
Run xray
daemon on an EC2 instance which you want your application run on.
https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon.html
USAGE
trace = Trace.new()
segment = AwsExRay.start_tracing(trace, "root_segment_name")
do_your_job()
AwsExRay.finish_tracing(segment)
def do_your_job() do
current_trace = AwsExRay.start_subsegment("subsegment-name")
do_some_work()
case current_trace do
{:ok, subsegment} ->
AwsExRay.finish_subsegment(subsegment)
{:error, :out_of_xray} -> :ok # you need to do nothing.
end
end
Multi Processes
Following example doesn't work.
start_subsegment
returns always {:error, :out_of_xray}
.
Because the subsegment is not on the process which start tracing.
Pay attention when you use Task.Supervisor or GenServer.
segment = AwsExRay.start_tracing(trace, "root_segment_name")
Task.Supervisor.start_child(MyTaskSupervisor, fn ->
####################################################################
# this function is executed on different process as root-segment!!!
####################################################################
current_trace = AwsExRay.start_subsegment("subsegment-name")
do_some_work()
case current_trace do
{:ok, subsegment} ->
AwsExRay.finish_subsegment(subsegment)
{:error, :out_of_xray} -> :ok
end
end)
The solution.
Call AwsExRay.Process.keep_tracing(process_which_starts_tracing)
like following
segment = AwsExRay.start_tracing(trace, "root_segment_name")
tracing_pid = self()
Task.Supervisor.start_child(MyTaskSupervisor, fn ->
AwsExRay.Process.keep_tracing(tracing_pid)
current_trace = AwsExRay.start_subsegment("subsegment-name")
do_some_work()
case current_trace do
{:ok, subsegment} ->
AwsExRay.finish_subsegment(subsegment)
{:error, :out_of_xray} -> :ok
end
end)
Multi Servers
[client] --> [1: front_server] --> [2: internal_api or job_worker]
You can tracking Trace including (2) not only (1). If (2) server is HTTP server. You can put X-Amzn-Trace-Id into your requests HTTP headers.
calling internal api on (1)
If you use AwsExRay.HTTPoison, it's easy. all you have to do is to set :traced
option.
options = [traced: true]
result = AwsExRay.HTTPoison.get(url, headers, options)
received internal request on (2)
If you setup AwsExRay.Plug, it automatically takes over tracing.
defmodule MyInternalAPIRouter do
use Plug.Router
plug AwsExRay.Plug, name: "my-internal-api"
WITHOUT SUPPORT LIBRARIES
You can directory pass Trace value
case AwsExRay.start_subsegment("internal-api-request", namespace: :remote) do
{:error, :out_of_xray} ->
pass_job_in_some_way(%{
your_job_data: ...
})
{:ok, subsegment} ->
pass_job_in_some_way(%{
your_job_data: ...
trace_value: Subsegment.generate_trace_value(subsegment)
})
AwsExRay.finish_subsegment(subsegment)
end
And job worker side, it can take over the Trace
job = receive_job_in_some_way()
case AwsExRay.Trace.parse(job.trace_value) do
{:ok, trace}
AwsExRay.start_tracing(trace, "internal-job-name")
:ok
{:error, :not_found} ->
:ok
end
More Simple Interface
If you don't need to put detailed parameters into segment/subsegment, You can do like following
Segment
trace = Trace.new()
result = AwsExRay.trace(trace, "root_segment_name", fn ->
do_your_job()
end)
This is same as,
AwsExRay.finish_tracing(segment)
segment = AwsExRay.start_tracing(trace, "root_segment_name")
result = do_your_job()
AwsExRay.finish_tracing(segment)
result
This way supports just only annotations
trace = Trace.new()
result = AwsExRay.trace(trace, "root_segment_name", %{"MyAnnotationKey" => "MyAnnotationValue"}, fn ->
do_your_job()
end)
Subsegment
opts = [namespace: :none]
result = AwsExRay.subsegment("name", opts, fn trace_value ->
# trace_value is an empty string if this context is out of trace
do_your_job()
end)
This is same as,
current_trace = AwsExRay.start_subsegment("subsegment-name")
result = do_some_work()
case current_trace do
{:ok, subsegment} ->
AwsExRay.finish_subsegment(subsegment)
{:error, :out_of_xray} -> :ok # you need to do nothing.
end
result
This way supports just only annotations
opts = [namespace: :none]
result = AwsExRay.subsegment("name", %{"MyAnnotationKey" => "MyAnnotationValue"}, opts, fn ->
do_your_job()
end)
Link to this section Summary
Link to this section Functions
finish_subsegment(subsegment, end_time \\ Util.now())
finish_subsegment(subsegment :: AwsExRay.Subsegment.t(), end_time :: number()) ::
:ok
finish_subsegment(subsegment :: AwsExRay.Subsegment.t(), end_time :: number()) :: :ok
finish_tracing(segment)
finish_tracing(segment :: AwsExRay.Segment.t()) :: :ok
finish_tracing(segment :: AwsExRay.Segment.t()) :: :ok
start_subsegment(name, opts \\ [])
start_subsegment(name :: String.t(), opts :: keyword()) ::
{:ok, AwsExRay.Subsegment.t()} | {:error, :out_of_xray}
start_subsegment(name :: String.t(), opts :: keyword()) :: {:ok, AwsExRay.Subsegment.t()} | {:error, :out_of_xray}
start_tracing(name)
start_tracing(name :: String.t()) :: AwsExRay.Segment.t()
start_tracing(name :: String.t()) :: AwsExRay.Segment.t()
start_tracing(trace, name)
start_tracing(trace :: AwsExRay.Trace.t(), name :: String.t()) ::
AwsExRay.Segment.t()
start_tracing(trace :: AwsExRay.Trace.t(), name :: String.t()) :: AwsExRay.Segment.t()
subsegment(name, func)
subsegment(name, opts, func)
subsegment(name, annotations, opts, func)
trace(name, func)
trace(trace, name, func)
trace(trace :: AwsExRay.Trace.t(), name :: String.t(), func :: (... -> any())) ::
any()
trace(trace :: AwsExRay.Trace.t(), name :: String.t(), func :: (... -> any())) :: any()
trace(trace, name, annotations, func)
trace(
trace :: AwsExRay.Trace.t(),
name :: String.t(),
annotations :: map(),
func :: (... -> any())
) :: any()
trace( trace :: AwsExRay.Trace.t(), name :: String.t(), annotations :: map(), func :: (... -> any()) ) :: any()