Skip to content

Commit

Permalink
Make the metric name be the first element output
Browse files Browse the repository at this point in the history
  • Loading branch information
rwdaigle committed May 30, 2024
1 parent 08878ea commit 1d416e8
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 28 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ Code contributors include:

### 1.0.0

* Ensure that metric name is the first element output
* Bump dev env to modern versions of Elixir (v1.16.3)
* Clean up dependencies
* Be more explicit internally with map vs. keyword list manipulation
Expand Down
35 changes: 14 additions & 21 deletions lib/metrix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,20 @@ defmodule Metrix do
def count(metric, num) when is_number(num), do: count(%{}, metric, num)
def count(metadata, metric), do: count(metadata, metric, 1)
def count(metadata, metric, num) do
metadata
|> add("count", metric, num)
|> log

log(format_metric("count", metric, num), metadata)
metadata
end

def sample(metric, value), do: sample(%{}, metric, value)
def sample(metadata, metric, value) do
metadata
|> add("sample", metric, value)
|> log

log(format_metric("sample", metric, value), metadata)
metadata
end

def measure(metric, ms) when is_number(ms), do: measure(%{}, metric, ms)
def measure(metric, fun) when is_function(fun), do: measure(%{}, metric, fun)
def measure(metadata, metric, ms) when is_number(ms) do
metadata
|> add("measure", metric, "#{ms}ms")
|> log
log(format_metric("measure", metric, "#{ms}ms"), metadata)
end
def measure(metadata, metric, fun) when is_function(fun) do

Expand All @@ -90,22 +82,23 @@ defmodule Metrix do
is_function(fun, 1) -> :timer.tc(fun, [metadata])
end

metadata
|> add("measure", metric, "#{service_us / 1000}ms")
|> log
log(format_metric("measure", metric, "#{service_us / 1000}ms"), metadata)

ret_value
end

defp add(list, type, metric, value) when is_list(list), do: add(Enum.into(list, %{}), type, metric, value)
defp add(map, type, metric, value) when is_map(map) do
Map.put(map, prefix_metric(type, metric), value)
defp format_metric(type, metric, value) do
Logfmt.encode(Map.put(%{}, prefix_metric(type, metric), value))
end

defp log(values = %{}) do
Map.merge(values, get_context())
|> Logfmt.encode
|> write
defp log(formatted_metric, metadata) do
metadata_with_context =
metadata
|> Enum.into(%{})
|> Map.merge(get_context())
|> Logfmt.encode

write("#{formatted_metric} #{metadata_with_context}")
end

defp prefix_metric(type, metric) do
Expand Down
14 changes: 9 additions & 5 deletions test/metrix_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ defmodule MetrixTest do
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
for event <- ["event_name", :event_name] do
output = line(fn -> Metrix.count(metadata, event) end)
assert matches_count?(output, event)
assert output |> String.contains?("count#event_name=1")
assert output |> String.contains?("meta=data")
line(fn -> assert Metrix.count(metadata, event) == metadata end)
Expand All @@ -42,7 +43,7 @@ defmodule MetrixTest do
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
for event <- ["event_name", :event_name] do
output = line(fn -> Metrix.count(metadata, event, 23) end)
assert output |> String.contains?("count#event_name=23")
assert matches_count?(output, event)
assert output |> String.contains?("meta=data")
line(fn -> assert Metrix.count(metadata, event, 1) == metadata end)
end
Expand All @@ -55,6 +56,7 @@ defmodule MetrixTest do
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
for event <- ["event_name", :event_name] do
output = line(fn -> Metrix.count(metadata, event, 23) end)
assert matches_count?(output, event)
assert output |> String.contains?("count#event_name=23")
assert output |> String.contains?("meta=data")
assert output |> String.contains?("context=global")
Expand Down Expand Up @@ -84,6 +86,7 @@ defmodule MetrixTest do
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
for event <- ["event_name", :event_name] do
output = line(fn -> Metrix.sample metadata, event, "13.4mb" end)
assert matches_sample?(output, event)
assert output |> String.contains?("sample#event_name=13.4mb")
assert output |> String.contains?("meta=data")
line(fn -> assert Metrix.sample(metadata, event, "13.4mb") == metadata end)
Expand All @@ -97,6 +100,7 @@ defmodule MetrixTest do
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
for event <- ["event_name", :event_name] do
output = line(fn -> Metrix.sample(metadata, event, "13.4mb") end)
assert matches_sample?(output, event)
assert output |> String.contains?("sample#event_name=13.4mb")
assert output |> String.contains?("meta=data")
assert output |> String.contains?("context=global")
Expand Down Expand Up @@ -156,22 +160,22 @@ defmodule MetrixTest do
test "with map metadata passed to function" do
metadata = %{"meta" => "data"}
output = line(fn -> Metrix.measure(metadata, "event.name", fn %{"meta" => _data} -> :timer.sleep(1) end) end)
assert matches_measure?(output), "Unexpected output format \"#{output}\""
assert matches_measure?(output, "event.name"), "Unexpected output format \"#{output}\""
assert output |> String.contains?("meta=data")
end

test "with keyword list metadata passed to function" do
metadata = [meta: "data"]
output = line(fn -> Metrix.measure(metadata, "event.name", fn [meta: _data] -> :timer.sleep(1) end) end)
assert matches_measure?(output), "Unexpected output format \"#{output}\""
assert matches_measure?(output, "event.name"), "Unexpected output format \"#{output}\""
assert output |> String.contains?("meta=data")
end

test "with metadata and global context" do
Metrix.add_context %{"meta" => "data_global"}
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
output = line(fn -> Metrix.measure metadata, "event.name", fn -> :timer.sleep(1) end end)
assert matches_measure?(output), "Unexpected output format \"#{output}\""
assert matches_measure?(output, "event.name"), "Unexpected output format \"#{output}\""
assert output |> String.contains?("meta=data")
end
end
Expand All @@ -180,7 +184,7 @@ defmodule MetrixTest do
Metrix.add_context %{"meta" => "data_global"}
for metadata <- [%{"meta" => "data"}, [meta: "data"]] do
output = line(fn -> Metrix.measure metadata, "event.name", 78 end)
assert matches_measure?(output), "Unexpected output format \"#{output}\""
assert matches_measure?(output, "event.name"), "Unexpected output format \"#{output}\""
assert output |> String.contains?("meta=data")
assert output |> String.contains?("=78ms"), "Incorrect measurement value"
end
Expand Down
13 changes: 11 additions & 2 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,19 @@ defmodule MetrixTestHelper do
def line(fun), do: capture_log(fun) |> String.trim
def silence(fun), do: capture_log(fun); nil

def matches_measure?(output), do: matches_measure?(output, "event.name")
def matches_measure?(output, event), do: matches_measure?(output, event, "")
def matches_measure?(output, event, prefix) do
Regex.match?(~r/measure##{prefix}#{event}=[0-9]+\.*+[0-9]+ms/u, output)
Regex.match?(~r/^measure##{prefix}#{event}=[0-9]+\.*+[0-9]+ms/u, output)
end

def matches_count?(output, event), do: matches_count?(output, event, "")
def matches_count?(output, event, prefix) do
Regex.match?(~r/^count##{prefix}#{event}=[0-9]+/u, output)
end

def matches_sample?(output, event), do: matches_sample?(output, event, "")
def matches_sample?(output, event, prefix) do
Regex.match?(~r/^sample##{prefix}#{event}=[0-9]+/u, output)
end

# All the machinations needed to start an app with a known config
Expand Down

0 comments on commit 1d416e8

Please sign in to comment.