defmodule Membrane.Log.Logger do @moduledoc deprecated: "Use Elixir `Logger` instead" @moduledoc """ Module containing functions spawning, shutting down, and handling messages sent to logger. """ use GenServer alias Membrane.Log.Logger.State # Type that defines possible return values of start/start_link functions. @type on_start :: GenServer.on_start() # Type that defines possible process options passed to start/start_link # functions. @type process_options_t :: GenServer.options() # Type that defines possible logger-specific options passed to # start/start_link functions. @type logger_options_t :: struct | nil # Type that defines possible tags attached to the message @type tag_t :: atom # Type that defines possible messages, witch are passed to logger. @type message_t :: list(message_t) | String.t() | {:binary, binary} | integer # Type that defines possible log levels. @type msg_level_t :: :warn | :debug | :info @doc """ Starts process for logger of given module, initialized with given options and links it to the current process in the supervision tree. Works similarly to `GenServer.start_link/3` and has the same return values. """ @spec start_link(module, logger_options_t, process_options_t) :: on_start def start_link(module, logger_options \\ nil, process_options \\ []) do GenServer.start_link(__MODULE__, {module, logger_options}, process_options) end @doc """ Starts process for logger of given module, initialized with given options outside of the supervision tree. Works similarly to `GenServer.start/3` and has the same return values. """ @spec start(module, logger_options_t, process_options_t) :: on_start def start(module, logger_options \\ nil, process_options \\ []) do GenServer.start(__MODULE__, {module, logger_options}, process_options) end @doc """ Stops given logger process. It will wait for reply for amount of time passed as second argument (in milliseconds). Will trigger calling `handle_shutdown/2` logger callback. Returns `:ok`. """ @spec shutdown(pid, timeout) :: :ok def shutdown(server, timeout \\ 5000) do GenServer.stop(server, :normal, timeout) :ok end # Private API @impl true def init({module, options}) do # Call logger's initialization callback case module.handle_init(options) do {:ok, internal_state} -> state = State.new(module, internal_state) {:ok, state} {:error, reason} -> {:stop, reason} end end @impl true def terminate(_reason, %State{module: module, internal_state: internal_state}) do module.handle_shutdown(internal_state) end # Callback invoked on incoming buffer. # # It will delegate actual processing to handle_log/5. @impl true def handle_info( {:membrane_log, level, content, time, tags}, %State{module: module, internal_state: internal_state} = state ) do level |> module.handle_log(content, time, tags, internal_state) |> handle_callback(state) |> Membrane.Helper.GenServer.noreply() end # Generic handler that can be used to convert return value from # logger callback to reply that is accepted by GenServer.handle_*. # # Case when callback returned successfully and requests no further action. defp handle_callback({:ok, new_internal_state}, state) do {:ok, %{state | internal_state: new_internal_state}} end # Generic handler that can be used to convert return value from # logger callback to reply that is accepted by GenServer.handle_info. # # Case when callback returned failure. defp handle_callback({:error, reason, new_internal_state}, %{module: module} = state) do content = ["Error occurred while trying to log message. Reason = ", inspect(reason)] case module.handle_log(:warn, content, Membrane.Time.pretty_now(), [], new_internal_state) do {:ok, new_internal_state} -> {:ok, %{state | internal_state: new_internal_state}} {:error, reason, new_internal_state} -> {{:error, reason}, %{state | internal_state: new_internal_state}} invalid_callback -> raise """ Logger callback replies are expected to be one of: {:ok, state} {:error, reason, state} but got callback reply #{inspect(invalid_callback)}. """ end end end