Can't get recon_trace to work with anon function

Background

I have an app constantly logging the following error:

=ERROR REPORT==== 18-Jun-2019::11:30:55.362697 ===
Unexpected message: {#Ref<0.1587460723.3280207877.77462>,badarg}

At first I thought that one of our GenServers with a handle_info callback was missing a clause. But now after some research I concluded that the process receiving this message doesn’t even have a handle_info callback implemented because I used recon_trace to spy on all modules that have implementations of handle_info and none was receiving messages like the one above.

Objective

My objective is now to, given a module, check for all the messages it receives, and print those who contain a tuple with the following format: {reference, any}

To achieve this I am trying to use recon_trace:

filter = fn args ->
  has_tuples? = Enum.any?(args, fn x ->
    case x do
      {ref, _reason} when is_reference(ref) -> true
       _ -> false
    end
  end)

  case has_tuples? do
    true  -> :ok
    false -> :nok
  end
end

:recon_trace.calls({hd(mods), :_, filter}, 10)

Error

However I can’t get this code to run due to the following error:

Error: fun with body matching ('=' in body) is illegal as match_spec
** (CaseClauseError) no case clause matching: {:error, :transform_error}
    (recon) src/recon_trace.erl:494: :recon_trace.validate_tspec/3
    (recon) src/recon_trace.erl:424: :recon_trace."-trace_calls/3-lc$^0/1-0-"/2
    (recon) src/recon_trace.erl:426: :recon_trace.trace_calls/3

What am I doing wrong?

  • Args is either the arity of a function ( 0..255 ), a wildcard pattern ( '_' ), a match specification, or a function from a shell session that can be transformed into a match specification

This is from the docs of recon. I’d imagine your function does not match the last part of being able to be transformed into a matchspec. Maybe try https://github.com/ericmj/ex2ms to generate the matchspec directly.

I tried the library with the following code:

iex -S mix
import Ex2ms

fn args ->
  has_tuples? = Enum.any?(args, fn x ->
    case x do
      {ref, _reason} when is_reference(ref) -> true
       _ -> false
    end
  end)

  case has_tuples? do
    true  -> :ok
    false -> :nok
  end
end

But it returned the following output:

#Function<6.128620087/1 in :erl_eval.expr/5>

Which is not a match specification afaik.

Am I using this library incorrectly?

Just importing a module doesn’t change anything… You need to actually use the provided macros…

In your case it should be enough to replace fn by fun.

2 Likes