DiscoLog is easy to set up with a mix task that creates three channels for you:
#occurrences: A forum-style channel where errors are grouped by fingerprint and tagged, making it easy to track and manage them.
#info: This channel pipes the output of Logger.info directly to Discord, keeping you informed of general application events.
#error: This channel pipes the output of Logger.error. If the logger content is not an exception, it goes here; otherwise, it’s routed to #occurrences.
Additionally, DiscoLog have integration with Plug, Phoenix, LiveView, and Oban to provide extra context through :telemetry
Additionally, DiscoLog includes a :logger handler that converts exceptions into error occurrences, even for processes that lack specific integrations, such as GenServer crashes.
By using Discord, DiscoLog benefits from built-in notifications through the Discord app. Another advantage of the forum channel is the ability to prevent specific errors from triggering notifications repeatedly.
The idea for DiscoLog emerged while experimenting with Discord’s Bot API. I realized that the Discord Forum Channel type could serve as a good solution for error tracking. The primary challenge was Discord’s limited message size, but I overcame this by utilizing message attachments to handle larger payloads.
I wonder how easy an integration with tower can be so to have a tower_discord package in order to be able to report errors both to Discord and other places at the same time.
I’m not sure what value integrating with Tower brings. DiscoLog already has a logger handler, so after configuring the Logger backend, doing Logger.error(some_exception) reports the error to the Discord backend. For telemetry, I also hook them and report separately. Adding DiscoLog to your app only requires modifying the config, with no additional code changes. Additionally, we have duplicate logic in event.ex, which I need for error tracking.
I’ve only started using it but it’s been great so far. I like how setting up logging for multiple projects/environment is a matter of configuring category_id/channel_id.
I think I may have preferred starting DiscoLog under the application’s supervision tree and explicitly configuring logger handlers, but it might be too early to say
Thanks for your PR! It’s been released on Hex as version 0.6.
I considered allowing DiscoLog to start under an application’s supervision tree and using explicit logger handlers, but decided against it to keep the setup simpler. Everything started by the DiscoLog application is configurable, though, so it still allows flexibility. You can check out the setup in DiscoLog’s application module.
I’ve been looking through the code recently, and I have a feeling that it’s feasible to allow users to start discolog under their supervision tree while maintaining the default option of running it as an independent application. Basically, it should boil down to only reading from global configuration on start up and then passing it to all downstream code (logger handler, Discord.Client, etc.) through composition. So, it’s possible for users to just set enable: false in global config and attach their own logger handlers with custom configuration.
The problem is that it’s a lot of changes and I can’t think of too many use cases that it would unlock. I suppose, if you want to publish to multiple guilds or categories, that will make it possible. I’d still be happy to do this, as I just love the idea behind DiscoLog and want it to be awesome, but I don’t want to create a 1000 LOC refactoring PR out of the blue without your blessing Do you think making DiscoLog highly configurable is worth it, or would you rather shelve the idea until some time in the future?
Sure, it’s possible to achieve this without a big LOC I think.
The clean approach would be to include a Supervisor in the DiscoLog module. After that, you could run it in your application like this:
# lib/my_app/application.ex
def start(_type, _args) do
children = [
# other stuff,
{DiscoLog, Application.fetch_env!(:my_app, :disco_log)}
]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
In terms of configuration, there wouldn’t be much to change—just move the existing application logic in the supervisor. The current application would then call the supervisor instead.
For the logger handler, I think the current setup is fine. You can disable it and attach a custom handler yourself.
That said, I can’t think of specific use cases for this right now, but adding this feature would certainly make DiscoLog more flexible.
Oban is a great example of a library that give you a supervisor to start in your application.
Yeah I think that’ll work! But I was thinking about going further and support attaching multiple handlers with different configuration. Say, we want to post to different channels based on domain. We can define 2 handlers with different info_channel_id and create a handler filter that would only keep messages with that domain. This setup would require handler and it’s downstream code to rely on its own configuration and not reading from the global configuration.
Regarding the logger handler, I see some improvements that could be made.
Add the Ability to Pass a Module Function: Allow passing a module function that receives the error or info message, enabling you to dispatch logs dynamically. The routing function would process the metadata and dispatch the log accordingly.
Example:
Logger.info("✨ New User #{customer.email} created successfully.", channel: "accounts")
Logger.info("💸 Payment of 5 € succeeded from customer `#{customer.email}`", channel: "billing")
Support for Occurrences: This could also be extended to handle occurrences, but it would require extra work since the current ETS table for fingerprint only supports a single Discord channel.
Behavior for Routing: DiscoLog could ship with a Behavior to implement this feature. Additionally, the Discord client functions should be exposed.
With these improvements, I don’t see a use case for running multiple logger handlers ?
To be clear, this is an imaginary use case, I just used it as an example meant to illustrate where configurability of the current design may come short. I have no doubt that with enough configuration options DiscoLog can cover pretty much any use case in the near future and perhaps for the time being.
Changes to configuration I’m talking about is for the love of the game, really. It would just be awesome if DiscoLog could play nicely with existing logging and application configuration. Following up with Oban example, there is a single place where Oban reads configuration and this is what unlocks independent Oban instances. As I mentioned, this isn’t necessary or anything, I just think it would be neat, so don’t feel pushed to agree or even consider this!