this repo has no description

Monitor application events via Telemetry spans

hauleth.dev 9b708c66 a94b9d1e

verified
Changed files
+78 -20
lib
test
esl_hn
+20 -8
lib/esl_hn/cache.ex
···
end
def fetch(tid, key) do
-
case :ets.lookup(tid, key) do
-
[{^key, data}] -> {:ok, data}
-
_ -> :error
-
end
+
meta = %{key: key, tid: tid}
+
+
:telemetry.span([:esl_hn, :cache, :fetch], meta, fn ->
+
case :ets.lookup(tid, key) do
+
[{^key, data}] -> {{:ok, data}, %{hit: 1}, meta}
+
_ -> {:error, %{miss: 1}, meta}
+
end
+
end)
end
def get(tid, key, default \\ nil) do
···
end
def write(tid, key, data) do
-
true = :ets.insert(tid, {key, data})
+
meta = %{key: key, tid: tid}
-
:ok
+
:telemetry.span([:esl_hn, :cache, :write], meta, fn ->
+
true = :ets.insert(tid, {key, data})
+
+
{:ok, %{count: 1}, meta}
+
end)
end
def write_all(tid, data) do
-
true = :ets.insert(tid, data)
+
meta = %{tid: tid}
+
+
:telemetry.span([:esl_hn, :cache, :write], meta, fn ->
+
true = :ets.insert(tid, data)
-
:ok
+
{:ok, %{count: length(data)}, meta}
+
end)
end
def prune(tid, id) do
+12 -4
lib/esl_hn/hn.ex
···
end
def story(id, opts \\ []) do
-
with {:ok, body} <- get("item/#{id}.json", opts) do
+
with {:ok, body} <- get("item/:id.json", [id: id], opts) do
Story.changeset(body)
|> Ecto.Changeset.apply_action(:create)
end
···
@base_url URI.new!("https://hacker-news.firebaseio.com/v0/")
-
defp get(path, opts) do
-
base_url = opts[:base_url] || @base_url
+
defp get(path, params \\ [], opts) do
+
opts =
+
Keyword.merge(
+
[
+
base_url: @base_url,
+
path_params: params
+
],
+
opts
+
)
-
Req.new(base_url: base_url)
+
Req.new(opts)
+
|> ReqTelemetry.attach()
|> Req.get(url: path)
|> case do
{:ok, %Req.Response{status: 200, body: body}} ->
+14 -7
lib/esl_hn/refresher.ex
···
@impl true
def handle_continue(:refresh, state) do
+
ids = fetch(state)
+
+
Process.send_after(self(), :refresh, state.refresh)
+
+
{:noreply, %{state | ids: ids}}
+
end
+
+
defp fetch(state) do
{mod, tid} = state.cache
-
ids =
+
:telemetry.span([:esl_hn, :refresh], %{cache: mod}, fn ->
with {:ok, ids} <- Hn.top_stories_ids(state.req_opts),
new_set = MapSet.new(ids),
new = MapSet.difference(new_set, state.ids),
···
EslHn.broadcast_new(for story <- stories, story.id in new, do: story)
-
new_set
+
{new_set, %{new: MapSet.size(new), old: MapSet.size(old)},
+
%{cache: mod}}
else
-
_ -> state.ids
+
_ ->
+
{state.ids, %{failed: 1}, %{cache: mod}}
end
-
-
Process.send_after(self(), :refresh, state.refresh)
-
-
{:noreply, %{state | ids: ids}}
+
end)
end
end
+13
lib/esl_hn_web/telemetry.ex
···
tags: [:event],
unit: {:native, :millisecond}
),
+
summary("esl_hn.refresh.stop.duration",
+
unit: {:native, :millisecond}
+
),
+
sum("esl_hn.refresh.stop.new"),
+
sum("esl_hn.refresh.stop.old"),
+
counter("esl_hn.refresh.stop.failed"),
+
sum("esl_hn.cache.fetch.stop.hit"),
+
sum("esl_hn.cache.fetch.stop.miss"),
+
sum("esl_hn.cache.write.stop.count"),
+
summary("req.request.pipeline.stop.duration",
+
tags: [:url],
+
unit: {:native, :millisecond}
+
),
# VM Metrics
summary("vm.memory.total", unit: {:byte, :kilobyte}),
+3 -1
mix.exs
···
def application do
[
mod: {EslHn.Application, []},
-
extra_applications: [:logger, :runtime_tools]
+
extra_applications: [:logger, :runtime_tools, :os_mon]
]
end
···
# HackerNews client
{:req, "~> 0.5.15"},
+
{:req_telemetry,
+
github: "hauleth/req_telemetry", ref: "template-paths-as-metadata"},
{:ecto, "~> 3.13"},
# Monitoring
+1
mix.lock
···
"plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"},
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
"req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"},
+
"req_telemetry": {:git, "https://github.com/hauleth/req_telemetry.git", "449ddbc2f409fb2ea9efe4ad2a2b229cd01aa153", [ref: "template-paths-as-metadata"]},
"stream_data": {:hex, :stream_data, "1.2.0", "58dd3f9e88afe27dc38bef26fce0c84a9e7a96772b2925c7b32cd2435697a52b", [:mix], [], "hexpm", "eb5c546ee3466920314643edf68943a5b14b32d1da9fe01698dc92b73f89a9ed"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"},
+15
test/esl_hn/hn_test.exs
···
end
describe "story/2" do
+
test "returns error on non 200 response" do
+
data = %{
+
id: 2137,
+
title: "Foo"
+
}
+
+
TestServer.add("/item/2137.json",
+
to: fn conn ->
+
Phoenix.Controller.json(conn, data)
+
end
+
)
+
+
assert {:ok, %{title: "Foo"}} =
+
@subject.story(2137, base_url: TestServer.url())
+
end
end
end