From cdd1d2aff78b06fa5083d74bd38cbfc3301c48f2 Mon Sep 17 00:00:00 2001 From: kballou Date: Tue, 22 Mar 2016 15:15:56 -0600 Subject: Refactor query module Break-up processing bits to add tests --- lib/ex_prometheus_io.ex | 12 ++++---- lib/ex_prometheus_io/query.ex | 60 +++++++++++++++++++++++------------- test/ex_prometheus_io_query_test.exs | 50 ++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 test/ex_prometheus_io_query_test.exs diff --git a/lib/ex_prometheus_io.ex b/lib/ex_prometheus_io.ex index cac39a5..dd47bee 100644 --- a/lib/ex_prometheus_io.ex +++ b/lib/ex_prometheus_io.ex @@ -7,25 +7,25 @@ defmodule ExPrometheusIo do def query(query, _opts \\ []) do query_opts = [query] - spawn_query(:fetch_query, query_opts) + spawn_query(:query, query_opts) end def range(query, start_ts, end_ts, step, _opts \\ []) do query_opts = [query, start_ts, end_ts, step] - spawn_query(:fetch_range, query_opts) + spawn_query(:range, query_opts) end def series(matches, _opts \\ []) do - spawn_query(:fetch_series, [matches]) + spawn_query(:series, [matches]) end - defp spawn_query(fetch, query_opts, _opts \\ []) do + defp spawn_query(query, query_opts, _opts \\ []) do query_ref = make_ref() - query_opts = query_opts ++ [query_ref, self()] + query_opts = [query | query_opts] ++ [query_ref, self()] {:ok, pid} = Task.Supervisor.start_child( ExPrometheusIo.QuerySupervisor, ExPrometheusIo.Query, - fetch, + :process, query_opts) {pid, query_ref} end diff --git a/lib/ex_prometheus_io/query.ex b/lib/ex_prometheus_io/query.ex index 2bba7bd..140d0a9 100644 --- a/lib/ex_prometheus_io/query.ex +++ b/lib/ex_prometheus_io/query.ex @@ -1,41 +1,59 @@ defmodule ExPrometheusIo.Query do - def fetch_query(query_str, query_ref, owner) do - "query=#{query_str}" <> "&time=#{:os.system_time(:seconds)}" - |> fetch_json("query") + def process(:query, query, query_ref, owner) do + build_url(:query, query) + |> fetch_json() |> Poison.decode |> send_results(query_ref, owner) end - def fetch_range(query_str, start_ts, end_ts, step, query_ref, owner) do - "query=#{query_str}" - <> "&start=#{start_ts}" - <> "&end=#{end_ts}" - <> "&step=#{step}" - |> fetch_json("query_range") + def process(:range, query, start_ts, end_ts, step, query_ref, owner) do + build_url(:range, {query, start_ts, end_ts, step}) + |> fetch_json() |> Poison.decode |> send_results(query_ref, owner) end - def fetch_series(matches, query_ref, owner) do - matches - |> Enum.map(fn(match) -> "match[]=#{match}" end) - |> Enum.join("&") - |> fetch_json("series") + def process(:series, matches, query_ref, owner) do + build_url(:series, matches) + |> fetch_json() |> Poison.decode |> send_results(query_ref, owner) end - defp fetch_json(query_str, query_type) do - {:ok, {_, _, body}} = :httpc.request( - "http://" - <> prometheus_host - <> "/api/v1/#{query_type}?" - <> query_str - |> String.to_char_list()) + defp fetch_json(uri) do + {:ok, {_, _, body}} = :httpc.request(uri |> String.to_char_list()) body end + def endpoint(:query), do: build_endpoint("query") + def endpoint(:range), do: build_endpoint("query_range") + def endpoint(:series), do: build_endpoint("series") + defp build_endpoint(endpoint) do + "http://" <> prometheus_host <> "/api/v1/#{endpoint}" + end + def build_url(query, opts) when query in [:query, :range, :series] do + endpoint(query) <> "?" <> query_params(query, opts) + end + + def query_params(:query, query_parameter) do + query_time = :os.system_time(:seconds) + "query=#{query_parameter}&time=#{query_time}" + end + + def query_params(:range, {topic, start_ts, end_ts, step}) do + "query=#{topic}" + <> "&start=#{start_ts}" + <> "&end=#{end_ts}" + <> "&step=#{step}" + end + + def query_params(:series, matches) when is_list(matches) do + matches + |> Enum.map(fn(match) -> "match[]=#{match}" end) + |> Enum.join("&") + end + defp send_results({:error, :invalid} = results, query_ref, owner) do send(owner, {:prometheus_results, query_ref, results}) end diff --git a/test/ex_prometheus_io_query_test.exs b/test/ex_prometheus_io_query_test.exs new file mode 100644 index 0000000..6e480a9 --- /dev/null +++ b/test/ex_prometheus_io_query_test.exs @@ -0,0 +1,50 @@ +defmodule ExPrometheusIo.QueryTest do + use ExUnit.Case + + import ExPrometheusIo.Query, only: [query_params: 2, + endpoint: 1, + build_url: 2] + + test "query_params builds proper query string" do + curr_time = :os.system_time(:seconds) + assert "query=up&time=#{curr_time}" == query_params(:query, "up") + end + + test "query_params builds correct range query" do + curr_time = :os.system_time(:seconds) + assert "query=up&start=#{curr_time-5}&end=#{curr_time}&step=1" == + query_params(:range, {"up", curr_time - 5, curr_time, 1}) + end + + test "query_params builds correct series query" do + assert "match[]=up" == query_params(:series, ["up"]) + end + + test "query endpoint" do + assert "http://#{prom_host}/api/v1/query" == endpoint(:query) + end + + test "range endpoint" do + assert "http://#{prom_host}/api/v1/query_range" == endpoint(:range) + end + + test "series endpoint" do + assert "http://#{prom_host}/api/v1/series" == endpoint(:series) + end + + test "build url" do + base_url = "http://#{prom_host}/api/v1/" + cur_time = :os.system_time(:seconds) + assert base_url <> "query?query=up&time=#{cur_time}" + == build_url(:query, "up") + assert base_url <> "query_range?query=up" + <> "&start=#{cur_time-5}" + <> "&end=#{cur_time}" + <> "&step=1" + == build_url(:range, {"up", cur_time - 5, cur_time, 1}) + assert base_url <> "series?match[]=up" == build_url(:series, ["up"]) + end + + defp prom_host, do: Application.fetch_env!(:ex_prometheus_io, :hostname) + +end -- cgit v1.2.1