Current section
Files
Jump to
Current section
Files
lib/oban_lens.ex
defmodule ObanLens do
@moduledoc """
ObanLens provides advanced job monitoring and filtering for Oban with persistent job history,
time-based search, detailed forensics, and AI-powered insights.
## Features
- **Persistent Job History**: Automatically records all job executions to a history table for forensic analysis
- **Advanced Filtering**: Filter jobs by worker, queue, state, time range, duration, and search within job args
- **Time-Based Search**: Find jobs from specific time periods (e.g., "last Tuesday 2-4 PM")
- **Job Details & Forensics**: Click any job to see complete details including args, errors, attempts, and execution timeline
- **CSV Export**: Export filtered job data for compliance audits and reporting
## Quick Start
1. Add ObanLens to your dependencies:
```elixir
# mix.exs
def deps do
[
{:oban_lens, "~> 0.1.0"}
]
end
```
2. Create the migration in your **Oban database**:
```bash
# If Oban uses the same repo as your app
mix ecto.gen.migration create_oban_job_history
# If Oban uses a separate repo (common with Oban Pro)
mix ecto.gen.migration create_oban_job_history --repo MyApp.ObanRepo
```
Copy the migration content from `ObanLens.Migration.create_job_history_table/0`.
3. Configure ObanLens:
```elixir
# config/config.exs
# Option 1: Explicit repo configuration (recommended)
config :oban_lens,
repo: MyApp.ObanRepo, # Use the same repo as Oban
history_retention_days: 30
# Option 2: Auto-detect from Oban config (if not specified above)
# ObanLens will automatically use the same repo as Oban
```
4. Attach telemetry in your application start:
```elixir
# lib/my_app/application.ex
def start(_type, _args) do
# ... other children
ObanLens.Telemetry.attach()
children = [
# ... your children
]
Supervisor.start_link(children, opts)
end
```
5. Mount the dashboard in your router:
```elixir
# lib/my_app_web/router.ex
scope "/" do
pipe_through :browser
ObanLens.Router.oban_lens_dashboard("/admin/oban")
end
```
## Configuration
All configuration options:
- `:repo` - Your application's Ecto repo (required)
- `:history_retention_days` - How long to keep job history (default: 30)
- `:record_completed` - Record successful jobs (default: true)
- `:record_failed` - Record failed jobs (default: true)
- `:record_discarded` - Record discarded jobs (default: true)
"""
@doc """
Returns the configured Ecto repo for ObanLens.
If no repo is explicitly configured, it will try to detect the Oban repo
from your Oban configuration to ensure tables are created in the same database.
"""
def repo do
case Application.get_env(:oban_lens, :repo) do
nil -> detect_oban_repo()
repo -> repo
end
end
@doc """
Detects the Oban repo from Oban configuration.
This is useful when you have a separate database for Oban jobs.
"""
def detect_oban_repo do
case Application.get_env(:oban, Oban) do
%{repo: oban_repo} -> oban_repo
config when is_list(config) ->
Keyword.get(config, :repo) ||
raise "Could not detect Oban repo. Please configure `config :oban_lens, repo: YourObanRepo`"
_ ->
raise "ObanLens repo not configured and could not detect Oban repo. Add `config :oban_lens, repo: YourRepo` to your config."
end
end
@doc """
Returns the configuration for ObanLens.
"""
def config do
Application.get_all_env(:oban_lens)
end
@doc """
Returns whether a specific job state should be recorded based on configuration.
"""
def record_state?(state) do
case state do
:completed -> Application.get_env(:oban_lens, :record_completed, true)
:failed -> Application.get_env(:oban_lens, :record_failed, true)
:discarded -> Application.get_env(:oban_lens, :record_discarded, true)
_ -> false
end
end
end