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

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
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
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews