defmodule NewRelic.Harvest.Collector.MetricData do # Heper functions for generating Metrics with the correct timeslice values @moduledoc false alias NewRelic.Metric def transform(:http_dispatcher, duration_s: duration_s), do: %Metric{ name: :HttpDispatcher, call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } def transform({:transaction, name}, type: type, duration_s: duration_s ), do: [ %Metric{ name: "#{type}Transaction", call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: "#{type}Transaction/all", call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: join(["#{type}Transaction", name]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, # UI doesn't handle Elixir's level of concurrency so great # sending just call count improves things %Metric{ name: "#{type}TransactionTotalTime", call_count: 1 }, %Metric{ name: join(["#{type}TransactionTotalTime", name]), call_count: 1 } ] def transform( {:caller, parent_type, parent_account_id, parent_app_id, transport_type}, duration_s: duration_s ), do: [ %Metric{ name: join([ "DurationByCaller", parent_type, parent_account_id, parent_app_id, transport_type, "all" ]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } ] def transform({:datastore, datastore, table, operation}, duration_s: duration_s), do: [ %Metric{ name: join(["Datastore/statement", datastore, table, operation]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: join(["Datastore/operation", datastore, operation]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: join(["Datastore", datastore, "all"]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } ] def transform({:external, url, component, method}, duration_s: duration_s) do host = URI.parse(url).host method = method |> to_string() |> String.upcase() [ %Metric{ name: :"External/all", call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: join(["External", host, "all"]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: join(["External", host, component, method]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } ] end def transform({:external, url, component, method}, type: type, scope: scope, duration_s: duration_s ) do host = URI.parse(url).host method = method |> to_string() |> String.upcase() [ %Metric{ name: join(["External", host, component, method]), scope: join(["#{type}Transaction", scope]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } ] end def transform({:external, name}, duration_s: duration_s), do: [ %Metric{ name: :"External/all", call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s }, %Metric{ name: join(["External", name, "all"]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } ] def transform({:external, name}, type: type, scope: scope, duration_s: duration_s), do: %Metric{ name: join(["External", name]), scope: join(["#{type}Transaction", scope]), call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } def transform(:external, type: type, duration_s: duration_s) do %Metric{ name: "External/all#{type}", call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } end def transform({:function, function_name}, duration_s: duration_s, exclusive_time_s: exclusive_time_s ) do %Metric{ name: join(["Function", function_name]), call_count: 1, total_call_time: duration_s, total_exclusive_time: exclusive_time_s, min_call_time: duration_s, max_call_time: duration_s } end def transform({:function, function_name}, type: type, scope: scope, duration_s: duration_s, exclusive_time_s: exclusive_time_s ) do %Metric{ name: join(["Function", function_name]), scope: join(["#{type}Transaction", scope]), call_count: 1, total_call_time: duration_s, total_exclusive_time: exclusive_time_s, min_call_time: duration_s, max_call_time: duration_s } end def transform(:error, error_count: error_count), do: %Metric{ name: :"Errors/all", call_count: error_count } def transform(:memory, mb: memory_mb), do: %Metric{ name: :"Memory/Physical", call_count: 1, total_call_time: memory_mb } def transform(:cpu, utilization: utilization), do: %Metric{ name: :"CPU/User Time", call_count: 1, total_call_time: utilization } def transform(:apdex, apdex: :satisfying, threshold: t), do: %Metric{name: :Apdex, call_count: 1, min_call_time: t, max_call_time: t} def transform(:apdex, apdex: :tolerating, threshold: t), do: %Metric{name: :Apdex, total_call_time: 1, min_call_time: t, max_call_time: t} def transform(:apdex, apdex: :frustrating, threshold: t), do: %Metric{name: :Apdex, total_exclusive_time: 1, min_call_time: t, max_call_time: t} def transform({:supportability, :error_event}, error_count: error_count), do: [ %Metric{ name: :"Supportability/Events/TransactionError/Sent", call_count: error_count }, %Metric{ name: :"Supportability/Events/TransactionError/Seen", call_count: error_count } ] def transform({:supportability, harvester}, reservoir_size: reservoir_size), do: [ %Metric{ name: join(["Supportability/EventHarvest", harvester, "HarvestLimit"]), call_count: 1, total_call_time: reservoir_size } ] def transform({:supportability, harvester}, harvest_size: harvest_size), do: [ %Metric{ name: join(["Supportability/Elixir/Collector/HarvestSize", harvester]), call_count: 1, total_call_time: harvest_size }, %Metric{ name: :"Supportability/Elixir/Harvest", call_count: 1 }, %Metric{ name: :"Supportability/Harvest", call_count: 1 } ] def transform({:supportability, :collector}, status: status), do: [ %Metric{ name: join(["Supportability/Agent/Collector/HTTPError", status]), call_count: 1 } ] def transform(:supportability, [:trace_context, :accept, :success]), do: [ %Metric{name: :"Supportability/TraceContext/Accept/Success", call_count: 1} ] def transform(:supportability, [:trace_context, :accept, :exception]), do: [ %Metric{name: :"Supportability/TraceContext/Accept/Exception", call_count: 1} ] def transform(:supportability, [:trace_context, :tracestate, :non_new_relic]), do: [ %Metric{name: :"Supportability/TraceContext/TraceState/NoNrEntry", call_count: 1} ] def transform(:supportability, [:trace_context, :traceparent, :invalid]), do: [ %Metric{name: :"Supportability/TraceContext/TraceParent/Parse/Exception", 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 } ] def transform(:supportability, [:transaction, :missing_attributes]), do: [ %Metric{ name: :"Supportability/Transaction/MissingAttributes", call_count: 1 } ] def transform(:queue_time, duration_s: duration_s) do [ %Metric{ name: "WebFrontend/QueueTime", call_count: 1, total_call_time: duration_s, total_exclusive_time: duration_s, min_call_time: duration_s, max_call_time: duration_s } ] end defp join(segments), do: NewRelic.Util.metric_join(segments) end