From f1e0530d4ea93b99a568a51d90d0fd20f125574d Mon Sep 17 00:00:00 2001 From: Ethan Gunderson Date: Tue, 28 Mar 2023 14:31:57 -0500 Subject: [PATCH 1/3] Add a sample rate configuration option to determine trace priority --- lib/spandex.ex | 14 +++++++++++++- lib/tracer.ex | 7 +++++-- test/spandex_test.exs | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/spandex.ex b/lib/spandex.ex index ba95749..c578e35 100644 --- a/lib/spandex.ex +++ b/lib/spandex.ex @@ -503,12 +503,13 @@ defmodule Spandex do defp do_start_trace(name, opts) do strategy = opts[:strategy] adapter = opts[:adapter] + priority = calculate_priority(opts[:sample_rate]) trace_id = adapter.trace_id() span_context = %SpanContext{trace_id: trace_id} with {:ok, span} <- span(name, opts, span_context, adapter) do Logger.metadata(trace_id: to_string(trace_id), span_id: to_string(span.id)) - trace = %Trace{spans: [], stack: [span], id: trace_id} + trace = %Trace{spans: [], stack: [span], id: trace_id, priority: priority} strategy.put_trace(opts[:trace_key], trace) end end @@ -548,6 +549,7 @@ defmodule Spandex do |> Keyword.put(:parent_id, span_context.parent_id) |> Keyword.put(:start, adapter.now()) |> Keyword.put(:id, adapter.span_id()) + |> Keyword.put(:priority, span_context.priority) |> Span.new() end @@ -557,4 +559,14 @@ defmodule Spandex do {:ok, span} -> span end end + + defp calculate_priority(sample_rate) do + cond do + sample_rate == nil -> 1 + sample_rate == 0 -> 0 + sample_rate == 1 -> 1 + :rand.uniform() <= sample_rate -> 1 + true -> 0 + end + end end diff --git a/lib/tracer.ex b/lib/tracer.ex index 9cdf3d3..e95028b 100644 --- a/lib/tracer.ex +++ b/lib/tracer.ex @@ -51,6 +51,7 @@ defmodule Spandex.Tracer do service: :atom, disabled?: :boolean, env: :string, + sample_rate: :float, service_version: :string, services: {:keyword, :atom}, strategy: :atom, @@ -61,7 +62,8 @@ defmodule Spandex.Tracer do defaults: [ disabled?: false, services: [], - strategy: Spandex.Strategy.Pdict + strategy: Spandex.Strategy.Pdict, + sample_rate: 1 ], describe: [ adapter: "The third party adapter to use", @@ -73,7 +75,8 @@ defmodule Spandex.Tracer do disabled?: "Allows for wholesale disabling a tracer", env: "A name used to identify the environment name, e.g `prod` or `development`", services: "A mapping of service name to the default span types.", - strategy: "The storage and tracing strategy. Currently only supports local process dictionary." + strategy: "The storage and tracing strategy. Currently only supports local process dictionary.", + sample_rate: "The rate at which to sample traces. 1.0 means 100% of traces are sampled." ] ) diff --git a/test/spandex_test.exs b/test/spandex_test.exs index 4406f95..cc56821 100644 --- a/test/spandex_test.exs +++ b/test/spandex_test.exs @@ -60,6 +60,34 @@ defmodule Spandex.Test.SpandexTest do assert {:service, "is required"} in validation_errors end + test "sets priority to 1 if no priority is set" do + assert {:ok, %Trace{priority: 1}} = + Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: nil]) + end + + test "sets priority to 1 if priority is set to 100" do + assert {:ok, %Trace{priority: 1}} = + Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: 100]) + end + + test "sets priority to 0 if no priority is set to 0" do + assert {:ok, %Trace{priority: 0}} = Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: 0]) + end + + test "sets priority based on sample rate value" do + sample_rate = 0.10 + + total_priority = + Enum.reduce(1..5000, 0, fn _, acc -> + {:ok, trace} = Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: sample_rate]) + Spandex.finish_trace(@base_opts) + acc + trace.priority + end) + + diff = abs(total_priority - 500) + assert diff <= 50 + end + test "adds span_id, trace_id to log metadata" do opts = @base_opts ++ @span_opts From e183bae880ef36457fc7dd2a263000df1fe8f444 Mon Sep 17 00:00:00 2001 From: Ethan Gunderson Date: Tue, 28 Mar 2023 15:01:07 -0500 Subject: [PATCH 2/3] Refactor, fix test --- lib/spandex.ex | 4 ++-- test/spandex_test.exs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/spandex.ex b/lib/spandex.ex index c578e35..dff37d2 100644 --- a/lib/spandex.ex +++ b/lib/spandex.ex @@ -503,7 +503,8 @@ defmodule Spandex do defp do_start_trace(name, opts) do strategy = opts[:strategy] adapter = opts[:adapter] - priority = calculate_priority(opts[:sample_rate]) + sample_rate = Keyword.get(opts, :sample_rate, 1.0) + priority = calculate_priority(sample_rate) trace_id = adapter.trace_id() span_context = %SpanContext{trace_id: trace_id} @@ -562,7 +563,6 @@ defmodule Spandex do defp calculate_priority(sample_rate) do cond do - sample_rate == nil -> 1 sample_rate == 0 -> 0 sample_rate == 1 -> 1 :rand.uniform() <= sample_rate -> 1 diff --git a/test/spandex_test.exs b/test/spandex_test.exs index cc56821..e2b5f98 100644 --- a/test/spandex_test.exs +++ b/test/spandex_test.exs @@ -65,9 +65,8 @@ defmodule Spandex.Test.SpandexTest do Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: nil]) end - test "sets priority to 1 if priority is set to 100" do - assert {:ok, %Trace{priority: 1}} = - Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: 100]) + test "sets priority to 1 if priority is set to 1" do + assert {:ok, %Trace{priority: 1}} = Spandex.start_trace("root_span", @base_opts ++ @span_opts ++ [sample_rate: 1]) end test "sets priority to 0 if no priority is set to 0" do From f74aa32a43297be1ed0df0ee199c5262818068af Mon Sep 17 00:00:00 2001 From: Ethan Gunderson Date: Tue, 28 Mar 2023 15:19:43 -0500 Subject: [PATCH 3/3] float default value --- lib/tracer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tracer.ex b/lib/tracer.ex index e95028b..f31b214 100644 --- a/lib/tracer.ex +++ b/lib/tracer.ex @@ -63,7 +63,7 @@ defmodule Spandex.Tracer do disabled?: false, services: [], strategy: Spandex.Strategy.Pdict, - sample_rate: 1 + sample_rate: 1.0 ], describe: [ adapter: "The third party adapter to use",