defmodule NewRelic.Harvest.Collector.AgentRun do use GenServer # This GenServer is responsible for connecting to the collector # and holding onto the Agent Run connect response in an ETS table @moduledoc false alias NewRelic.Harvest.Collector def start_link(_) do GenServer.start_link(__MODULE__, :ok, name: __MODULE__) end def init(:ok) do NewRelic.sample_process() :ets.new(__MODULE__, [:named_table, :public, :set]) if NewRelic.Config.enabled?() do {:ok, %{status: :not_connected}, {:continue, :preconnect}} else {:ok, %{status: :not_connected}} end end def ensure_initialized do GenServer.call(__MODULE__, :ping) end def agent_run_id, do: lookup(:agent_run_id) def trusted_account_key, do: lookup(:trusted_account_key) def account_id, do: lookup(:account_id) def primary_application_id, do: lookup(:primary_application_id) def reconnect, do: send(__MODULE__, :reconnect) def handle_continue(:preconnect, _state) do case Collector.Protocol.preconnect() do {:ok, %{"redirect_host" => redirect_host}} -> Application.put_env(:new_relic_agent, :collector_instance_host, redirect_host) {:noreply, %{status: :preconnected}, {:continue, :connect}} _error -> {:noreply, %{status: :error_during_preconnect}} end end def handle_continue(:connect, _state) do status = connect() {:noreply, %{status: status}, {:continue, :complete_boot}} end def handle_continue(:complete_boot, %{status: :connected} = state) do NewRelic.EnabledSupervisorManager.start_child() {:noreply, state} end def handle_continue(:complete_boot, state) do {:noreply, state} end def handle_info(:reconnect, _state) do status = connect() {:noreply, %{status: status}} end def handle_call(:ping, _from, state) do {:reply, true, state} end defp connect() do Collector.Connect.payload() |> Collector.Protocol.connect() |> store_agent_run() end defp store_agent_run({:ok, %{"agent_run_id" => _} = connect_response}) do store(:agent_run_id, connect_response["agent_run_id"]) store(:trusted_account_key, connect_response["trusted_account_key"]) store(:account_id, connect_response["account_id"]) store(:primary_application_id, connect_response["primary_application_id"]) store(:request_headers, connect_response["request_headers_map"] |> Map.to_list()) store(:sampling_target, connect_response["sampling_target"]) store(:sampling_target_period, connect_response["sampling_target_period_in_seconds"] * 1000) connect_response["data_methods"] event_harvest = connect_response["event_harvest_config"] harvest_limits = event_harvest["harvest_limits"] if harvest_limits["analytic_event_data"] do store(:transaction_event_reservoir_size, harvest_limits["analytic_event_data"]) store(:transaction_event_harvest_cycle, event_harvest["report_period_ms"]) else analytic_event = connect_response["data_methods"]["analytic_event_data"] store(:transaction_event_reservoir_size, analytic_event["max_samples_stored"]) store(:transaction_event_harvest_cycle, analytic_event["report_period_in_seconds"] * 1000) end if harvest_limits["custom_event_data"] do store(:custom_event_reservoir_size, harvest_limits["custom_event_data"]) store(:custom_event_harvest_cycle, event_harvest["report_period_ms"]) else custom_event = connect_response["data_methods"]["custom_event_data"] store(:custom_event_reservoir_size, custom_event["max_samples_stored"]) store(:custom_event_harvest_cycle, custom_event["report_period_in_seconds"] * 1000) end if harvest_limits["error_event_data"] do store(:error_event_reservoir_size, harvest_limits["error_event_data"]) store(:error_event_harvest_cycle, event_harvest["report_period_ms"]) else error_event = connect_response["data_methods"]["error_event_data"] store(:error_event_reservoir_size, error_event["max_samples_stored"]) store(:error_event_harvest_cycle, error_event["report_period_in_seconds"] * 1000) end if harvest_limits["span_event_data"] do store(:span_event_reservoir_size, harvest_limits["span_event_data"]) store(:span_event_harvest_cycle, event_harvest["report_period_ms"]) else span_event = connect_response["data_methods"]["span_event_data"] store(:span_event_reservoir_size, span_event["max_samples_stored"]) store(:span_event_harvest_cycle, span_event["report_period_in_seconds"] * 1000) end store(:data_report_period, connect_response["data_report_period"] * 1000) store(:apdex_t, connect_response["apdex_t"]) :connected end defp store_agent_run(_bad_connect_response) do :bad_connect_response end def store(key, value) do :ets.insert(__MODULE__, {key, value}) end def lookup(key, default \\ nil) do Application.get_env(:new_relic_agent, key) || case :ets.lookup(__MODULE__, key) do [{^key, value}] -> value [] -> default end end end