Adding Hyperlinks to Logger Output


/images/PMLogger.png

It would be nice to simply click on a debug message and have it open Emacs to the correct location in the corresponding file. There are a variety of ways to accomplish this, I chose to use terminal hyperlinks along with adding an Emacs URI protocol to my system.

emacs://open/?url=file://{_filename}&line=#{line_num}&column={col_num}

To appear as a link in the terminal, the URI string must appear inside a terminal hyperlink escape sequence (shown below).

'\e]8;;http://example.com\e\\This is a link\e]8;;\e\\'

I created a simple Elixir macro to add links to Logger messages. Since Elixir macros are expanded at compile time there is no run-time overhead to this approach. I made the Logger calls lazy in the macro, which means the caller can use a non lazy call and it will be optimized in this macro.

ElixirApp.PMLogger

  defmodule ElixirApp.PMLogger do
    @moduledoc false

    defmacro __using__(_opts) do
      quote do
        require Logger
        alias ElixirApp.PMLogger
      end
    end

    defmacro log(message \\ "") do
      quote do: Logger.log fn -> " \e]8;;emacs://open/?url=file://#{__ENV__.file}&line=#{__ENV__.line}&column=0\e\\#{__MODULE__}\e]8;;\e\\ : #{unquote(message)} " end 
    end

    defmacro info(message \\ "") do
      quote do: Logger.info fn -> " \e]8;;emacs://open/?url=file://#{__ENV__.file}&line=#{__ENV__.line}&column=0\e\\#{__MODULE__}\e]8;;\e\\ : #{unquote(message)} " end 
    end

    defmacro debug(message \\ "") do
      quote do: Logger.debug fn -> " \e]8;;emacs://open/?url=file://#{__ENV__.file}&line=#{__ENV__.line}&column=0\e\\#{__MODULE__}\e]8;;\e\\ : #{unquote(message)} " end 
    end

    defmacro error(message \\ "") do
      quote do: Logger.error fn -> " \e]8;;emacs://open/?url=file://#{__ENV__.file}&line=#{__ENV__.line}&column=0\e\\#{__MODULE__}\e]8;;\e\\ : #{unquote(message)} " end 
    end

  end

With this macro, hyperlinks will be shown in the Logger output. I chose to use the module name as the hyperlink text because the links themselves can be very long. You can see the link in action in the image above. In iTerm2 you hold the command key down then hover over links to see the target URI in the status bar.

To add the Emacs protocol on macOS you can try my uri-handler solution.

comments powered by Disqus