diff --git a/lib/ring_logger.ex b/lib/ring_logger.ex index 7c8a148..772eae0 100644 --- a/lib/ring_logger.ex +++ b/lib/ring_logger.ex @@ -57,6 +57,7 @@ defmodule RingLogger do alias RingLogger.Autoclient alias RingLogger.Server + alias RingLogger.Viewer @typedoc "Option values used by the ring logger" @type server_option() :: @@ -193,11 +194,17 @@ defmodule RingLogger do @spec tail(non_neg_integer(), client_options()) :: :ok def tail(n, opts), do: Autoclient.tail(n, opts) + @doc """ + Starts the Ring Logger Viewer TUI app on the current prompt with intial arguments + """ + @spec viewer(String.t()) :: :ok + defdelegate viewer(cmd_string), to: Viewer, as: :view + @doc """ Starts the Ring Logger Viewer TUI app on the current prompt """ @spec viewer() :: :ok - def viewer(), do: RingLogger.Viewer.view() + defdelegate viewer(), to: Viewer, as: :view @doc """ Reset the index into the log for `next/1` to the oldest entry. diff --git a/lib/ring_logger/viewer.ex b/lib/ring_logger/viewer.ex index 8cf3225..e1168ff 100644 --- a/lib/ring_logger/viewer.ex +++ b/lib/ring_logger/viewer.ex @@ -42,7 +42,6 @@ defmodule RingLogger.Viewer do @level_strings ["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"] @microsecond_factor 1_000_000 - @seconds_in_year 365 * 24 * 60 * 60 @seconds_in_month 30 * 24 * 60 * 60 @seconds_in_week 7 * 24 * 60 * 60 @@ -50,8 +49,8 @@ defmodule RingLogger.Viewer do @seconds_in_hour 60 * 60 @seconds_in_minute 60 - @spec view() :: :ok - def view() do + @spec view(String.t()) :: :ok + def view(cmd_string \\ "") do screen_dims = get_screen_dims() if screen_dims.w <= @min_width do @@ -62,9 +61,7 @@ defmodule RingLogger.Viewer do raise "Sorry, your terminal needs to be at least #{@min_height} rows high to use this tool!" end - IO.puts("Starting RingLogger Viewer...") - - @init_state |> get_log_snapshot() |> loop() + parse_launch_cmd(cmd_string, @init_state) |> get_log_snapshot() |> loop() end @doc """ @@ -88,6 +85,11 @@ defmodule RingLogger.Viewer do # apply_command_parser/3 returns state by applying single filter defp apply_command_parser(cmd_char, cmd, state) do case {cmd_char, cmd, state} do + {"l", cmd, state} -> set_log_level(cmd, state) + {"a", cmd, state} -> add_remove_app(cmd, state) + {"r", _cmd, _state} -> %{@init_state | current_page: 0} + {"g", cmd, state} -> add_remove_grep(cmd, state) + {"q", _cmd, state} -> %{state | running: false} {"d", cmd, state} -> add_time_log(cmd, state) _ -> state end @@ -339,13 +341,21 @@ defmodule RingLogger.Viewer do inspect_entry(index, state, current_logs) state else - first_char = String.at(cmd_string, 0) |> String.downcase() - command(first_char, cmd_string, state) + handle_commands(cmd_string, state, String.contains?(cmd_string, ";")) end %{new_state | last_cmd_string: cmd_string} end + defp handle_commands(cmd_string, state, true) do + parse_launch_cmd(cmd_string, state) |> get_log_snapshot() + end + + defp handle_commands(cmd_string, state, false) do + cmd = String.at(cmd_string, 0) |> String.downcase() + command(cmd, cmd_string, state) + end + defp command(cmd_exit, _cmd_string, state) when cmd_exit in ["e", "q"] do %{state | running: false} end @@ -531,6 +541,12 @@ defmodule RingLogger.Viewer do %{state | applications_filter: [app_atom | state.applications_filter], current_page: 0} end + # accept the series of applications if entered by user and convert them to atoms list + [_cmd | app_strings] -> + app_atom = Enum.map(app_strings, &String.to_existing_atom/1) + + %{state | applications_filter: app_atom, current_page: 0} + _ -> state end @@ -567,6 +583,7 @@ defmodule RingLogger.Viewer do "\t(g)rep [regex/string] - regex/string search expression, leaving argument blank clears filter.\n", "\t(l)evel [log_level] - filter to specified level (or higher), leaving level blank clears the filter.\n", "\t(a)pp [atom] - adds/remove an atom from the 'application' metadata filter, leaving argument blank clears filter.\n", + "\t(;)concat commands [example usage] - a telit_modem; g some_name \n", "\t(d)ate [start_time] [duration] - show entries at specified time and duration. [ex. d 2024-12-25 10:20:01 P0Y0M0W0DT0H1M0S]\n", "\t0..n - input any table index number to fully inspect a log line, and view its metadata.\n", "\t(e)xit or (q)uit - closes the log viewer.\n", diff --git a/test/ring_logger/viewer_test.exs b/test/ring_logger/viewer_test.exs index 1b4bdd5..9421613 100644 --- a/test/ring_logger/viewer_test.exs +++ b/test/ring_logger/viewer_test.exs @@ -52,6 +52,31 @@ defmodule RingLogger.ViewerTest do {:ok, %{state: nil}} end + test "a command with single application using parse_launch_cmd/2" do + cmd_string = "a blofeld_firmware" + state = Viewer.parse_launch_cmd(cmd_string, @init_state) + assert [:blofeld_firmware] == state.applications_filter + end + + test "a command with multiple applications using parse_launch_cmd/2" do + cmd_string = "a blofeld_firmware telit_modem nil $kmsg" + state = Viewer.parse_launch_cmd(cmd_string, @init_state) + assert [:blofeld_firmware, :telit_modem, nil, :"$kmsg"] == state.applications_filter + end + + test "Viewer.parse_launch_cmd/2 with multiple commands ; separated" do + cmd_string = "a telit_modem; l debug" + state = Viewer.parse_launch_cmd(cmd_string, @init_state) + assert [:telit_modem] == state.applications_filter + assert :debug == state.lowest_log_level + end + + test "Viewer.parse_launch_cmd/2 with invalid format" do + cmd_string = "r l debug; a" + state = Viewer.parse_launch_cmd(cmd_string, @init_state) + assert [] == state.applications_filter + end + test "goto date command without duration argument [d 2024-12-25] " do cmd_string = "d 2024-12-25" state = Viewer.parse_launch_cmd(cmd_string, @init_state)