# LogOut
[](https://hex.pm/packages/log_out)
[](https://hex.pm/packages/log_out)
**LogOut** is a pluggable Elixir Logger backend for routing exceptions and application logs directly to team chat platforms.
It uses an `Adapter` pattern to seamlessly format Elixir logs and send them asynchronously to services like **Slack, Discord, Telegram, and Zulip**.
Because `LogOut` hooks into Elixir's native `:logger` (via `:gen_event`), it integrates perfectly with all normal `Logger.info`, `Logger.error`, and unexpected exception traces across your app. Also, it uses `Task.start/1` to dispatch HTTP requests asynchronously, meaning your Phoenix controllers or background jobs are never blocked by logging.
---
## Installation
Add `log_out` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:log_out, "~> 0.1.0"}
]
end
```
## Configuration Basics
`LogOut` runs as an extra backend for Elixir's built-in `:logger`. You configure it in your environment config (e.g., `config/prod.exs`).
```elixir
# 1. Add LogOut to your active backends
config :logger, backends: [:console, LogOut]
# 2. Configure LogOut
config :logger, LogOut,
# We recommend only forwarding :warning or :error to chat
level: :warning,
project_name: "My App Production", # Prefixes the chat messages
adapters: [
# You can configure one or multiple adapters to fire simultaneously!
{LogOut.Adapters.Slack, url: System.get_env("SLACK_WEBHOOK_URL")}
]
```
## Supported Adapters & Usage
`LogOut` provides four built-in adapters out of the box.
### Zulip (Highly Recommended for Multiple Projects)
Zulip is highly recommended because of its unique Stream/Topic threading model. Your `#alerts` stream won't become a completely unreadable wall of text if your database goes down, because individual project names are grouped by Topic.
```elixir
config :logger, LogOut,
adapters: [
{LogOut.Adapters.Zulip,
url: "https://zulip.example.com",
bot_email: "bot@example.com",
bot_api_key: System.get_env("ZULIP_API_KEY"),
stream: "alerts",
# topic defaults to the global `project_name` if not specified
topic: "my-app-production"
}
]
```
### Telegram (Recommended for Instant Mobile Push)
```elixir
config :logger, LogOut,
adapters: [
{LogOut.Adapters.Telegram,
bot_token: System.get_env("TELEGRAM_BOT_TOKEN"),
chat_id: "-10012345678",
# message_thread_id: 123 (Optional: if using Telegram Topics in groups)
}
]
```
### Discord / Slack
Both use standard generic Incoming Webhook URLs for channels.
```elixir
config :logger, LogOut,
adapters: [
{LogOut.Adapters.Discord, url: System.get_env("DISCORD_WEBHOOK_URL")},
{LogOut.Adapters.Slack, url: System.get_env("SLACK_WEBHOOK_URL")}
]
```
---
## Filtering Noise
If a specific library or background worker is generating `Logger.error` entries that you want to ignore, you can use Elixir's built-in Logger filtering system:
```elixir
# Filter out noisy events before they ever reach LogOut
config :logger, LogOut,
level: :warning,
project_name: "App",
adapters: [...],
metadata_filter: [application: :my_app] # Only send logs from :my_app
```
## Writing Your Own Adapter
If you need to send logs to Mattermost, Teams, or an internal HTTP endpoint, writing a custom adapter is trivial.
```elixir
defmodule MyMattermostAdapter do
@behaviour LogOut.Adapter
@impl true
def send_message(log_event, config) do
# log_event = %{level: :error, msg: {:string, "Bad connection"}, meta: %{...}}
# Optional helpers bundled with LogOut
formatted_msg = LogOut.format_message(log_event)
emoji = LogOut.get_emoji(log_event.level)
# Use any HTTP client to fire off the web request
Req.post!("https://mattermost...", json: %{text: formatted_msg})
end
end
```
Then just add your module to the adapters list:
```elixir
config :logger, LogOut,
adapters: [
{MyMattermostAdapter, some_config_key: "value"}
]
```
## Documentation
Full documentation can be found at [https://hexdocs.pm/log_out](https://hexdocs.pm/log_out).