When I teach OTP I always show observer application. Observer is a graphical user interface capable of displaying supervision trees and providing information about processes. It is really cool to show how processes get restarted and what structure they follow. It is also suitable for using with production systems too!

Erlang example for teaching purposes

You can start observer by typing this inside Erlang shell.

observer:start().

Cowboy and ranch are great examples of using OTP principles in action.

WARNING: You need at least Erlang 18 installed to work with cowboy examples from master.

git clone https://github.com/ninenines/cowboy.git cd cowboy/examples/rest_hello_world make run (rest_hello_world_example@127.0.0.1)1 observer:start(). ** exception error: undefined function observer:start/0

You can easily start the example but not observer.

Cowboy uses erlang.mk to build the apps. It automatically pulls dependencies, compiles code and generates a release. Releases are self contained packages that include Erlang. They can be copied to another server and they should run fine even if Erlang is not installed there (as long as the other server has the same CPU architecture). They also strip all unnecessary applications to make the final output lightweight. This includes observer.

Releases are great for deploying to production but for teaching purposes I would like to use observer with the generated release. How can I do that? After running make run for the first time, ebin directory is created. Edit file ebin/rest_hello_world.app like this:

{applications, [kernel,stdlib,cowboy,runtime_tools,wx,observer]},

Those three applications: runtime_tools, wx and observer are all you need to launch observer gui. Just type make run again. For producation systems you probably don’t want to include entire observer with wx widgets. It would be better to leave out the graphical part and just add bare minimum to the release so we can inspect it from outside. Lets do it this time with an Elixir example.

Elixir example for production purposes

We can apply similar trick. Lets build an Elixir release using exrm. After adding it as dependency we can run:

MIX_ENV=prod mix compile MIX_ENV=prod mix release rel/my_app_name/bin/my_app_name console

This should result in something like this:

iex(my_app_name@MacBook-Pro-Tomasz)1 Node.get_cookie :my_app_name iex(my_app_name@MacBook-Pro-Tomasz)2 :observer.start ** (UndefinedFunctionError) undefined function :observer.start/0 (module :observer is not available)

As before our release stripped all additional stuff. This time instead of adding all three applications needed to start observer, lets only add bare minimum that will enable inspecting running node from outside. Inside mix.exs application section add :runtime_tools :

applications: [:phoenix, :phoenix_html, :cowboy, :logger, :gettext, :phoenix_ecto, :postgrex, :runtime_tools]]

Now repeat those three steps:

MIX_ENV=prod mix compile MIX_ENV=prod mix release rel/my_app_name/bin/my_app_name console

But this time open another iex console starting completely different Erlang node:

iex --sname watcher --cookie my_app_name iex(watcher@MacBook-Pro-Tomasz)1 :net_adm.ping :"my_app_name@MacBook-Pro-Tomasz" :pong iex(watcher@MacBook-Pro-Tomasz)2 :observer.start :ok

Now in observer choose from menu Nodes and then my_app_name@MacBook-Pro-Tomasz . Adding just one application to our release (the :runtime_tools ) enabled us to connect to our release from outside and start inspecting it! Runtime tools is an application that delivers “low footprint tracing/debugging tools suitable for inclusion in a production system”.

If you want to play with it, try going to Applications tab. You can right click on any process and kill it with arbitrary reason. What happens with children PIDs?