defmodule BuffLog do use GenServer def init([acc_uuid, options]) do ets = :ets.new(:somelog, [:public]) :erlang.send_after(3000, self(), :tick) # open FD here if some persistent_term is true st = Map.merge(options, %{ ets: ets, counter: 0, monitors: [], last_add: :os.system_time(1000), name: acc_uuid }) {:ok, st} end def handle_info(:tick, state) do if state.monitors == [] && :os.system_time(1) > state.last_add + 60 * 60 do {:stop, :normal, state} else :erlang.send_after(30000, self(), :tick) {:noreply, state} end end def handle_info({:add_line, line, side}, state) do state = %{state | counter: state.counter + 1, last_add: :os.system_time(1000)} if state.counter > 5000 do :ets.delete(state.ets, state.counter - 5000) end :ets.insert(state.ets, {state.counter, state.last_add, side, line}) Enum.each(state.monitors, fn {pid, _} -> send(pid, {:log_notification, state.counter, line}) end) # write line to FD here if some persistent_term is true {:noreply, state} end def handle_call(:get_lines, caller, state) do lines = :ets.tab2list(state.ets) {:reply, lines, state} end def handle_info({:DOWN, ref, :process, pid, _}, state) do state = %{state | monitors: Enum.reject(state.monitors, fn {p, _} -> pid == p end)} {:noreply, state} end def handle_call(:watch, {pid, _} = caller, state) do ref = Process.monitor(pid) state = %{state | monitors: [{pid, ref} | state.monitors]} {:reply, :ok, state} end def add_line(log, line, side \\ "note") do cond do log == :log_mitm -> cond do is_binary(line) -> IO.puts(line) true -> IO.inspect(line, limit: :infinity) end l = Process.whereis(log) -> # Mitm.Game.send_to_log(side, (if is_binary(line) do line else inspect(line) end), inspect(line)) # if Process.get(:output_std_io, false) do if is_binary(line) do IO.puts(line) else IO.inspect(line, limit: :infinity) end end send(l, {:add_line, line, side}) is_pid(log) -> send(log, {:add_line, line, side}) true -> # :ok IO.puts("log process doesn't exists: #{inspect(log)} #{inspect(line)}") end end def get_lines(log) do GenServer.call(log, :get_lines) |> Enum.sort_by(fn {x, _, _, _} -> x end) end def tail(log, num \\ 20) do name = if is_binary(log) do :"log_#{log}" else log end lines = BuffLog.get_lines(name) lines = Enum.drop(lines, max(0, Enum.count(lines) - num)) Enum.each(lines, fn line -> if is_binary(line) do IO.puts(line) else IO.inspect(line, limit: :infinity) end end) end def watch(log) do GenServer.call(log, :watch) end def watch1() do receive do {:log_notification, _, x} when is_binary(x) -> IO.puts(x) watch1() {:log_notification, _, x} -> IO.inspect(x, limit: :infinity) watch1() :exit -> :ok msg -> IO.inspect(msg, limit: :infinity) end end def start_log(acc_uuid, options \\ %{}) do log_name = :"log_#{acc_uuid}" Process.put(:bufflog, log_name) if Process.whereis(log_name) == nil do GenServer.start(BuffLog, [acc_uuid, options], name: log_name) end end def add(line, side \\ "note") do line = case line do "->" <> _ -> IO.ANSI.color(200) <> line <> IO.ANSI.reset() "<-" <> _ -> IO.ANSI.light_green() <> line <> IO.ANSI.reset() _ when is_binary(line) -> IO.ANSI.light_yellow() <> line <> IO.ANSI.reset() _ -> line end add_line(Process.get(:bufflog), line, side) end end