NatureWhistle

NatureWhistle Banner

Nature Whistle CI

Let your system whisper its troubles before they become screams.

NatureWhistle is an Elixir library that listens to :telemetry events and sends alerts to collaboration tools (Slack, Microsoft Teams, generic webhooks, or the console) when metric thresholds are crossed. It also sends resolution (“calm”) notifications when a metric returns to normal.

The name combines “nature” – the author’s nickname – with “whistle”, because it sounds an alarm when something goes wrong and blows a calming note when the system recovers.

Features

Installation

Add nature_whistle to your mix.exs dependencies:

defp deps do
[
{:nature_whistle, "~> 0.1.0"}
]
end

Then run mix deps.get.

Configuration

Configuration is placed in your host application’s config/config.exs. You can define alerts, notifiers, and retry behaviour.

Basic example

import Config
config :nature_whistle,
alerts: [
%{
id: :high_memory,
event: [:vm, :memory, :total],
measurement_key: :total,
threshold: 1_073_741_824, # 1 GB
alert_message: "🚨 High memory: %{value} MB",
calm_message: "✅ Memory back to normal: %{value} MB",
cooldown_ms: 300_000, # 5 minutes
resolution_ms: 60_000, # 1 minute
notifier: :slack
}
],
notifiers: [
slack: [webhook_url: "https://hooks.slack.com/services/..."],
console: [] # optional, always available as fallback
],
retry: [
max_attempts: 3,
base_delay_ms: 1000,
max_delay_ms: 30_000
]

Alert fields

FieldRequiredDescription
idUnique identifier for this alert (used for state & cooldown).
eventTelemetry event name as a list of atoms, e.g. [:vm, :memory, :total].
measurement_key❌ (default :value)Key inside the measurements map that holds the numeric value (e.g. :duration, :total).
thresholdNumeric value that triggers the alert (when value >= threshold).
alert_messageMessage sent when threshold is crossed. Use %{value} as placeholder.
calm_messageMessage sent when metric stays below threshold for resolution_ms after a spike.
cooldown_ms❌ (default 60 000)Minimum time between repeated alert messages while the metric remains high.
resolution_ms❌ (default 60 000)Time the metric must stay below threshold before sending the calm message.
notifier❌ (default :console)One of :slack, :teams, :webhook, or :console.

Notifier configuration

Notifiers are configured under the :notifiers key. Each notifier expects a keyword list of options:

Retry settings

Under the :retry key you can configure:

Starting NatureWhistle

Add NatureWhistle.Application to your application’s supervision tree. This ensures the package is started, its ETS tables are created, and telemetry handlers are attached.

# lib/my_app/application.ex
def start(_type, _args) do
children = [
MyApp.Repo,
MyAppWeb.Endpoint,
NatureWhistle.Application # <-- add this line
]
Supervisor.start_link(children, strategy: :one_for_one)
end

Note:

nature_whistle works with any Elixir (or Erlang) application that emits :telemetry events – it does not require Phoenix. Simply add NatureWhistle.Application as a child of your application's supervision tree.

Usage

Once configured and started, nature_whistle automatically listens to telemetry events. You do not need to call any additional functions – just emit events as usual.

Emitting custom telemetry events

Your application can emit its own events, and nature_whistle will alert on them if you add a corresponding alert entry.

# Example: emit a slow query event
:telemetry.execute(
[:my_app, :db, :query],
%{duration: 650}, # value under :duration
%{query: "SELECT * FROM users"}
)

Then define an alert:

%{
id: :slow_query,
event: [:my_app, :db, :query],
measurement_key: :duration,
threshold: 500,
alert_message: "🐢 Slow query: %{value} ms",
calm_message: "✅ Query speed recovered: %{value} ms"
}

Default alerts

If you do not specify any :alerts, nature_whistle provides two built‑in alerts that use the console notifier:

This ensures the package is never idle – you will always see warnings in the logs if there is any spike.

How it works

Fault tolerance & supervision

Customising messages

Both alert_message and calm_message support the %{value} placeholder, which is replaced with the current metric value (converted to a string). Memory values for [:vm, :memory, :total] are automatically formatted as megabytes for readability. For all other metrics, the raw value is inserted as a string.

Future enhancement – A future version of nature_whistle will allow you to provide a custom formatting function per alert (e.g., converting microseconds to milliseconds, adding units). Currently, formatting is limited to built‑in VM memory conversion.

Integration with PromEx

PromEx is a powerful Elixir library that collects and exposes application metrics to Prometheus (and then to Grafana for visualisation). However, PromEx itself does not send alerts – you would need to add Prometheus + Alertmanager to get Slack or Teams notifications.

This is where nature_whistle becomes the perfect lightweight companion. Both libraries listen to the same :telemetry events, so you can run them side by side:

You get the best of both worlds: rich visualisations for debugging trends and direct, low‑latency alerts for critical spikes. No separate Alertmanager setup, no PromQL to learn. Just add nature_whistle to your supervision tree, configure your thresholds, and you’re done.

Pro tip: You can even use nature_whistle to alert on the same custom telemetry events that PromEx exposes – giving you a complete monitoring story with almost zero operational overhead.

Performance considerations

NatureWhistle is designed for low to medium telemetry volume (dozens to hundreds of events per second). It processes each event synchronously in the caller process, and HTTP alerts are sent directly from that process.

For very high‑volume systems (thousands of events per second), consider using a purpose-built observability stack like Prometheus + Alertmanager or a hosted monitoring service. A future version of NatureWhistle will introduce asynchronous processing and batching to support higher throughput. Stay tuned.

Contributing & Feedback

NatureWhistle is an open source project that thrives on community input. Whether you have a bug report, a feature request, a question, or want to contribute code, you are very welcome.

Let’s make nature_whistle the go‑to alerting toolkit for the Elixir ecosystem. 🌿🔊