{"id":34711877,"url":"https://github.com/kx0101/replayer","last_synced_at":"2026-04-02T18:27:38.538Z","repository":{"id":327992308,"uuid":"1110715441","full_name":"kx0101/replayer","owner":"kx0101","description":"HTTP request replay and comparison tool in Go. Replay real traffic, compare multiple environments, detect broken endpoints, generate HTML/JSON reports, and analyze latency","archived":false,"fork":false,"pushed_at":"2026-03-29T16:33:59.000Z","size":24496,"stargazers_count":14,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2026-03-29T18:47:57.560Z","etag":null,"topics":["api","api-testing","devex","devtools","go","http","logs","open-source","regression"],"latest_commit_sha":null,"homepage":"https://www.replayer.online/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kx0101.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":null}},"created_at":"2025-12-05T15:58:13.000Z","updated_at":"2026-02-15T21:52:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kx0101/replayer","commit_stats":null,"previous_names":["kx0101/replayer"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/kx0101/replayer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kx0101%2Freplayer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kx0101%2Freplayer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kx0101%2Freplayer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kx0101%2Freplayer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kx0101","download_url":"https://codeload.github.com/kx0101/replayer/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kx0101%2Freplayer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31312865,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["api","api-testing","devex","devtools","go","http","logs","open-source","regression"],"created_at":"2025-12-25T00:29:43.267Z","updated_at":"2026-04-02T18:27:38.529Z","avatar_url":"https://github.com/kx0101.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Replayer\n\nAn HTTP request replay and comparison tool written in Rust. Perfect for testing API changes, comparing environments, load testing, validating migrations, and generating detailed reports\n\n## Features\n\n### Core\n- **Replay HTTP requests** from JSON log files\n- **Multi-target support** - test multiple environments simultaneously\n- **Concurrent execution** with configurable limits\n- **Smart filtering** by method, path, and limits\n- **Ignore rules** for skipping noisy or irrelevant fields during diffing\n- **Regression rules**: to automatically fail when behavioral or performance regressions are detected\n\n### Performance \u0026 Load\n- **Rate limiting** - control requests per second\n- **Configurable timeouts** and delays\n- **Real-time progress tracking** with ETA\n- **Detailed latency statistics** (p50, p90, p95, p99, min, max, avg)\n\n### Response Comparison\n- **Automatic diff detection** between targets\n- **Status code mismatch** reporting\n- **Response body comparison**\n- **Latency comparison** across targets\n- **Per-target statistics** breakdown\n- **Ignore fields** during comparison\n\n### Authentication \u0026 Headers\n\n- **Bearer token authentication**\n- **Custom API headers** (repeatable)\n- **Supports multiple headers simultaneously**\n\n### Output\n- **Colorized console output** for easy reading\n- **JSON output** for programmatic use and CI/CD\n- **HTML reports** with executive summary, latency charts, per-target breakdown, and difference highlighting\n- **Summary-only mode** for quick overview\n\n### Logs\n- **Nginx log conversion** to JSON Lines format (combined/common)\n- Supports filtering and replay directly from raw logs\n- Fully replayable: captured logs can be replayed or compared after the fact\n\n### Exit Codes\n\nReplayer returns specific exit codes to allow CI/CD pipelines and scripts to react programmatically:\n\n| Exit Code | Meaning                                                            |\n| --------- | ------------------------------------------------------------------ |\n| 0         | Run completed successfully, no differences or errors               |\n| 1         | Differences detected between targets (used with `--compare`)       |\n| 2         | One or more regression rules were violated                         |\n| 3         | Invalid arguments or command-line usage                            |\n| 4         | Runtime error occurred (network, file I/O, or unexpected failure)  |\n\n## 🚀 Quick Start\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone \u003crepo-url\u003e\ncd replayer\n\n# Build all components\nmake build\n```\n\n## Usage Guide\n\n### Basic Replay\n\nReplay requests against a single target:\n\n```bash\n./replayer --input-file test_logs.json --concurrency 5 localhost:8080\n```\n\n### Compare Staging vs Production\n\nThe killer feature - compare two environments side-by-side:\n\n```bash\n./replayer \\\n  --input-file prod_logs.json \\\n  --compare \\\n  --concurrency 10 \\\n  staging.example.com \\\n  production.example.com\n```\n\n### Load Testing\n\nSimulate realistic load patterns:\n\n```bash\n./replayer \\\n  --input-file logs.json \\\n  --rate-limit 1000 \\\n  --concurrency 50 \\\n  --timeout 10000 \\\n  localhost:8080\n```\n\n### Authentication \u0026 Custom Headers\n\nProvide auth token or custom headers:\n\n```bash\n# Bearer token\n./replayer --input-file logs.json --auth \"Bearer token123\" api.example.com\n\n# Custom headers\n./replayer --input-file logs.json --header \"X-API-Key: abc\" --header \"X-Env: staging\" api.example.com\n```\n\n### HTML Report Generation\n\n```bash\n# Single target\n./replayer --input-file logs.json --html-report report.html localhost:8080\n\n# Comparison mode\n./replayer --input-file logs.json --compare --html-report comparison_report.html staging.api production.api\n```\n\n### Nginx Log Parsing\n\n```bash\n# Convert nginx logs to JSON Lines\n./replayer --input-file /var/log/nginx/access.log --parse-nginx traffic.json --nginx-format combined\n\n# Replay converted logs\n./replayer --input-file traffic.json --concurrency 10 staging.api.com\n```\n\n### Filter Specific Requests\n\nTest only certain endpoints:\n\n```bash\n# Only replay POST requests to /checkout\n./replayer \\\n  --input-file test_logs.json \\\n  --filter-method POST \\\n  --filter-path /checkout \\\n  --limit 100 \\\n  localhost:8080\n```\n\n### Ignore Rules\n\nIgnore specific JSON fields when comparing responses\n\n| Type | Example |\n|------|------|\n| Exact field | `--ignore status.updated_at` |\n| Wildcard | `--ignore '*.timestamp'` |\n| Multiple fields | `--ignore x --ignore y --ignore z`|\n\n```bash\n# Ignore timestamps, request IDs, metadata\n./replayer \\\n  --input-file logs.json \\\n  --compare \\\n  --ignore \"*.timestamp\" \\\n  --ignore \"request_id\" \\\n  --ignore \"metadata.*\" \\\n  staging.api prod.api\n\n# Ignore an entire object subtree\n--ignore \"debug_info\"\n```\n\n### JSON Output for Automation\n\nPerfect for CI/CD pipelines:\n\n```bash\n./replayer \\\n  --input-file test_logs.json \\\n  --output-json \\\n  --compare \\\n  staging.api \\\n  production.api \u003e results.json\n\ncat results.json | jq '.summary.succeeded'\n```\n\n### Live Capture Mode\n\nCapture requests in real-time from a running service or proxy and replay/compare them on the fly\n\n```bash\n# HTTP capture\n./replayer --capture \\\n  --listen :8080 \\\n  --upstream http://staging.api \\\n  --output traffic.json \\\n  --stream\n\n# HTTPS capture\n./replayer --capture \\\n  --listen :8080 \\\n  --upstream https://staging.api \\\n  --output traffic.json \\\n  --stream \\\n  --tls-cert proxy.crt \\\n  --tls-key proxy.key\n\n# Replay captured traffic\n./replayer --input-file traffic.json staging.api\n\n# Compare captured traffic between two environments\n./replayer --input-file traffic.json --compare staging.api production.api\n```\n\nWhen you finish capturing you may use the generated `traffic.json` file to replay or compare as usual\n\n### Regression Rules (Contract \u0026 Performance)\n\nDeclare regression rules via a yaml file. Replayer allows you to fail runs automatically when behavioral or performance regressions are detected\n\n```bash\n./replayer \\\n  --input-file traffic.json \\\n  --compare \\\n  --rules rules.yaml \\\n  staging.api \\\n  production.api\n```\n\nIf any rule is violated the run **fails** and violations are reported\n\n**rules.yaml** example\n```yaml\nrules:\n  status_mismatch:\n    max: 0\n\n  body_diff:\n    allowed: false\n    ignore:\n      - \"*.timestamp\"\n      - \"request_id\"\n\n  latency:\n    metric: p95\n    regression_percent: 20\n\n  endpoint_rules:\n    - path: /users\n      method: GET\n      status_mismatch:\n        max: 0\n\n    - path: /slow\n      latency:\n        metric: p95\n        regression_percent: 10\n```\n\n- **Status**: fails if response status differ\n- **Body**: exact fields, or prefix/suffix wildcards\n- **Latency**: you need a baseline for this (available metrics: min, max, avg, p50, p90, p95, p99)\n\nExample:\n\n```bash\n./replayer \\\n  --input-file traffic.json \\\n  --compare \\\n  --output-json \\\n  staging.api production.api \u003e baseline.json\n\n./replayer \\\n  --input-file traffic.json \\\n  --compare \\\n  --rules rules.yaml \\\n  --baseline baseline.json \\\n  staging.api production.api\n```\n\n### Dry Run Mode\n\nPreview what will be replayed without sending requests:\n\n```bash\n./replayer --input-file test_logs.json --dry-run\n```\n\n### Cloud Upload\n\nUpload replay results to Replayer Cloud for tracking, comparison, and team collaboration:\n\n```bash\n# set your API key (or use --cloud-api-key flag)\nexport REPLAYER_API_KEY=\"rp_your_api_key_here\"\n\n# upload results to cloud\n./replayer \\\n  --input-file traffic.json \\\n  --compare \\\n  --cloud \\\n  --cloud-env production \\\n  --cloud-label \"version=v1.2.3\" \\\n  --cloud-label \"branch=main\" \\\n  staging.api \\\n  production.api\n\n**What you get:**\n- Historical tracking of all replay runs\n- Web UI for viewing results and diffs\n- Baseline comparison across runs\n- Team collaboration with shared results\n\n## Replayer Cloud\n\nReplayer Cloud is a self-hosted SaaS platform for storing, comparing, and analyzing replay results with:\n\n- Register, login, email verification\n- Generate API keys for CLI access\n- Browse and search all replay runs\n- Set baselines and compare new runs\n- Organize runs by environment\n\n### Running Replayer Cloud\n\n```bash\nexport DATABASE_URL=\"postgres://user:pass@localhost/replayer?sslmode=disable\"\nexport SESSION_SECRET=\"your-32-character-secret-key-here\"\nexport BASE_URL=\"http://localhost:8090\"\ncargo run -p replayer-cloud\n```\n\n### Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `DATABASE_URL` | Yes | PostgreSQL connection string |\n| `SESSION_SECRET` | Yes | 32+ character secret for session encryption |\n| `BASE_URL` | Yes | Public URL for email links |\n| `SECURE_COOKIES` | No | Set to `true` in production (default: false) |\n| `SMTP_HOST` | No | SMTP server host for email verification |\n| `SMTP_PORT` | No | SMTP server port (default: 587) |\n| `SMTP_USER` | No | SMTP username |\n| `SMTP_PASSWORD` | No | SMTP password |\n| `SMTP_FROM` | No | From address for emails |\n\n### API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | `/api/v1/runs` | Upload a new run |\n| GET | `/api/v1/runs` | List runs (paginated) |\n| GET | `/api/v1/runs/{id}` | Get run details |\n| POST | `/api/v1/runs/{id}/baseline` | Set run as baseline |\n| GET | `/api/v1/compare/{id}` | Compare run with baseline |\n\n## Command-Line Options\n\n| Flag | Type | Default | Description |\n|------|------|---------|-------------|\n| `--input-file` | string | **required** | Path to the input log file |\n| `--concurrency` | int | 1 | Number of concurrent requests |\n| `--timeout` | int | 5000 | Request timeout in milliseconds |\n| `--delay` | int | 0 | Delay between requests in milliseconds |\n| `--rate-limit` | int | 0 | Maximum requests per second (0 = unlimited) |\n| `--limit` | int | 0 | Limit number of requests to replay (0 = all) |\n| `--filter-method` | string | \"\" | Filter by HTTP method (GET, POST, etc.) |\n| `--filter-path` | string | \"\" | Filter by path substring |\n| `--compare` | bool | false | Compare responses between targets |\n| `--output-json` | bool | false | Output results as JSON |\n| `--progress` | bool | true | Show progress bar |\n| `--dry-run` | bool | false | Preview mode - don't send requests |\n| `--summary-only` | bool | false | Output summary only |\n| `--auth` | string | \"\" | Authorization header value |\n| `--header` | string | \"\" | Custom header (repeatable) |\n| `--html-report` | string | \"\" | Generate HTML report |\n| `--parse-nginx` | string | \"\" | Convert nginx log to JSON Lines |\n| `--nginx-format` | string | \"combined\" | Nginx format: combined/common |\n| `--ignore` | string | \"\" | Ignore fields during diff (repeatable) |\n| `--capture` | | | Enable live capture mode |\n| `--listen` | string | \"\" | Port to listen for incoming requests |\n| `--upstream` | string | \"\" | URL of the real service to forward requests to |\n| `--output` | string | \"\" | Path to save captured requests in JSON format |\n| `--stream` | | | Optionally stream captured requests to stdout as they happen |\n| `--tls-cert` | string | \"\" | TLS certification |\n| `--tls-key` | string | \"\" | TLS key |\n| `--rules` | string | \"\" | Path to rules.yaml file for regression testing |\n| `--baseline` | string | \"\" | Path to baseline results JSON for comparison |\n| `--cloud` | bool | false | Upload results to Replayer Cloud |\n| `--cloud-url` | string | `$REPLAYER_CLOUD_URL` or `http://localhost:8090` | Replayer Cloud server URL |\n| `--cloud-api-key` | string | `$REPLAYER_API_KEY` | API key for cloud authentication |\n| `--cloud-env` | string | \"default\" | Environment name for cloud upload |\n| `--cloud-label` | string | \"\" | Label in `key=value` format (repeatable) |\n\n## Log File Format\n\n- Each line is a single JSON object (JSON Lines)\n- Request/response bodies are base64-encoded\n- Headers are arrays to support multiple values per key\n\n```json\n{\"timestamp\":\"2025-12-10T17:12:48.377+02:00\",\"method\":\"POST\",\"path\":\"/test\",\"headers\":{\"Content-Type\":[\"application/json\"]},\"body\":\"SGVsbG8gd29ybGQ=\",\"status\":200,\"response_headers\":{\"Content-Type\":[\"application/json\"]},\"response_body\":\"eyJzdWNjZXNzIjp0cnVlfQ==\",\"latency_ms\":12}\n```\n\n## Output Examples\n\n### Console Output (Default)\n\n```\n[████████████████████████░░░░░░░░░░░░] 150/200 (75.0%) | Elapsed: 15s | ETA: 5s\n\n[0][localhost:8080] 200 -\u003e 45ms\n[0][localhost:8081] 200 -\u003e 47ms\n\n[12][localhost:8080] 200 -\u003e 5ms\n[12][localhost:8081] 200 -\u003e 6ms\n  [DIFF] Request 12 - GET /users/42:\n    Response bodies differ:\n      localhost:8080: {\"id\":42,\"name\":\"Liakos koulaxis\"}\n      localhost:8081: {\"id\":42,\"name\":\"Liakos Koulaxis Jr.\",\"version\":\"v2\"}\n\n[45][localhost:8080] 200 -\u003e 3ms\n[45][localhost:8081] 404 -\u003e 2ms\n  [DIFF] Request 45 - GET /users/678:\n    Status codes differ: localhost:8080=200 localhost:8081=404\n\n==== Summary ====\nOverall Statistics:\nTotal Requests: 200\nSucceeded:      195\nFailed:         5\nDifferences:    23\n\nLatency (ms):\n  min: 2\n  avg: 45\n  p50: 42\n  p90: 78\n  p95: 95\n  p99: 124\n  max: 2001\n\nPer-Target Statistics:\n\nlocalhost:8080:\n  Succeeded: 98\n  Failed:    2\n  Latency:\n    min: 2\n    avg: 43\n    p50: 40\n    p90: 75\n    p95: 92\n    p99: 120\n    max: 2001\n\nlocalhost:8081:\n  Succeeded: 97\n  Failed:    3\n  Latency:\n    min: 2\n    avg: 47\n    p50: 44\n    p90: 81\n    p95: 98\n    p99: 128\n    max: 3002\n```\n\n### JSON Output\n\n```json\n{\n  \"results\": [\n    {\n      \"index\": 0,\n      \"request\": {\n        \"method\": \"GET\",\n        \"path\": \"/users/123\",\n        \"headers\": {\"Content-Type\": \"application/json\"},\n        \"body\": null\n      },\n      \"responses\": {\n        \"localhost:8080\": {\n          \"index\": 0,\n          \"status\": 200,\n          \"latency_ms\": 45,\n          \"body\": \"{\\\"id\\\":123,\\\"name\\\":\\\"Liakos koulaxis\\\"}\"\n        },\n        \"localhost:8081\": {\n          \"index\": 0,\n          \"status\": 200,\n          \"latency_ms\": 47,\n          \"body\": \"{\\\"id\\\":123,\\\"name\\\":\\\"Liakos koulaxis\\\",\\\"version\\\":\\\"v2\\\"}\"\n        }\n      },\n      \"diff\": {\n        \"status_mismatch\": false,\n        \"body_mismatch\": true,\n        \"body_diffs\": {\n          \"localhost:8080\": \"{\\\"id\\\":123,\\\"name\\\":\\\"Liakos koulaxis\\\"}\",\n          \"localhost:8081\": \"{\\\"id\\\":123,\\\"name\\\":\\\"Liakos koulaxis\\\",\\\"version\\\":\\\"v2\\\"}\"\n        }\n      }\n    }\n  ],\n  \"summary\": {\n    \"total_requests\": 200,\n    \"succeeded\": 195,\n    \"failed\": 5,\n    \"latency\": {\n      \"p50\": 42,\n      \"p90\": 78,\n      \"p95\": 95,\n      \"p99\": 124,\n      \"min\": 2,\n      \"max\": 2001,\n      \"avg\": 45\n    },\n    \"by_target\": {\n      \"localhost:8080\": {\n        \"succeeded\": 98,\n        \"failed\": 2,\n        \"latency\": {...}\n      }\n    }\n  }\n}\n```\n\n## Real-World Use Cases\n\n### 1. Production to Staging Validation with Auth \u0026 HTML Report\n\n**Problem:** Is staging behaving exactly like production?\n\n```bash\n# Parse logs\n./replayer --input-file prod_traffic.log --parse-nginx prod_traffic.json\n\n# Replay and compare with auth\n./replayer \\\n  --input-file prod_traffic.json \\\n  --auth \"Bearer ${STAGING_TOKEN}\" \\\n  --compare \\\n  --html-report staging_validation.html \\\n  --rate-limit 100 \\\n  staging.api.example.com \\\n  production.api.example.com\n```\n\n**What you get:** Instant visibility into any behavioral differences between environments\n\n### 2. Performance Regression Testing\n**Problem:** Did the new version slow down any endpoints?\n\n```bash\n./replayer --input-file baseline_traffic.json --compare old-api.com new-api.com\n```\n\n**What you get:** Side-by-side latency comparison for every endpoint\n\n### 3. Migration Validation\n**Problem:** Can the new infrastructure handle production load?\n\n```bash\n./replayer --input-file prod_logs.json --rate-limit 1000 --concurrency 50 new-infra.com\n```\n\n**What you get:** Confidence that your new infrastructure can handle real traffic patterns\n\n### 4. API Contract Testing\n**Problem:** Did the API response format change?\n\n```bash\n./replayer --input-file api_calls.json --compare --output-json v1.api v2.api \u003e diff.json\n```\n\n**What you get:** Automated detection of breaking changes\n\n### 5. Load Testing with Real Patterns\n**Problem:** Synthetic load tests don't match real usage.\n\n```bash\n./replayer --input-file peak_hour_traffic.json --rate-limit 500 api.example.com\n```\n\n**What you get:** Load testing based on actual production traffic patterns\n\n## Tips\n\n### Filtering for Specific Scenarios\n\n```bash\n# Only test authentication endpoints\n./replayer --input-file logs.json --filter-path /auth localhost:8080\n\n# Only test write operations\n./replayer --input-file logs.json --filter-method POST localhost:8080\n\n# Test just the first 50 requests\n./replayer --input-file logs.json --limit 50 localhost:8080\n```\n\n### Rate Limiting Strategies\n\n```bash\n# Gentle ramp-up: 10 req/s\n./replayer --input-file logs.json --rate-limit 10 --concurrency 5 api.com\n\n# Stress test: 1000 req/s\n./replayer --input-file logs.json --rate-limit 1000 --concurrency 100 api.com\n\n# Sustained load test with unlimited rate\n./replayer --input-file logs.json --concurrency 50 api.com\n```\n\n### CI/CD Integration\n\n```bash\n#!/bin/bash\n# compare staging to production and fail if differences found\n\n./replayer --input-file smoke_tests.json --compare --output-json \\\n  staging.api production.api \u003e results.json\n\nDIFFS=$(cat results.json | jq '[.results[] | select(.diff != null)] | length')\n\nif [ \"$DIFFS\" -gt 0 ]; then\n  echo \"Found $DIFFS differences between staging and production\"\n  exit 1\nelse\n  echo \"Staging matches production\"\nfi\n```\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request\n\n## Show Your Support\n\nIf this tool helped you catch bugs or validate deployments, give it a star! ⭐\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkx0101%2Freplayer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkx0101%2Freplayer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkx0101%2Freplayer/lists"}