Repository: newrelic/elixir_agent
Pull request #82 (2019-01-17 01:09:37)

Proper error handling for bad DT payloads
This fixes up our error handling for bad Distributed Trace header payloads
* Log at `debug`
* Send a supportability metric


Patch:
diff --git a/lib/new_relic/distributed_trace/context.ex b/lib/new_relic/distributed_trace/context.ex
index 6eae075..c5dafc1 100644
--- a/lib/new_relic/distributed_trace/context.ex
+++ b/lib/new_relic/distributed_trace/context.ex
@@ -22,10 +22,12 @@ defmodule NewRelic.DistributedTrace.Context do
     with {:ok, json} <- Base.decode64(raw_payload),
          {:ok, map} <- Jason.decode(json),
          context <- validate(map) do
+      NewRelic.report_metric(:supportability, [:dt, :accept, :success])
       context
     else
       error ->
-        NewRelic.log(:error, "Bad DT Payload: #{inspect(error)} #{inspect(raw_payload)}")
+        NewRelic.report_metric(:supportability, [:dt, :accept, :parse_error])
+        NewRelic.log(:debug, "Bad DT Payload: #{inspect(error)} #{inspect(raw_payload)}")
         nil
     end
   end
diff --git a/lib/new_relic/harvest/collector/metric/harvester.ex b/lib/new_relic/harvest/collector/metric/harvester.ex
index 291f9c1..f9e8944 100644
--- a/lib/new_relic/harvest/collector/metric/harvester.ex
+++ b/lib/new_relic/harvest/collector/metric/harvester.ex
@@ -91,7 +91,7 @@ defmodule NewRelic.Harvest.Collector.Metric.Harvester do
 
   def encode(%NewRelic.Metric{name: name, scope: scope} = m),
     do: [
-      %{name: name, scope: scope},
+      %{name: to_string(name), scope: to_string(scope)},
       [
         m.call_count,
         m.total_call_time,
diff --git a/lib/new_relic/harvest/collector/metric_data.ex b/lib/new_relic/harvest/collector/metric_data.ex
index bf90f84..46e209d 100644
--- a/lib/new_relic/harvest/collector/metric_data.ex
+++ b/lib/new_relic/harvest/collector/metric_data.ex
@@ -8,7 +8,7 @@ defmodule NewRelic.Harvest.Collector.MetricData do
   def transform({:transaction, name}, duration_s: duration_s),
     do: [
       %Metric{
-        name: "HttpDispatcher",
+        name: :HttpDispatcher,
         call_count: 1,
         total_call_time: duration_s,
         total_exclusive_time: duration_s,
@@ -16,7 +16,7 @@ defmodule NewRelic.Harvest.Collector.MetricData do
         max_call_time: duration_s
       },
       %Metric{
-        name: "WebTransaction",
+        name: :WebTransaction,
         call_count: 1,
         total_call_time: duration_s,
         total_exclusive_time: duration_s,
@@ -95,7 +95,7 @@ defmodule NewRelic.Harvest.Collector.MetricData do
         max_call_time: duration_s
       },
       %Metric{
-        name: "External/allWeb",
+        name: :"External/allWeb",
         call_count: 1,
         total_call_time: duration_s,
         total_exclusive_time: duration_s,
@@ -106,20 +106,20 @@ defmodule NewRelic.Harvest.Collector.MetricData do
 
   def transform(:error, error_count: error_count),
     do: %Metric{
-      name: "Errors/all",
+      name: :"Errors/all",
       call_count: error_count
     }
 
   def transform(:memory, mb: memory_mb),
     do: %Metric{
-      name: "Memory/Physical",
+      name: :"Memory/Physical",
       call_count: 1,
       total_call_time: memory_mb
     }
 
   def transform(:cpu, utilization: utilization),
     do: %Metric{
-      name: "CPU/User Time",
+      name: :"CPU/User Time",
       call_count: 1,
       total_call_time: utilization
     }
@@ -127,11 +127,11 @@ defmodule NewRelic.Harvest.Collector.MetricData do
   def transform({:supportability, :error_event}, error_count: error_count),
     do: [
       %Metric{
-        name: "Supportability/Events/TransactionError/Sent",
+        name: :"Supportability/Events/TransactionError/Sent",
         call_count: error_count
       },
       %Metric{
-        name: "Supportability/Events/TransactionError/Seen",
+        name: :"Supportability/Events/TransactionError/Seen",
         call_count: error_count
       }
     ]
@@ -143,11 +143,27 @@ defmodule NewRelic.Harvest.Collector.MetricData do
         call_count: harvest_size
       },
       %Metric{
-        name: "Supportability/Elixir/Harvest",
+        name: :"Supportability/Elixir/Harvest",
         call_count: 1
       },
       %Metric{
-        name: "Supportability/Harvest",
+        name: :"Supportability/Harvest",
+        call_count: 1
+      }
+    ]
+
+  def transform(:supportability, [:dt, :accept, :success]),
+    do: [
+      %Metric{
+        name: :"Supportability/DistributedTrace/AcceptPayload/Success",
+        call_count: 1
+      }
+    ]
+
+  def transform(:supportability, [:dt, :accept, :parse_error]),
+    do: [
+      %Metric{
+        name: :"Supportability/DistributedTrace/AcceptPayload/ParseException",
         call_count: 1
       }
     ]


Test patch:
diff --git a/test/distributed_trace_test.exs b/test/distributed_trace_test.exs
index 13e132d..c54f448 100644
--- a/test/distributed_trace_test.exs
+++ b/test/distributed_trace_test.exs
@@ -95,7 +95,7 @@ defmodule DistributedTraceTest do
     refute NewRelic.DistributedTrace.Tracker.fetch(self())
   end
 
-  test "Generate the expected caller metric" do
+  test "Generate the expected metrics" do
     TestHelper.restart_harvest_cycle(Collector.Metric.HarvestCycle)
 
     _response =
@@ -104,8 +104,14 @@ defmodule DistributedTraceTest do
       |> TestPlugApp.call([])
 
     metrics = TestHelper.gather_harvest(Collector.Metric.Harvester)
+
     assert TestHelper.find_metric(metrics, "DurationByCaller/Browser/190/2827902/HTTP/all")
 
+    assert TestHelper.find_metric(
+             metrics,
+             "Supportability/DistributedTrace/AcceptPayload/Success"
+           )
+
     TestHelper.pause_harvest_cycle(Collector.Metric.HarvestCycle)
   end