Skip to content

Conversation

solnic
Copy link
Collaborator

@solnic solnic commented Jan 29, 2025

This adds otp_apps config option which is then used to auto-discover module names for the in_app_module_allow_list option.

Closes #800

@solnic solnic linked an issue Jan 29, 2025 that may be closed by this pull request
@solnic solnic force-pushed the solnic/800-better-in_app_module_allow_list-default branch from eeede8c to aa7273a Compare January 29, 2025 14:33
@solnic solnic force-pushed the solnic/800-better-in_app_module_allow_list-default branch from aa7273a to 7c2ce0e Compare January 30, 2025 13:06
@solnic solnic force-pushed the solnic/800-better-in_app_module_allow_list-default branch from 7c2ce0e to 901d184 Compare January 30, 2025 13:09
@solnic solnic marked this pull request as ready for review January 30, 2025 13:27
@solnic solnic requested a review from whatyouhide January 30, 2025 13:27
@sl0thentr0py
Copy link
Member

sl0thentr0py commented Feb 3, 2025

so if I understand correctly, the user will still have to supply these values?
Is there no way to just detect a project root and just use that so that it works ootb?
We really want a good ootb experience here, that's kinda important.

Copy link
Member

@sl0thentr0py sl0thentr0py left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can merge this but let's also please make the ootb experience possible

@solnic
Copy link
Collaborator Author

solnic commented Feb 3, 2025

so if I understand correctly, the user will still have to supply these values?

No, the user would only have to provide names of applications that should be considered when auto-discovering the modules. For example if you're building an app called Blog and there's a corresponding :blog OTP app, then you just configure it in otp_apps: [:blog] and every module from this app will be added to in_app_module_allow_list setting.

@sl0thentr0py
Copy link
Member

yes but that's still manual, why cannot we just detect a project root like other SDKs? we want good default ootb stacktraces

@solnic
Copy link
Collaborator Author

solnic commented Feb 3, 2025

@sl0thentr0py due to Elixir limitations, it cannot provide us with this information in a released Elixir app, so it does work in dev env, but not released prod.

@sl0thentr0py
Copy link
Member

sl0thentr0py commented Feb 3, 2025

okay but from here
#800 (comment)

If yes, then we get all the apps from the umbrella and do what's described below, otherwise just do it for the root app.

all the apps are already in the mix config, why do we ask for them again in a separate config?

@solnic
Copy link
Collaborator Author

solnic commented Feb 3, 2025

okay but from here #800 (comment)

If yes, then we get all the apps from the umbrella and do what's described below, otherwise just do it for the root app.

all the apps are already in the mix config, why do we ask for them again in a separate config?

It's explained here #854 (comment)

@solnic solnic requested a review from whatyouhide February 6, 2025 11:29
Copy link
Collaborator

@whatyouhide whatyouhide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to mention the new option in :in_app_module_allow_list too

@solnic solnic requested a review from whatyouhide February 6, 2025 15:57
@whatyouhide whatyouhide merged commit fbbf707 into master Feb 9, 2025
3 of 4 checks passed
@whatyouhide whatyouhide deleted the solnic/800-better-in_app_module_allow_list-default branch February 9, 2025 09:38
@Miradorn
Copy link
Contributor

Miradorn commented Apr 1, 2025

Hey, just tried this new option and I really want to love it, but it might have one problem (maybe special for us): previously the list was something like 12 entries for us due to the "greedy" nature of it, using the new option the list now has ~25k entries needing something like 1.5 mb. I'm wondering if it would be reasonable to generate the modules also in a more "prefix" way to avoid this problem?

@whatyouhide
Copy link
Collaborator

@Miradorn can't you override the current option ([]) and keep the old option around?

@Miradorn
Copy link
Contributor

Miradorn commented Apr 1, 2025

Sorry I wasn't clear enough. I wanted to migrate to the new options since it seems a lot clearer to me (and also avoids possibly forgetting to add new module namespaces when they get added in the future).
There is no problem when I'm not using the new option, I'd just prefer to migrate to it :D

@whatyouhide
Copy link
Collaborator

@Miradorn your use case sounds like you might be better off with the old prefix-based option to me?

@Miradorn
Copy link
Contributor

Miradorn commented Apr 4, 2025

@whatyouhide Hi again and sorry for picking this up again, I just couldn't stop thinking about this since something seemed wrong to me:

I think there might be actually a somewhat easy optimization in here from which everybody might benefit:
Sort the list of modules and only keep the shortest Prefixes that are part of the list. Or stated the other way: throwing away all modules away that are a submodule of a module in the list. In our case that reduces the list of modules from ~12500 entries to 800. Since the matching algorithm is greedy it should change exactly nothing semantic wise, it might improve performance (only scanning the small list) and have at least a small memory imapct :D

If you agree i could prepare an MR including the logic, probably something like (thanks to chatgpt :D):
If you say the optimization is not worth it I'll leave it at that. Thanks again!

defmodule ModulePrefixFilter do
  def filter_shortest_prefixes(modules) do
    modules
    |> Enum.sort_by(&module_name_to_string/1)
    |> filter_prefixes([])
  end

  defp filter_prefixes([], acc), do: Enum.reverse(acc)

  defp filter_prefixes([head | tail], acc) do
    head_str = module_name_to_string(head)
    if Enum.any?(acc, fn existing_module ->
         existing_module_str = module_name_to_string(existing_module)
         String.starts_with?(head_str, existing_module_str)
       end) do
      filter_prefixes(tail, acc)
    else
      filter_prefixes(tail, [head | acc])
    end
  end

  defp module_name_to_string(module) when is_atom(module) do
    module
    |> Atom.to_string()
    |> String.replace(~r{\.}, ".")
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Better :in_app_module_allow_list default
4 participants