Current section
Files
Jump to
Current section
Files
lib/notion.ex
defmodule Notion do
@moduledoc """
Notion is a thin wrapper around [`:telemetry`](https://github.com/beam-telemetry/telemetry) that defines functions that dispatch telemetry events, documentation, and specs for your applications events.
"""
@moduledoc_template """
`MODULE_NAME` is a thin wrapper around [`:telemetry`](https://github.com/beam-telemetry/telemetry).
All events will be prefixed with `NOTION_NAME`.
The following events are emitted:
NOTION_EVENTS
To access this list programmatically use `events/0`.
If set, default metadata will be applied to all events. See: `metadata/0`
"""
@doc false
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
@notion_name opts[:name]
@notion_metadata opts[:metadata] || %{}
Module.register_attribute(__MODULE__, :events, accumulate: true, persist: false)
@before_compile Notion
require Notion
import Notion
@spec name() :: atom
@doc "The instrumenter name"
def name(), do: @notion_name
@spec metadata() :: map
@doc """
Default metadata added to all events.
Defaults:
`#{inspect(@notion_metadata)}`
"""
def metadata(), do: @notion_metadata
@spec metadata(map) :: map
@doc "Merges metadata with defaults"
def metadata(alt), do: Map.merge(metadata(), alt)
end
end
defmacro __before_compile__(env) do
events = Module.get_attribute(env.module, :events)
name = Module.get_attribute(env.module, :notion_name)
metadata = Module.get_attribute(env.module, :notion_metadata)
moduledoc =
case Module.get_attribute(env.module, :moduledoc) do
{_line, body} when is_binary(body) -> body
_not_set -> @moduledoc_template
end
quote bind_quoted: [
module_name: env.module,
events: events,
moduledoc: moduledoc,
name: name,
metadata: Macro.escape(metadata)
] do
event_list = Enum.map(events, fn e -> "* `#{inspect(e)}` \n" end)
module_name = String.replace("#{module_name}", ~r/Elixir\./, "")
@moduledoc moduledoc
|> String.replace("MODULE_NAME", "#{module_name}")
|> String.replace("NOTION_NAME", "#{name}")
|> String.replace("NOTION_EVENTS", Enum.join(event_list, ""))
|> String.replace("NOTION_DEFAULT_METADATA", "`#{inspect(metadata)}`")
@spec events() :: list(list(atom))
@doc """
Returns a list of all events emitted by this module:
#{event_list}
Great for use with `:telemetry.attach_many/4`
"""
def events(), do: unquote(events)
end
end
defmacro defevent(event) do
names =
case event do
event when is_list(event) -> event
event -> [event]
end
function_name = Enum.join(names, "_")
quote do
@event [@notion_name | unquote(names)]
@events @event
found_typespec =
Enum.find(@spec, fn {:spec, {_, _lines, typespecs}, _} ->
Enum.find(typespecs, fn ast ->
case ast do
{func_name, _, _} -> func_name == unquote(:"#{function_name}")
_ -> false
end
end)
end)
if !found_typespec do
@spec unquote(:"#{function_name}")(map, map) :: :ok
end
# credo:disable-for-next-line
def unquote(:"#{function_name}")(measurements, metadata \\ %{}) do
:telemetry.execute(@event, measurements, metadata(metadata))
:ok
end
end
end
end