Skip to content

Fix submenu id assign #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
360 changes: 360 additions & 0 deletions lib/debugger.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,360 @@
defmodule ExSni.Debugger do
@moduledoc """
Debugger module that attaches to telemetry events.
Configurable using the EXSNI_DEBUG environment variable, with the following events,
given as a comma-separated list:
- menu_diff - Outputs the old menu structure, the new menu structure, and the diff result
- menu_update - Outputs branch and menu update structures
- menu_set - Outputs the structure that is set as the current menu
- dbus_method - Outputs D-Bus method calls and replies
- dbus_signal - Outputs D-Bus signals sent
- menu - alias for "menu_diff,menu_update,menu_set" (all menu events)
- dbus - alias for "dbus_method,dbus_signal" (all dbus events)
- all - alias for "menu,dbus" (all events)
"""
require Logger

@debug_env_name "EXSNI_DEBUG"

def init(_opts \\ []) do
get_debug_options()
|> Enum.each(fn metric ->
unique_id =
metric
|> Enum.map(&Atom.to_string/1)
|> Enum.join("_")

:telemetry.attach(
unique_id,
metric,
&handle_event/4,
nil
)
end)
end

# Menu Diff telemetry
def handle_event(
[:ex_sni, :menu_diff, :branch],
_metrics,
%{
branch: branch,
description: description,
layout_changes: layout_changes,
items_updated_properties_signal: item_updates,
params: _params,
new_root: new_root,
old_root: old_root
},
_config
) do
xml_new_root = ExSni.Menu.Debug.debug_root(new_root)
xml_old_root = ExSni.Menu.Debug.debug_root(old_root)

{"ex_sni", [{"timestamp", "#{now()}"}],
[
{"menu_diff",
[
{"branch", "#{branch}"},
{"layout_changes", "#{inspect(layout_changes)}"},
{"item_updates", "#{inspect(item_updates)}"},
{"description", "#{description}"}
],
[
"<old_root>#{xml_old_root}</old_root><new_root>#{xml_new_root}</new_root>"
]}
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :menu_diff, :result],
_metrics,
%{
branch: branch,
description: description,
layout_changes: layout_changes,
items_updated_properties_signal: item_updates,
code: code,
node: node
},
_config
) do
xml_node = ExSni.Menu.Debug.debug_root(node)

{"ex_sni", [{"timestamp", "#{now()}"}],
[
{"menu_diff_result",
[
{"branch", "#{branch}"},
{"code", "#{code}"},
{"layout_changes", "#{inspect(layout_changes)}"},
{"item_updates", "#{inspect(item_updates)}"},
{"description", "#{description}"}
],
[
"<node>#{xml_node}</node>"
]}
]}
|> Saxy.encode!()
|> _debug()
end

# ExSni.Menu.Server metrics

def handle_event(
[:ex_sni, :do_menu_update],
_metrics,
%{
branch: branch,
description: description,
menu_queue: menu_queue,
returns: returns,
new_root: new_root,
old_root: old_root
},
_config
) do
xml_new_root =
if is_atom(new_root) do
Atom.to_string(new_root)
else
ExSni.Menu.Debug.debug_root(new_root)
end

xml_old_root = ExSni.Menu.Debug.debug_root(old_root)

{"ex_sni", [{"timestamp", "#{now()}"}],
[
{"do_menu_update",
[
{"branch", "#{branch}"},
{"menu_queue", "#{inspect(menu_queue)}"},
{"returns", "#{inspect(returns)}"},
{"description", "#{description}"}
],
[
"<old_root>#{xml_old_root}</old_root><new_root>#{xml_new_root}</new_root>"
]}
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :send_dbus_signal],
_metrics,
%{signal: "LayoutUpdated", args: args},
_config
) do
xml_updates =
args
|> ExSni.Menu.Debug.parse_signal_layout_updated()
|> Saxy.encode!()

{"dbus", [{"timestamp", "#{now()}"}],
[
"#{xml_updates}"
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :send_dbus_signal],
_metrics,
%{signal: "ItemsPropertiesUpdated", args: args},
_config
) do
xml_updates =
args
|> ExSni.Menu.Debug.parse_signal_items_properties_updated()
|> Saxy.encode!()

{"dbus", [{"timestamp", "#{now()}"}],
[
"#{xml_updates}"
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :dbus_method, :call],
_metrics,
%{method: "GetLayout", args: {id, depth, properties}},
_config
) do
xml_item =
{"get_layout",
[{"item_id", "#{id}"}, {"depth", "#{depth}"}, {"properties", Enum.join(properties, ",")}],
[]}
|> Saxy.encode!()

{"dbus", [{"timestamp", "#{now()}"}],
[
{"method_call", [{"name", "GetLayout"}], ["#{xml_item}"]}
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :dbus_method, :call],
_metrics,
%{method: "GetGroupProperties", args: {ids, properties}},
_config
) do
xml_item =
{"get_group_properties",
[{"ids", Enum.join(ids, ",")}, {"properties", Enum.join(properties, ",")}], []}
|> Saxy.encode!()

{"dbus", [{"timestamp", "#{now()}"}],
[
{"method_call", [{"name", "GetGroupProperties"}], ["#{xml_item}"]}
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :dbus_method, :reply],
_metrics,
%{method: "GetLayout", response: response},
_config
) do
xml_layout =
response
|> ExSni.Menu.Debug.parse_layout_response()
|> Saxy.encode!()

{"dbus", [{"timestamp", "#{now()}"}],
[
{"method_reply", [{"name", "GetLayout"}], ["#{xml_layout}"]}
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event(
[:ex_sni, :dbus_method, :reply],
_metrics,
%{method: "GetGroupProperties", response: response},
_config
) do
xml_properties =
response
|> ExSni.Menu.Debug.parse_get_group_properties()
|> Saxy.encode!()

{"dbus", [{"timestamp", "#{now()}"}],
[
{"method_reply", [{"name", "GetGroupProperties"}], ["#{xml_properties}"]}
]}
|> Saxy.encode!()
|> _debug()
end

def handle_event([:ex_sni, :set_current_menu], _metrics, %{root: root}, _config) do
xml_new_root = ExSni.Menu.Debug.debug_root(root)

{"ex_sni", [{"timestamp", "#{now()}"}],
[
{"set_current_menu", [],
[
"#{xml_new_root}"
]}
]}
|> Saxy.encode!()
|> _debug()
end

defp _debug(str) do
Logger.debug(str)
end

defp now() do
DateTime.to_unix(DateTime.utc_now())
end

# Options parsing

defp get_debug_options() do
System.fetch_env(@debug_env_name)
|> case do
{:ok, value} ->
value
|> String.split(",", trim: true)

:error ->
[]
end
|> process_opts()
end

defp process_opts(opts) do
opts
|> process_filter_opts()
|> Enum.reduce([], &env_opt_to_event/2)
end

defp process_filter_opts(opts) do
if env_opts_contains?(opts, "all") do
["all"]
else
opts =
if env_opts_contains?(opts, "menu") do
Enum.reject(opts, &(&1 in ["menu_diff", "menu_update", "menu_set"]))
else
opts
end

opts =
if env_opts_contains?(opts, "dbus") do
Enum.reject(opts, &(&1 in ["dbus_method", "dbus_signal"]))
else
opts
end

opts
end
end

defp env_opts_contains?(opts, what) do
Enum.any?(opts, &(&1 == what))
end

defp env_opt_to_event("all", acc) do
Enum.reduce(["menu", "dbus"], acc, &env_opt_to_event/2)
end

defp env_opt_to_event("menu", acc) do
Enum.reduce(["menu_diff", "menu_update", "menu_set"], acc, &env_opt_to_event/2)
end

defp env_opt_to_event("menu_diff", acc) do
[[:ex_sni, :menu_diff, :branch], [:ex_sni, :menu_diff, :result] | acc]
end

defp env_opt_to_event("menu_update", acc) do
[[:ex_sni, :do_menu_update] | acc]
end

defp env_opt_to_event("menu_set", acc) do
[[:ex_sni, :set_current_menu] | acc]
end

defp env_opt_to_event("dbus", acc) do
Enum.reduce(["dbus_method", "dbus_signal"], acc, &env_opt_to_event/2)
end

defp env_opt_to_event("dbus_method", acc) do
[[:ex_sni, :dbus_method, :call], [:ex_sni, :dbus_method, :reply] | acc]
end

defp env_opt_to_event("dbus_signal", acc) do
[[:ex_sni, :send_dbus_signal] | acc]
end
end
3 changes: 3 additions & 0 deletions lib/ex_sni.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule ExSni do

alias ExSni.Bus
alias ExSni.{Icon, Menu}
alias ExSni.Debugger

def start_link(init_opts \\ [], start_opts \\ []) do
Supervisor.start_link(__MODULE__, init_opts, start_opts)
Expand All @@ -22,6 +23,8 @@ defmodule ExSni do
menu: menu_server_pid
}

Debugger.init()

children = [
{Registry, keys: :unique, name: ExSniRegistry},
%{
Expand Down
Loading