larshei

larshei

I have a number of different notifications, each identified by an id (example “ticket_closed”).

This ID can later be used to select the right E-Mail Template for the right language etc.

So basically, the recipient, the notification id and some metadata is stored as an Oban Job,
and the E-Mail is sent from there.

I would love to automatically extract all the available notification IDs, for 2 reasons:

  1. I could then check if I have an E-Mail template for each ID and
  2. I can check if any references to notification IDs are actually referring to existing IDs

I am pretty sure this is a rather simple task with mix/elixir, but so far I could not figure it out.

How could I extract all calls to a function and the functions n-th argument?


I found the tracers: compile options, however I am not sure how to add a Tracer inside a project that is meant to trace the project itselft (and would therefore needs itself compiled before it can compile itself?)

Showing Posts 1 to 6

alvises

alvises

Do you want trace function calls of a running app which you have access to? Or is it something you want to add to the code of your app which you’ll then deploy and run?
Can you please post an example of the code and function calls you want to trace?

larshei

larshei OP

He @alvises, thanks for the reply.

I do not want any runtime tracing.

It would be great to find all functions calls for

Notifications.External.schedule(
  reporting_user.id,
  link_to(helpdesk_ticket),
  :ticket_updated,          # Notification ID
  metadata
)

and extract the third argument Notification ID into a list.

LostKobrakai

LostKobrakai

Boundary seems to use a custom compiler (Mix.Task.Compiler implementation) which registeres itself as the tracer module. That probably makes mix load that module, before compilation of the project itself.

alvises

alvises

@larshei I just saw you don’t need a tracer, you can ignore the post below (I didn’t find a way to delete my post :sweat_smile: )


For debugging purpose, for an app at runtime, I’ve used on a running distributed cluster the :dbg module, which is really simple to use.

# tracing handler
handler = fn {_, pid, _, {module, fun, args}, timestamp}=_data, trace_name ->
    IO.inspect({pid, module, fun, args, timestamp, trace_name})
end

# Start tracer with a handler
:dbg.tracer(:process, {handler, "my tracer"})

#  trace pattern. This function enables call trace for one or more functions.
:dbg.tp(String, :downcase, 1, [])

# traces :all
# :all -> All processes and ports in the system as well as all processes and ports created hereafter are to be traced.
# :call -> traces global function calls for the process according to the trace patterns set in the system
# :timestamp -> Includes a time stamp in all trace messages.
:dbg.p(:all, [:call, :timestamp])
iex> String.downcase("Hello")
{#PID<0.111.0>, String, :downcase, ["hello"], {1704, 212048, 422855},
 "my tracer"}
"hello"
dimitarvp

dimitarvp

You can try using GitHub - ast-grep/ast-grep: ⚡A CLI tool for code structural search, lint and rewriting. Written in Rust · GitHub.

Given this input on my machine:

# Put this in f.ex. `test.ex`

defmodule Notifications.External do
  def schedule(user_id, link, notification_type, metadata) do
    IO.puts(
      "Scheduling stuff for user #{user_id}: " <>
        " link=#{link}, " <>
        "notification_type=#{notification_type}, " <> "metadata=#{inspect(metadata)}"
    )
  end
end

defmodule UserModuleOne do
  def function_one() do
    Notifications.External.schedule(1, "nope", :ticket_created, %{})
  end
end

defmodule UserModuleTwo do
  def function_two() do
    Notifications.External.schedule(2, "never", :ticket_updated, %{})
  end
end

defmodule UserModuleThree do
  def function_three() do
    Notifications.External.schedule(3, "not_happening", :ticket_closed, %{})

    task1 =
      Task.async(fn ->
        Notifications.External.schedule(4, "gone", :ticket_removed, %{})
      end)

    task2 =
      Task.async(fn ->
        Notifications.External.schedule(5, "you_serious?", :ticket_closed, %{})
      end)

    Task.await_many([task1, task2])
  end
end

Then you just run this:

sg -l ex -p 'Notifications.External.schedule($USER_ID, $LINK, $TYPE, $METADATA)' --rewrite '$TYPE' --json=compact | jq -r '.[] | .replacement' | sort | uniq

And that gives you:

:ticket_closed
:ticket_created
:ticket_removed
:ticket_updated

NOTE: it’s not perfect f.ex. if you have code that does alias Notifications.External and then calls External.schedule(...) then this incantation will not catch it. Though you can also make variants for any levels of nesting i.e. replace the pattern Notifications.External.schedule($USER_ID, $LINK, $TYPE, $METADATA) with External.schedule($USER_ID, $LINK, $TYPE, $METADATA) and you should be good. (And then you should be doing a union of all these results which is pretty easy with cat and then doing sort | uniq again.)

larshei

larshei OP

That is veeerry cool and will for sure be added to my list of tools.

This can get the job done I think, will try in a bit.

I am still curious about an erlang/elixir solution.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews