Packages
membrane_core
1.0.0-rc0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.7
1.2.6
1.2.5
retired
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc1
1.1.2
1.1.1
1.1.0
1.1.0-rc1
1.1.0-rc0
1.0.1
1.0.0
1.0.0-rc1
1.0.0-rc0
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
retired
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.1
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
Membrane Multimedia Framework (Core)
Current section
Files
Jump to
Current section
Files
lib/membrane/core/observability.ex
defmodule Membrane.Core.Observability do
@moduledoc false
alias Membrane.ComponentPath
@unsafely_name_processes_for_observer Application.compile_env(
:membrane_core,
:unsafely_name_processes_for_observer,
[]
)
@type config :: %{
optional(:parent_path) => ComponentPath.path(),
optional(:log_metadata) => Logger.metadata(),
name: Membrane.Child.name(),
component_type: :element | :bin | :pipeline,
pid: pid()
}
@doc """
Configures logger and component path.
Also registers the process with a meaningful name for easier introspection with
observer if enabled by setting `unsafely_name_processes_for_observer: :components`
in config.exs.
"""
@spec setup(config, utility_name :: String.Chars.t()) :: :ok
def setup(config, utility_name \\ "") do
%{name: name, component_type: component_type, pid: pid} = config
utility_name = if utility_name == "", do: "", else: " #{utility_name}"
parent_path = Map.get(config, :parent_path, [])
log_metadata = Map.get(config, :log_metadata, [])
Logger.metadata(log_metadata)
pid_string = pid |> :erlang.pid_to_list() |> to_string()
{name, unique_prefix, component_type_suffix} =
if name,
do: {name, pid_string <> " ", ""},
else: {pid_string, "", " (#{component_type})"}
name_suffix = if component_type == :element, do: "", else: "/"
name_str = if(String.valid?(name), do: name, else: inspect(name)) <> name_suffix
register_name_for_observer(
:"##{unique_prefix}#{name_str}#{component_type_suffix}#{utility_name}"
)
component_path = parent_path ++ [name_str]
ComponentPath.set(component_path)
Membrane.Logger.set_prefix(ComponentPath.format(component_path) <> utility_name)
:ok
end
if :components in @unsafely_name_processes_for_observer do
defp register_name_for_observer(name) do
if Process.info(self(), :registered_name) == {:registered_name, []} do
Process.register(self(), name)
end
:ok
end
else
defp register_name_for_observer(_name), do: :ok
end
@doc """
Starts processes to reflect pads structure in the process tree for visibility in observer.
Can be optionally turned on by setting `unsafely_name_processes_for_observer: :links` in
config.exs.
"""
@spec setup_link(Membrane.Pad.ref(), metadata) :: metadata
when metadata: %{optional(:process_to_link) => pid()}
if :links in @unsafely_name_processes_for_observer do
def setup_link(pad_ref, observability_metadata \\ %{}) do
{:ok, observer_dbg_process} =
Task.start_link(fn ->
Process.flag(:trap_exit, true)
Process.register(self(), :"pad #{inspect(pad_ref)} #{:erlang.pid_to_list(self())}")
process_to_link = Map.get(observability_metadata, :process_to_link)
if process_to_link, do: Process.link(process_to_link)
receive do
{:EXIT, _pid, _reason} -> :ok
end
end)
%{process_to_link: observer_dbg_process}
end
else
def setup_link(_pad_ref, _observability_metadata \\ %{}), do: %{}
end
end