How to trace a GenServer’s Execution? Elixir

Enable tracing using the debug option.

This article is for beginners especially who have been started playing with GenServer .

Today, you are going to build an OTP server and you will trace the server using simple technique. This is not a technique, it is an option while calling the start_link/3 function.

Talk is cheap, lets code it.

What we do here ?

We together implement the STACK server and will trace that server. 
As you know stack is a data structure based on the concept of first in last out or last in first out.

I’ll try to keep this as simple as possible with out dwelling in over engineering. Our ultimate goal is to understand the concept.

stack.ex

Create a file stack.ex using your favourite editor. Here, I use vim

$ vim stack.ex

In elixir , we usually name our module with the name of the file. It is a general convention to avoid confusion. So, create a module named Stack with the following code.

Our Stack server is very simple. However, I keep talking few words about the code.

Please make a note that it is not a production grade code. I used list concatenation at end of the list. It is better performed by adding element to the head section like [new_elem|state] however, you need to change some code logic. So, I did that purposely to bring the idea of element is adding at last position and it is get popped first. In production code you need to reverse the logic as lists in elixir implements linked_lists behavior.

Thanks to Hubert Pompecki for noticing this as it may result in miss guiding the beginners.

The very first line of code use GenServer usually adds up the OTP GenServer behaviour to our module Stack . It also means we don’t have to define every callback in our module — the behaviour defines defaults for them all. We can just override the things we needed.

When the client makes a synchronous request by using GenServer.call , the pattern matched handle_call callback is triggered in our GenServer . The server receives three parameters and passed them to the callback definition.

  1. Client message
  2. Pid of the client
  3. Current state of the server in order.

We simply return a tuple with three elements {:reply, <return_value>, <new_state> } to the OTP. The Otp will return <return_value> to the client.

That is how the flow will be.

client -> GenServer -> OTP -> client

There are other callback functions. I cannot explain them here. You can read them by own.

Execution & Tracing

Before running the following command, make sure you are in the same directory of where the file stack.ex exists.

$ iex stack.ex

It opens the interactive shell environment along with loading our module Stack .

Starting the server and enable tracing using debug option

iex> {:ok, pid } = GenServer.start_link(Stack, [1,2,3,4,5],[debug: [:trace]])

The GenServer.start_link third parameter takes few options. So, we use debug: [:trace] for debugging. This option will log all the messages flow to the console. It clearly gives you information like who is sending the message and to whom it was sent.

Give a try by calling server.

Get state

iex> GenServer.call pid, :get

Pop message

iex> GenServer.cast pid, :pop

Put message

iex> GenServer.cast pid, {:put, 6}

Tracing Existing Server

In the above tracing style, we added an option debug: [:trace] as the third parameter while calling the GenServer.start_link definition.

Now, we will create the process with out that option. So, it will be the existing server and will trace that server manually.

We will follow same process except calling the GenServer.start_link

$ iex stack.ex

It loads the module into iex session.

iex> {:ok,pid} = GenServer.start_link(Stack,[1,2,3,4,5])

If you observe, we are not passing the third option here.

Lets call the server

iex> GenServer.call pid, :get
[1,2,3,4,5]

It just returns the state with out any debugging information.

Tracing Manually

Now we will trace the existing server using :sys.trace

iex> :sys.trace pid, true
:ok

The :sys.trace takes two parameters pid of the existing server to trace and second parameter is a boolean true means enable tracing and false means disable tracing.

Now, call the other server calls you will see the debug information like we did in first section of tracing using option as third parameter.

Disable Tracing

iex> :sys.trace pid, false

Check the following screen shot

This is just another way to enable and disable tracing the existing server using pid .

Hope you like this. Feel free to share and let others get benefited from this.

if worth_clapping, do: CLAP, else: nil

Happy Coding :) & Keep ever smiling.

Like what you read? Give Blackode a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.