I have an Elixir umbrella application. The applications under the umbrella use Logger. I want to add a backend (logger_logstash_backend) for :logger
application. So, I need to add that as a dependency in deps
function in mix file.
In the outermost mix file of the umbrella application, the documentation of deps
function states:
Dependencies listed here are available only for this project and cannot be accessed from applications inside the apps folder
That means I have to add the backend module as a dependency for each of the applications under the umbrella. However, doing so causes several problems:
It becomes harder to move out the individual applications as separate libraries later.
The individual applications under the umbrella are not actually dependent on the custom :logger
backend module. They're okay with default :console
backend. But I want to have an additional backend only for prod environment. Therefore, it's more of a cross-applications concern where I'm forced to add the dependency to each application individually.
Do you know any better strategy? What is it?
Each application should have its own dependencies and configuration.
Problems that you mentioned:
- It becomes harder to move out the individual applications as separate libraries later.
If you have configurations inside each app, this actually makes it easier to move out the individual applications out of the umbrella app. As mentioned in the Elixir guides, you simply need to move the app out of the apps/
directory.
- The individual applications under the umbrella are not actually dependent on the custom :logger backend module. They're okay with default :console backend. But I want to have an additional backend only for prod environment. Therefore, it's more of a cross-applications concern where I'm forced to add the dependency to each application individually.
If the custom logger backend is required only in production environment, then the apps can add this configuration only to config/prod.exs
file and use this only in prod environment.
Umbrella apps still have global configuration, IIRC. This means that if you do config :logger, backends: [CustomBackend]
in one, you'll be configuring for them all.
With that in mind, recently I've been using two alternatives I'm happy with:
set the logger as a global dependency. I tend to use this when all the apps will always use the same backend and configuration. As an example, when I'm using the RingLogger backend and no other.
create a logs
app. This may not be acceptable depending on how you are separating the apps. But I do this when I want more granular configuration (e.g. configuring an external logging service). Usually this has extra dependencies and configuration details that are abstracted within that app and don't leak to any other. If necessary, I have all other apps depend on it explicitly. It may seem too much of a hassle but I have some issues with configuring external services in the root app. I don't feel like service-specific dependencies should be a global dependency. Instead hiding them away and abstracting those within a logs app gives transparency and allows me to swap services if necessary.
I'm actually curious about the takes on this since I've been debating on it myself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With