Step-by-step demo script showing a fresh Phoenix project going from zero to full observability (metrics, logs, traces) with a single Igniter install.
Pre-requisites (before recording)
Publish to Hex
timeless_metrics,timeless_logs,timeless_tracestimeless_metrics_dashboard,timeless_logs_dashboard,timeless_traces_dashboardtimeless_phoenix
Install latest Phoenix + Igniter globally
mix archive.install hex phx_new mix archive.install hex igniter_new
Demo Script
Act 1: Fresh Phoenix Project (~2 min)
mix phx.new demo_app --no-ecto --no-mailer --install
cd demo_app
mix phx.server
- Open
http://localhost:4000— vanilla Phoenix welcome page - Open
http://localhost:4000/dev/dashboard— stock LiveDashboard - Talking point: "This is what you get out of the box. Metrics are ephemeral — refresh and they're gone. No logs, no traces."
Act 2: One-Line Install (~1 min)
Stop the server, then:
mix igniter.install timeless_phoenix
What Igniter does automatically (show the diff or narrate):
- Adds
{:timeless_phoenix, "~> 0.x"}tomix.exsdeps - Adds
{TimelessPhoenix, data_dir: "priv/observability"}to your supervision tree inapplication.ex - Configures OpenTelemetry to export spans to TimelessTraces in
config.exs - Adds
import TimelessPhoenix.Routerto your router - Adds
timeless_phoenix_dashboard "/dashboard"inside your browser scope - Updates
.formatter.exswithimport_deps: [:timeless_phoenix] - Prints a notice to remove the default
/dev/dashboardroute (avoids live_session conflict)
Important: Remove the default LiveDashboard route from the router (the if Application.compile_env(:your_app, :dev_routes) block) to avoid a live_session conflict.
Talking point: "One command. No config files. No YAML. No docker-compose."
Act 3: Generate Demo Traffic (~1 min)
mix timeless_phoenix.gen_demo
What Igniter generates:
lib/<app>/demo_traffic.ex— a GenServer that spawns 3-6 simulated activities every 2 seconds (HTTP requests, DB queries, background jobs, cache operations, plus periodic warnings and errors)- Adds
{Task.Supervisor, name: <App>.DemoTaskSupervisor}and<App>.DemoTrafficto the supervision tree
Talking point: "This gives us realistic background activity so the dashboards have something interesting to show. All log levels, telemetry events, simulated request patterns."
Act 4: Start and Explore (~3 min)
mix phx.server
Open http://localhost:4000/dashboard — LiveDashboard now has three observability pages, and the demo traffic generator is already populating them:
Metrics tab — VM metrics (memory, run queues, process counts) already being captured and persisted. Refresh the page — history is still there.
- Talking point: "These metrics survive page refreshes, restarts, even deploys. They're stored in a Gorilla+zstd compressed time series database at 0.67 bytes per point — an 11.5x compression ratio."
Logs tab — Demo traffic is generating logs at all four levels. Show the search.
- All
Loggercalls are automatically captured, compressed, and indexed - Demo: search by level (
:error,:warning), substring match ("timeout", "deadlock"), time range - Talking point: "Every Logger call in your app is automatically captured. No extra config. Search by level, message, metadata — all indexed in SQLite."
- All
Traces tab — Demo traffic is generating OpenTelemetry spans for every simulated activity (HTTP requests, DB queries, background jobs, cache operations). Spans appear with service name, duration, status.
- Click a trace ID to see span details
- Filter by
status=error,min_duration, etc. - Talking point: "Spans go straight from the OTel SDK to compressed storage. No collector, no Jaeger, no external infra."
TimelessMetrics tab — Persistent charts, compression stats, backup controls.
- Talking point: "This is your metrics TSDB dashboard. Compression ratios, point counts, segment info — all at a glance."
Act 5: Real Phoenix Traces (optional, ~2 min)
To also capture spans from real Phoenix HTTP requests (not just demo traffic), add OTel instrumentation:
# mix.exs — add these deps
{:opentelemetry_phoenix, "~> 2.0"},
{:opentelemetry_bandit, "~> 0.2"}# application.ex — in start/2, before supervisor
OpentelemetryPhoenix.setup()
OpentelemetryBandit.setup()Restart, hit a few pages, then show the new spans in the Traces tab alongside the demo traffic spans.
- Talking point: "One line of setup and every real HTTP request gets traced end-to-end."
Act 6: The Punchline (~1 min)
Show the data directory:
ls -la priv/observability/
# metrics/ logs/ spans/
du -sh priv/observability/
Talking points:
- "All three pillars of observability in one dep"
- "Zero external infrastructure — no Prometheus, no Loki, no Jaeger, no Grafana needed"
- "11.5x compression on metrics, 11x on logs, 10x on traces"
- "SQLite + immutable segment files — back it up with a single function call"
- "Works with
mix phx.serverin dev, works in production containers"
Bonus Demos (if time allows)
- Memory-only mode:
mix igniter.install timeless_phoenix --storage memoryfor CI/test environments - Forecasting: Hit
/chart?metric=vm.memory.total&from=-1h&forecast=30min the browser - Anomaly detection: Add
&anomalies=mediumto the chart URL for red dot overlays - Backup: Click the backup button in the dashboard or call
TimelessMetrics.backup(:tp_default_timeless, "/tmp/bak")
Pre-flight Checklist
- [ ] All packages published to Hex (or clean GitHub dep story ready)
- [x]
mix igniter.install timeless_phoenixworks against a cleanphx.newproject - [x] Remove default LiveDashboard route after install (live_session conflict)
- [x]
mix timeless_phoenix.gen_demogenerates DemoTraffic + Task.Supervisor correctly - [ ] Traces tab populates with OTel Phoenix/Bandit instrumentation (if using Act 5)
- [x] Data directory creates cleanly under
priv/observability/