Мониторинг телеметрии phoenix для восходящих вызовов API

У меня есть следующий клиент API в нашем приложении phoenix.

defmodule SomeService do
  use HTTPoison.Base


  def process_request_url(url) do
    Application.get_env(:my_app, :some_service)[:host] <> url
  end

  def process_response_body(body) do
    if String.trim(body) != "" do
      body
      |> Poison.decode! # this could fail if the response is html
      |> Enum.map(fn({k, v}) -> {String.to_atom(k), v} end)
      |> Enum.into(%{})
    else
      body
    end
  end

  def get_some_data(customer_id, access_token) do
    path = "/customer/#{customer_id}/"
    headers = [{"Authorization", "Bearer #{access_token}"}]

    case get(path, headers) do
      {:ok, %HTTPoison.Response{body: body}} ->
        {:ok, body}
      {:error, error} -> {:error, error}
      _ -> {:error, "unknown error from upstream system"}
    end

  end

end

Как лучше всего отслеживать исходящие вызовы API?

  • то есть путь запроса, ответ, time_taken и т. д.

мы используем телеметрию для мониторинга входящих запросов и запросов ECTO. Однако HTTPoison, похоже, не предоставляет события телеметрии из коробки, как мы можем использовать телеметрию для достижения этого?


person Sreerag    schedule 29.01.2020    source источник
comment
взгляните на это, было выпущено не так давно именно для этой задачи github.com/beam-telemetry/ телеметрия   -  person Daniel    schedule 29.01.2020
comment
спасибо @Daniel, я сделал то же самое, чтобы вызвать событие после каждого вызова API с соответствующим обработчиком, но это самый чистый подход, потому что, если я добавляю больше вызовов API к клиенту, я должен сам вызывать событие. это можно улучшить? Размещение моего ответа ниже.   -  person Sreerag    schedule 30.01.2020


Ответы (1)


На данный момент я вызываю событие телеметрии с данными ответа, как показано ниже:

defmodule SomeService do
  use HTTPoison.Base


  def process_request_url(url) do
    Application.get_env(:my_app, :some_service)[:host] <> url
  end

  def process_response_body(body) do
    if String.trim(body) != "" do
      body
      |> Poison.decode! # this could fail if the response is html
      |> Enum.map(fn({k, v}) -> {String.to_atom(k), v} end)
      |> Enum.into(%{})
    else
      body
    end
  end

  def get_some_data(customer_id, access_token) do
    path = "/customer/#{customer_id}/"
    headers = [{"Authorization", "Bearer #{access_token}"}]

    case get(path, headers) do
      {:ok, %HTTPoison.Response{body: body}} ->


        :telemetry.execute(
          [:my_app, :upstream_endpoint],
          %{request_path: response.request_url, 
            status_code: response.status_code, 
            response_headers: response.headers
           },
          response
        )


        {:ok, body}
      {:error, error} -> {:error, error}
      _ -> {:error, "unknown error from upstream system"}
    end

  end

end

Объект ответа содержит всю необходимую информацию (url, статус, продолжительность и т. д.), которую необходимо отслеживать, и она регистрируется в обработчике.

    def handle_event([:my_app, :upstream_endpoint], measurements, metadata, config) do

        summary_event = []
        |> Keyword.put(:route_url, measurements.request_path)
        |> Keyword.put(:status_code, measurements.status_code)
        |> Keyword.put(:response_headers, Enum.into(measurements.response_headers, %{}))

        Logger.info("upstream-call", summary_event)
    end

Событие [:my_app, :upstream_endpoint] привязывается к обработчику при запуске приложения.

:telemetry.attach("may-app", [:my_app, :upstream_endpoint], &handle_event/4, %{})

Хотя на данный момент это работает хорошо, при каждом вызове API событие должно вызываться императивно, а не очень расширяемо.

person Sreerag    schedule 30.01.2020