{"id":42958905,"url":"https://github.com/betterdb-inc/monitor","last_synced_at":"2026-05-05T17:01:55.481Z","repository":{"id":331108756,"uuid":"1124809458","full_name":"BetterDB-inc/monitor","owner":"BetterDB-inc","description":"Real-time monitoring, slowlog analysis, and audit trails for Valkey and Redis","archived":false,"fork":false,"pushed_at":"2026-04-22T07:27:21.000Z","size":3027,"stargazers_count":299,"open_issues_count":8,"forks_count":45,"subscribers_count":26,"default_branch":"master","last_synced_at":"2026-04-22T08:25:19.178Z","etag":null,"topics":["metrics","monitoring","obsevability","prometheus","redis","valkey"],"latest_commit_sha":null,"homepage":"https://betterdb.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BetterDB-inc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":"CLA.md"}},"created_at":"2025-12-29T16:47:38.000Z","updated_at":"2026-04-21T17:00:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/BetterDB-inc/monitor","commit_stats":null,"previous_names":["kivanow/monitor","betterdb-inc/monitor"],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/BetterDB-inc/monitor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterDB-inc%2Fmonitor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterDB-inc%2Fmonitor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterDB-inc%2Fmonitor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterDB-inc%2Fmonitor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BetterDB-inc","download_url":"https://codeload.github.com/BetterDB-inc/monitor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BetterDB-inc%2Fmonitor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32240613,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["metrics","monitoring","obsevability","prometheus","redis","valkey"],"created_at":"2026-01-30T22:52:13.727Z","updated_at":"2026-04-24T21:01:36.705Z","avatar_url":"https://github.com/BetterDB-inc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BetterDB Monitor\n\nA monorepo application for monitoring Valkey/Redis databases with a NestJS backend and React frontend.\n\nBetterDB is built by [BetterDB Inc.](https://betterdb.com), a public benefit company operating under the [OCV Open Charter](https://github.com/OpenCoreVentures/ocv-public-benefit-company).\n\n## Project Structure\n\n```\nbetterdb-monitor/\n├── apps/\n│   ├── api/                 # NestJS backend (Fastify)\n│   └── web/                 # React frontend (Vite)\n├── packages/\n│   ├── cli/                 # CLI package (npx betterdb)\n│   └── shared/              # Shared TypeScript types\n├── docker-compose.yml       # Local Valkey (port 6380) and Redis (port 6382) for testing\n└── package.json             # Workspace root\n```\n\n## Tech Stack\n\n### Backend\n- **NestJS** with Fastify adapter\n- **iovalkey** for Valkey/Redis connections\n- TypeScript with strict mode\n- Runs on port **3001**\n\n### Frontend\n- **React** with TypeScript\n- **Vite** for build tooling\n- **TailwindCSS** for styling\n- **Recharts** for data visualization\n- Runs on port **5173**\n\n### Monorepo\n- **pnpm workspaces** for dependency management\n- **Turborepo** for build orchestration\n\n## Quick Start\n\n### Prerequisites\n- Node.js \u003e= 20.0.0\n- pnpm \u003e= 9.0.0\n- Docker (for local Valkey or Redis instances)\n\n### Installation\n\n1. Install dependencies:\n```bash\npnpm install\n```\n\n2. Copy environment variables:\n```bash\ncp .env.example .env\n```\n\n3. Start local database instances (Valkey on 6380, Redis on 6382):\n```bash\npnpm docker:up\n```\n\nTo connect to Redis instead of Valkey, update `.env`:\n```env\nDB_PORT=6382\n```\n\n4. Start development servers:\n```bash\npnpm dev\n```\n\nThe application will be available at:\n- Frontend: http://localhost:5173\n- Backend API: http://localhost:3001\n\n### Individual Commands\n\nRun only the API:\n```bash\npnpm dev:api\n```\n\nRun only the web frontend:\n```bash\npnpm dev:web\n```\n\nStop Docker containers:\n```bash\npnpm docker:down\n```\n\nBuild for production:\n```bash\npnpm build\n```\n\n## CLI Installation (npx)\n\nThe easiest way to run BetterDB Monitor without Docker:\n\n```bash\nnpx @betterdb/monitor\n```\n\nOn first run, an interactive setup wizard will guide you through configuration:\n- Database connection (host, port, credentials)\n- Storage backend (SQLite, PostgreSQL, or in-memory)\n- Server port and other settings\n\nConfiguration is saved to `~/.betterdb/config.json`.\n\n### Global Installation\n\n```bash\nnpm install -g @betterdb/monitor\nbetterdb\n```\n\n### CLI Options\n\n```bash\nbetterdb --setup           # Re-run setup wizard, then start server\nbetterdb --port 8080       # Override server port\nbetterdb --db-host 1.2.3.4 # Override database host\nbetterdb --help            # Show all options\n```\n\n### SQLite Storage (Optional)\n\nTo use SQLite storage with the CLI, install `better-sqlite3`:\n\n```bash\nnpm install -g better-sqlite3\n```\n\n### Requirements\n\n- Node.js \u003e= 20.0.0\n- A Valkey or Redis instance to monitor\n\n---\n\n## Docker Production Deployment\n\n### Building the Docker Image\n\n```bash\npnpm docker:build\n```\n\nFor multi-arch builds (AMD64 + ARM64), first set up buildx:\n\n```bash\ndocker buildx create --name mybuilder --use --bootstrap\n```\n\nThen build:\n\n```bash\npnpm docker:build:multiarch\n```\n\n### Running the Docker Container\n\nThe Docker image contains only the monitoring application (backend + frontend). It requires:\n1. A Valkey/Redis instance to monitor\n2. A PostgreSQL instance for data persistence (or use memory storage)\n\n#### Basic Run (Memory Storage)\n\n```bash\ndocker run -d \\\n  --name betterdb-monitor \\\n  -p 3001:3001 \\\n  -e DB_HOST=your-valkey-host \\\n  -e DB_PORT=6379 \\\n  -e DB_PASSWORD=your-password \\\n  -e STORAGE_TYPE=memory \\\n  betterdb/monitor\n```\n\n#### Run on Custom Port\n\nYou can run the application on any port by setting the `PORT` environment variable with `-e PORT=\u003cport\u003e`:\n\n```bash\ndocker run -d \\\n  --name betterdb-monitor \\\n  -p 8080:8080 \\\n  -e PORT=8080 \\\n  -e DB_HOST=your-valkey-host \\\n  -e DB_PORT=6379 \\\n  -e DB_PASSWORD=your-password \\\n  -e STORAGE_TYPE=memory \\\n  betterdb/monitor\n```\n\n**Note**: When not using `--network host`, make sure the `-p` flag port mapping matches the `PORT` environment variable (e.g., `-p 8080:8080 -e PORT=8080`).\n\n#### Run with PostgreSQL Storage\n\n```bash\ndocker run -d \\\n  --name betterdb-monitor \\\n  -p 3001:3001 \\\n  -e DB_HOST=your-valkey-host \\\n  -e DB_PORT=6379 \\\n  -e DB_PASSWORD=your-password \\\n  -e STORAGE_TYPE=postgres \\\n  -e STORAGE_URL=postgresql://user:pass@postgres-host:5432/dbname \\\n  betterdb/monitor\n```\n\n#### Run with Host Network (Access localhost services)\n\nIf your Valkey and PostgreSQL are running on the same host:\n\n```bash\ndocker run -d \\\n  --name betterdb-monitor \\\n  --network host \\\n  -e DB_HOST=localhost \\\n  -e DB_PORT=6380 \\\n  -e DB_PASSWORD=devpassword \\\n  -e STORAGE_TYPE=postgres \\\n  -e STORAGE_URL=postgresql://dev:devpass@localhost:5432/postgres \\\n  betterdb/monitor\n```\n\n#### Auto-Remove Previous Container\n\nTo automatically remove any existing container with the same name:\n\n```bash\ndocker rm -f betterdb-monitor 2\u003e/dev/null; docker run -d \\\n  --name betterdb-monitor \\\n  -p 3001:3001 \\\n  -e DB_HOST=your-valkey-host \\\n  -e DB_PORT=6379 \\\n  -e DB_PASSWORD=your-password \\\n  -e STORAGE_TYPE=postgres \\\n  -e STORAGE_URL=postgresql://user:pass@postgres-host:5432/dbname \\\n  betterdb/monitor\n```\n\n### Environment Variables\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `DB_HOST` | Yes | `localhost` | Valkey/Redis host to monitor |\n| `DB_PORT` | No | `6379` | Valkey/Redis port |\n| `DB_PASSWORD` | No | - | Valkey/Redis password |\n| `DB_USERNAME` | No | `default` | Valkey/Redis ACL username |\n| `DB_TYPE` | No | `auto` | Database type: `auto`, `valkey`, or `redis` |\n| `STORAGE_TYPE` | No | `memory` | Storage backend: `memory` or `postgres` |\n| `STORAGE_URL` | Conditional | - | PostgreSQL connection URL (required if `STORAGE_TYPE=postgres`) |\n| `PORT` | No | `3001` | Application HTTP port |\n| `NODE_ENV` | No | `production` | Node environment |\n| `ANOMALY_DETECTION_ENABLED` | No | `true` | Enable anomaly detection |\n| `ANOMALY_PROMETHEUS_INTERVAL_MS` | No | `30000` | Prometheus summary update interval (ms) |\n\n### Accessing the Application\n\nOnce running, access the web interface at:\n- **Web UI**: `http://localhost:3001`\n- **Health Check**: `http://localhost:3001/health`\n- **Prometheus Metrics**: `http://localhost:3001/prometheus/metrics`\n\n### Docker Image Details\n\n- **Base Image**: `node:20-alpine`\n- **Size**: ~188MB (optimized, no build tools)\n- **Platforms**: `linux/amd64`, `linux/arm64`\n- **Contains**: Backend API + Frontend static files (served by Fastify)\n- **Excluded**: SQLite support (use PostgreSQL or Memory storage)\n\n### Checking Container Logs\n\n```bash\ndocker logs -f betterdb-monitor\n```\n\n### Stopping the Container\n\n```bash\ndocker stop betterdb-monitor\ndocker rm betterdb-monitor\n```\n\n## Features\n\n### Current Features\n- Database connection health monitoring\n- Auto-detection of Valkey vs Redis\n- Version detection\n- Capability detection (Command Log, Slot Stats)\n- Auto-refresh every 5 seconds\n- Full Redis 6.x and 7.x support (85-90% feature parity with Valkey)\n- Graceful degradation for Valkey-only features\n\n### Vector / AI\n\nFor deployments running RediSearch or [`valkey-search`](https://github.com/valkey-io/valkey-search), BetterDB ships a dedicated **Vector / AI** tab that surfaces FT.SEARCH ops/sec and average latency over time alongside per-index health (docs, records, deleted docs, indexing failures, backfill progress). Stale Prometheus labels are reconciled when indexes are dropped, and the tab hides automatically when the Search module isn't available. See [`docs/vector-ai/`](docs/vector-ai/README.md) for the full walkthrough and screenshots.\n\n### Supported Database Versions\n\n| Database | Minimum Version | Supported Features |\n|----------|----------------|-------------------|\n| **Valkey** | 8.0+ | All features including COMMANDLOG and CLUSTER SLOT-STATS |\n| **Redis** | 6.0+ | All features except COMMANDLOG and CLUSTER SLOT-STATS |\n\n### Feature Compatibility Matrix\n\n| Feature | Command | Valkey | Redis |\n|---------|---------|--------|-------|\n| Server Info | `INFO` | Yes | Yes |\n| Health Check | `PING` | Yes | Yes |\n| Slowlog | `SLOWLOG` | Yes | Yes (2.2+) |\n| Client List | `CLIENT LIST` | Yes | Yes (2.4+) |\n| Latency Monitor | `LATENCY` | Yes | Yes (2.8+) |\n| Memory Stats | `MEMORY STATS` | Yes | Yes (4.0+) |\n| ACL Log | `ACL LOG` | Yes | Yes (6.0+) |\n| Command Log | `COMMANDLOG` | Yes (8.1+) | No (Valkey-only) |\n| Cluster Slot Stats | `CLUSTER SLOT-STATS` | Yes (8.0+) | No (Valkey-only) |\n\n### Architecture Highlights\n\n**Unified Adapter Pattern**: The backend uses a unified `UnifiedDatabaseAdapter` that works seamlessly with both Valkey and Redis through the wire-compatible `iovalkey` client library.\n\n**Auto-detection**: The application automatically detects whether it's connecting to Valkey or Redis by inspecting the `INFO` response.\n\n**Capability Detection**: Features like Command Log (Valkey 8.1+) and Slot Stats (Valkey 8.0+) are automatically detected based on database type and version. The UI gracefully degrades when connecting to Redis, showing only supported features.\n\n**Graceful Degradation**: When connected to Redis, Valkey-specific features return clear error messages indicating they're not supported, while all shared features work identically.\n\n## Prometheus Metrics\n\nMetrics are exposed at `GET /prometheus/metrics` in Prometheus text format.\n\n### ACL Audit Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_acl_denied` | gauge | - | Total ACL denied events captured |\n| `betterdb_acl_denied_by_reason` | gauge | `reason` | ACL denied events by reason |\n| `betterdb_acl_denied_by_user` | gauge | `username` | ACL denied events by username |\n\n### Client Connection Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_client_connections_current` | gauge | - | Current number of client connections |\n| `betterdb_client_connections_peak` | gauge | - | Peak connections in retention period |\n| `betterdb_client_connections_by_name` | gauge | `client_name` | Current connections by client name |\n| `betterdb_client_connections_by_user` | gauge | `user` | Current connections by ACL user |\n\n### Slowlog Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_slowlog_pattern_count` | gauge | `pattern` | Number of slow queries per pattern |\n| `betterdb_slowlog_pattern_avg_duration_us` | gauge | `pattern` | Average duration in microseconds per pattern |\n| `betterdb_slowlog_pattern_percentage` | gauge | `pattern` | Percentage of slow queries per pattern |\n\n### COMMANDLOG Metrics (Valkey 8.1+)\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_commandlog_large_request` | gauge | - | Total large request entries |\n| `betterdb_commandlog_large_reply` | gauge | - | Total large reply entries |\n| `betterdb_commandlog_large_request_by_pattern` | gauge | `pattern` | Large request count by command pattern |\n| `betterdb_commandlog_large_reply_by_pattern` | gauge | `pattern` | Large reply count by command pattern |\n\n### Node.js Process Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_process_cpu_user_seconds_total` | counter | - | Total user CPU time spent in seconds |\n| `betterdb_process_cpu_system_seconds_total` | counter | - | Total system CPU time spent in seconds |\n| `betterdb_process_cpu_seconds_total` | counter | - | Total user and system CPU time spent in seconds |\n| `betterdb_process_start_time_seconds` | gauge | - | Start time of the process since unix epoch in seconds |\n| `betterdb_process_resident_memory_bytes` | gauge | - | Resident memory size in bytes |\n| `betterdb_process_virtual_memory_bytes` | gauge | - | Virtual memory size in bytes |\n| `betterdb_process_heap_bytes` | gauge | - | Process heap size in bytes |\n| `betterdb_process_open_fds` | gauge | - | Number of open file descriptors |\n| `betterdb_process_max_fds` | gauge | - | Maximum number of open file descriptors |\n\n### Node.js Event Loop Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_nodejs_eventloop_lag_seconds` | gauge | - | Lag of event loop in seconds |\n| `betterdb_nodejs_eventloop_lag_min_seconds` | gauge | - | Minimum recorded event loop delay |\n| `betterdb_nodejs_eventloop_lag_max_seconds` | gauge | - | Maximum recorded event loop delay |\n| `betterdb_nodejs_eventloop_lag_mean_seconds` | gauge | - | Mean of recorded event loop delays |\n| `betterdb_nodejs_eventloop_lag_stddev_seconds` | gauge | - | Standard deviation of recorded event loop delays |\n| `betterdb_nodejs_eventloop_lag_p50_seconds` | gauge | - | 50th percentile of recorded event loop delays |\n| `betterdb_nodejs_eventloop_lag_p90_seconds` | gauge | - | 90th percentile of recorded event loop delays |\n| `betterdb_nodejs_eventloop_lag_p99_seconds` | gauge | - | 99th percentile of recorded event loop delays |\n\n### Node.js Runtime Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_nodejs_active_resources` | gauge | `type` | Active resources keeping the event loop alive |\n| `betterdb_nodejs_active_resources_total` | gauge | - | Total number of active resources |\n| `betterdb_nodejs_active_handles` | gauge | `type` | Active libuv handles by type |\n| `betterdb_nodejs_active_handles_total` | gauge | - | Total number of active handles |\n| `betterdb_nodejs_active_requests` | gauge | `type` | Active libuv requests by type |\n| `betterdb_nodejs_active_requests_total` | gauge | - | Total number of active requests |\n| `betterdb_nodejs_version_info` | gauge | `version`, `major`, `minor`, `patch` | Node.js version info |\n\n### Node.js Heap Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_nodejs_heap_size_total_bytes` | gauge | - | Process heap size from Node.js in bytes |\n| `betterdb_nodejs_heap_size_used_bytes` | gauge | - | Process heap size used from Node.js in bytes |\n| `betterdb_nodejs_external_memory_bytes` | gauge | - | Node.js external memory size in bytes |\n| `betterdb_nodejs_heap_space_size_total_bytes` | gauge | `space` | Process heap space size total in bytes |\n| `betterdb_nodejs_heap_space_size_used_bytes` | gauge | `space` | Process heap space size used in bytes |\n| `betterdb_nodejs_heap_space_size_available_bytes` | gauge | `space` | Process heap space size available in bytes |\n\n### Node.js GC Metrics\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `betterdb_nodejs_gc_duration_seconds` | histogram | `kind` | Garbage collection duration (major, minor, incremental, weakcb) |\n\n## Configuration\n\n### Database Connection (Valkey/Redis)\n\nEdit `.env` to configure the Valkey/Redis database connection:\n\n```env\nDB_HOST=localhost\nDB_PORT=6379\nDB_USERNAME=default\nDB_PASSWORD=devpassword\nDB_TYPE=auto  # 'valkey' | 'redis' | 'auto'\n```\n\n### Storage Backend\n\nBetterDB Monitor supports multiple storage backends for persisting audit trail and client analytics data:\n\n#### SQLite (Local Development Only)\n```bash\nSTORAGE_TYPE=sqlite\nSTORAGE_SQLITE_FILEPATH=./data/audit.db  # Optional, defaults to this path\n```\n- **Use Case**: Local development\n- **Pros**: No external database required, simple setup\n- **Cons**: Not available in Docker production builds\n- **Data Location**: `apps/api/data/audit.db`\n\n#### PostgreSQL (Recommended for Production)\n```bash\nSTORAGE_TYPE=postgres\nSTORAGE_URL=postgresql://username:password@host:port/database\n```\n- **Use Case**: Production and local development\n- **Pros**: Full relational database, better for production workloads\n- **Cons**: Requires PostgreSQL instance\n- **Example**: `postgresql://dev:devpass@localhost:5432/postgres`\n\n#### Memory (Testing/Ephemeral)\n```bash\nSTORAGE_TYPE=memory\n```\n- **Use Case**: Testing, ephemeral environments\n- **Pros**: No persistence required, fast\n- **Cons**: All data lost on restart\n\n### Running Locally with Different Storage Backends\n\n#### With SQLite:\n```bash\nSTORAGE_TYPE=sqlite \\\nDB_HOST=localhost \\\nDB_PORT=6380 \\\nDB_PASSWORD=devpassword \\\npnpm dev:api\n```\n\n#### With PostgreSQL:\n```bash\n# Start PostgreSQL (if using docker-compose)\ndocker compose up -d postgres\n\n# Run API with PostgreSQL\nSTORAGE_TYPE=postgres \\\nSTORAGE_URL=postgresql://betterdb:devpassword@localhost:5432/betterdb \\\nDB_HOST=localhost \\\nDB_PORT=6380 \\\nDB_PASSWORD=devpassword \\\npnpm dev:api\n```\n\n#### With Memory:\n```bash\nSTORAGE_TYPE=memory \\\nDB_HOST=localhost \\\nDB_PORT=6380 \\\nDB_PASSWORD=devpassword \\\npnpm dev:api\n```\n\n## Development\n\n### Adding New Features\n\nThe codebase is structured to make it easy to add new monitoring features:\n\n1. Add new endpoints in `apps/api/src/`\n2. Add corresponding API calls in `apps/web/src/api/`\n3. Add shared types in `packages/shared/src/types/`\n\n### Code Style\n\n- TypeScript strict mode is enabled\n- Explicit return types required on functions\n- No `any` types allowed\n- ESLint + Prettier configured\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbetterdb-inc%2Fmonitor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbetterdb-inc%2Fmonitor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbetterdb-inc%2Fmonitor/lists"}