How to Monitor Slime with Vigilmon
Slime is a Slim/HAML-inspired template engine for Elixir and Phoenix. It replaces HEEx's angle-bracket syntax with indentation-based whitespace-significant markup — less ceremony, cleaner structure, and a familiar feel for developers coming from Ruby on Rails.
Slime handles rendering. It does not tell you whether a rendered page is returning HTTP 200, whether a template is crashing on a missing assign, or whether your app is reachable from the internet. Those are external concerns — the kind Vigilmon was built for.
This tutorial covers:
- A health check endpoint alongside typical Phoenix/Slime setup
- HTTP uptime monitoring with Vigilmon
- Keyword checks to verify rendered output actually contains expected content
- Alerts when template errors cause silent 500s
Why Monitor Slime?
| Failure mode | Symptom without monitoring |
|---|---|
| Missing assign causes KeyError | 500 rendered as HTML; no external alert |
| Slime compilation error after deploy | All routes rendering that template return 500 |
| App unreachable | Templates irrelevant; users see nothing |
| Slow render from expensive assigns | High p95 latency; users see a slow site |
| Static asset pipeline broken | Template renders but CSS/JS references 404 |
Step 1: Add Slime and a health check endpoint
Install Slime:
# mix.exs
{:slime, "~> 1.3"},
{:phoenix_slime, "~> 0.13"},
Configure Phoenix to recognize .slime templates:
# config/config.exs
config :phoenix, :template_engines,
slim: PhoenixSlime.Engine,
slime: PhoenixSlime.Engine
A typical Slime template (instead of HEEx):
/ templates/page/index.html.slime
h1 = @page_title
p.lead = @intro_text
ul
= for item <- @items do
li = item.name
Add a health check plug that verifies the app can serve requests:
# lib/my_app_web/plugs/health_check.ex
defmodule MyAppWeb.Plugs.HealthCheck do
import Plug.Conn
def init(opts), do: opts
def call(%Plug.Conn{request_path: "/health"} = conn, _opts) do
checks = %{
database: check_database(),
memory: check_memory(),
endpoint: check_endpoint()
}
status = if Enum.all?(checks, fn {_, v} -> v == :ok end), do: 200, else: 503
conn
|> put_resp_content_type("application/json")
|> send_resp(status, Jason.encode!(%{
status: if(status == 200, do: "ok", else: "degraded"),
checks: checks
}))
|> halt()
end
def call(conn, _opts), do: conn
defp check_database do
case Ecto.Adapters.SQL.query(MyApp.Repo, "SELECT 1", []) do
{:ok, _} -> :ok
_ -> :error
end
end
defp check_memory do
total_mb = :erlang.memory()[:total] / 1_048_576
if total_mb < 1_500, do: :ok, else: :error
end
defp check_endpoint do
case Process.whereis(MyAppWeb.Endpoint) do
pid when is_pid(pid) ->
if Process.alive?(pid), do: :ok, else: :error
nil ->
:error
end
end
end
Register before the router:
# lib/my_app_web/endpoint.ex
plug MyAppWeb.Plugs.HealthCheck
plug MyAppWeb.Router
Test:
mix phx.server
curl http://localhost:4000/health | jq .
# {"status":"ok","checks":{"database":"ok","memory":"ok","endpoint":"ok"}}
Step 2: Set up HTTP monitoring in Vigilmon
- Sign up at vigilmon.online.
- Click New Monitor → HTTP.
- Enter
https://your-app.example.com/health. - Set check interval to 60 seconds.
- Add a keyword check for
"ok"to catch degraded responses. - Set alert threshold to 2 consecutive failures.
Step 3: Keyword checks for template output
A health endpoint confirms the app process is running. A keyword check on a real page confirms that Slime templates are rendering correctly end-to-end — catching compile errors, broken assigns, and layout failures that the health endpoint misses.
In Vigilmon, add a second monitor:
- Click New Monitor → HTTP.
- Enter
https://your-app.example.com/(or your most-visited public route). - Add a keyword check for a string that should always appear in your rendered output — e.g. your app name, a heading, or a footer copyright string.
- Set check interval to 5 minutes.
If a Slime template throws on a missing assign and your error handler renders a generic error page, Vigilmon's keyword check will fire — even though the HTTP status might still be 200 from the error handler.
Example with <h1> verification:
If your index.html.slime always renders:
h1 Welcome to MyApp
Set the keyword check to Welcome to MyApp. Any render failure will remove that string from the page and trigger the alert.
Step 4: Heartbeat monitoring for background render jobs
If your app uses background jobs to pre-render Slime templates (email bodies, PDF reports, static site generation), add a heartbeat to confirm they complete successfully:
# lib/my_app/workers/report_renderer_worker.ex
defmodule MyApp.Workers.ReportRendererWorker do
use Oban.Worker, queue: :rendering
require Logger
@impl Oban.Worker
def perform(%Oban.Job{args: %{"report_id" => report_id}}) do
with {:ok, report} <- MyApp.Reports.get_report(report_id),
{:ok, html} <- render_report(report),
:ok <- MyApp.Reports.save_rendered(report_id, html) do
ping_heartbeat()
:ok
else
error ->
Logger.error("ReportRendererWorker failed: #{inspect(error)}")
{:error, error}
end
end
defp render_report(report) do
assigns = %{report: report, generated_at: DateTime.utc_now()}
html = Phoenix.View.render_to_string(MyAppWeb.ReportView, "show.html.slime", assigns)
{:ok, html}
rescue
e -> {:error, e}
end
defp ping_heartbeat do
url = System.get_env("VIGILMON_REPORT_RENDERER_HEARTBEAT_URL")
if url do
Task.start(fn ->
:httpc.request(:get, {String.to_charlist(url), []}, [], [])
end)
end
end
end
In Vigilmon, create a Heartbeat Monitor:
- Click New Monitor → Heartbeat.
- Set grace period matching your job schedule (e.g. 1 hour for an hourly report job).
- Copy the ping URL into
VIGILMON_REPORT_RENDERER_HEARTBEAT_URL.
Step 5: Key metrics to alert on
| Metric | Alert threshold | Why |
|---|---|---|
| /health HTTP status | Non-200 for 2 checks | App process down |
| Homepage keyword check | Expected string missing | Template render failure |
| Response latency p95 | > 3 000 ms | Slow assigns or heavy render |
| Heartbeat silence | Grace period exceeded | Background render job stalled |
Step 6: Status page
- In Vigilmon, go to Status Pages → New.
- Add your health monitor, homepage keyword monitor, and any render-job heartbeats.
- Label them "App health", "Homepage render", and "Report renderer".
- Share the URL in your support docs so customers can check status independently.
Conclusion
Slime makes Phoenix templates concise and readable. Vigilmon makes sure those templates are actually reaching your users. Together:
- Uptime checks detect app failures before users do
- Keyword checks catch silent render errors that return 200 with wrong content
- Heartbeat monitors alert when background render jobs stall
Start with the /health endpoint and a keyword check on your homepage, then add heartbeats for any background rendering workload.
Get started free at vigilmon.online.