Skip to content

Commit

Permalink
optional reshape/1 added to: impl, conf, attr (#39)
Browse files Browse the repository at this point in the history
* optional `reshape/1` added to: impl, conf, attr

* optional `reshape/1` added to: impl, conf, attr
  • Loading branch information
am-kantox authored Nov 27, 2024
1 parent 46aa58c commit 2b71270
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 16 deletions.
12 changes: 11 additions & 1 deletion lib/telemetria.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ defmodule Telemetria do
see `:throttle` setting in `Telemetria.Options`
- **`locals: [atom()]`** — the list of names of local variables to be exported
to the telemetry call
- **`transform: [{:args, (list() -> list())}, {:result, (any() -> any())}]`** —
the functions to be called on the incoming attributes and/or result to reshape them
- **`reshape: (map() -> map())`** — the function to be called on the resulting attributes
to reshape them before sending to the actual telemetry handler; the default application-wide
reshaper might be set in `:telemetria, :reshaper` config
### Example
Expand Down Expand Up @@ -130,6 +135,8 @@ defmodule Telemetria do
@type event_prefix :: [atom()]
@type handler_config :: term()

@default_reshaper Application.compile_env(:telemetria, :reshaper)

@doc false
defmacro __using__(opts) do
initial_ast =
Expand Down Expand Up @@ -331,6 +338,9 @@ defmodule Telemetria do
locals =
context |> get_in([:options, :locals]) |> Kernel.||([])

reshape =
context |> get_in([:options, :reshape]) |> Kernel.||(@default_reshaper)

{clause_args, context} = Keyword.pop(context, :arguments, [])
args = Keyword.merge(args, clause_args)

Expand Down Expand Up @@ -363,7 +373,7 @@ defmodule Telemetria do

Telemetria.Throttler.execute(
unquote(group),
{block_ctx, %{system_time: now, consumed: benchmark}, attributes}
{block_ctx, %{system_time: now, consumed: benchmark}, attributes, unquote(reshape)}
)
end

Expand Down
34 changes: 26 additions & 8 deletions lib/telemetria/backend.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ defmodule Telemetria.Backend do
@doc "The implementation will be called when the block context is to be updated"
@callback update(block_context(), block_metadata()) :: block_context()

@doc "The implementation will be called to reshape the event before sending it to the actual handler"
@callback reshape(block_metadata()) :: block_metadata()

@optional_callbacks reshape: 1

@implementation Telemetria.Application.backend()

case @implementation do
Expand All @@ -41,18 +46,31 @@ defmodule Telemetria.Backend do
defdelegate return(block_context, context), to: @implementation
@doc false
defdelegate update(block_context, updates), to: @implementation
@doc false
def reshape(updates) do
if function_exported?(@implementation, :reshape, 1),
do: apply(@implementation, :reshape, [updates]),
else: updates
end

list when is_list(list) ->
def entry(block_id) do
Enum.each(@implementation, & &1.entry(block_id))
if Enum.any?(@implementation, &function_exported?(&1, :reshape, 1)) do
IO.warn("[telemetría] `reshape/1` is ignored when several backends are specified")
end

def return(block_context, context) do
Enum.each(@implementation, & &1.return(block_context, context))
end
@doc false
def entry(block_id),
do: Enum.each(@implementation, & &1.entry(block_id))

def update(block_context, updates) do
Enum.each(@implementation, & &1.update(block_context, updates))
end
@doc false
def return(block_context, context),
do: Enum.each(@implementation, & &1.return(block_context, context))

@doc false
def update(block_context, updates),
do: Enum.each(@implementation, & &1.update(block_context, updates))

@doc false
def reshape(updates), do: updates
end
end
8 changes: 5 additions & 3 deletions lib/telemetria/backend/open_telemetry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ case {Telemetria.Application.open_telemetry?(), Code.ensure_compiled(OpenTelemet

@impl true
def return(block_ctx, context) do
attributes = Estructura.Flattenable.flatten(context, jsonify: true)

Span.set_attributes(block_ctx, attributes)
Span.set_attributes(block_ctx, context)
Span.end_span(block_ctx)
OpenTelemetry.Ctx.detach(block_ctx)

:ok
end

@impl true
def reshape(updates),
do: Estructura.Flattenable.flatten(updates, jsonify: true) |> IO.inspect()

defp fix_block_id(block_id) when is_list(block_id), do: Enum.join(block_id, ".")
defp fix_block_id(block_id), do: block_id
end
Expand Down
3 changes: 3 additions & 0 deletions lib/telemetria/backend/telemetry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ case {Telemetria.Application.telemetry?(), Code.ensure_compiled(:telemetry)} do
{measurements, metadata} = Map.pop(context, :measurements, %{})
:telemetry.execute(block_id, measurements, metadata)
end

@impl true
def reshape(updates), do: updates
end

_ ->
Expand Down
14 changes: 11 additions & 3 deletions lib/telemetria/throttler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,21 @@ defmodule Telemetria.Throttler do
Logger.warning("Wrong config for group: #{group}, skipping")
end

defp do_execute(group, {event, measurements, metadata}) do
context =
defp do_execute(group, {event, measurements, metadata, reshaper}) do
{context, updates} =
metadata
|> Map.put(:telemetria_group, group)
|> Map.put(:measurements, measurements)
|> Map.pop(:context, %{})

Telemetria.Backend.return(event, context)
updates = if is_function(reshaper, 1), do: reshaper.(updates), else: updates

updates =
updates
|> Map.put(:context, context)
|> Telemetria.Backend.reshape()

Telemetria.Backend.return(event, updates)
end

defp do_execute(group, [event]),
Expand Down
5 changes: 4 additions & 1 deletion test/support/telemetria_tester.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ defmodule Test.Telemetria.Example do
transform: [
args: {__MODULE__, :transform_args},
result: &__MODULE__.transform_result/1
]
],
reshape: &Test.Telemetria.Example.reshape/1
defp annotated_2(i) when (is_integer(i) and i == 42) or is_nil(i), do: i || 42

@telemetria level: :error, if: &Test.Telemetria.S.allow?/1
Expand Down Expand Up @@ -84,4 +85,6 @@ defmodule Test.Telemetria.Example do
def transform_args(args), do: inspect(args)

def transform_result(result), do: inspect(result)

def reshape(outcome), do: Map.take(outcome, [:args, :result, :locals])
end

0 comments on commit 2b71270

Please sign in to comment.