Skip to content

feat(mavvrik): add Mavvrik integration for automatic LLM spend export#26573

Merged
oss-pr-review-agent-shin[bot] merged 1 commit into
BerriAI:litellm_agent_oss_staging_05_11_2026from
cloudwizio:mavvrik/berriai-pr
May 11, 2026
Merged

feat(mavvrik): add Mavvrik integration for automatic LLM spend export#26573
oss-pr-review-agent-shin[bot] merged 1 commit into
BerriAI:litellm_agent_oss_staging_05_11_2026from
cloudwizio:mavvrik/berriai-pr

Conversation

@pghuge-cloudwiz

@pghuge-cloudwiz pghuge-cloudwiz commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

What is Mavvrik?

Mavvrik is an AI cost management platform. This PR adds a native LiteLLM integration that automatically exports daily LLM spend data from the LiteLLM proxy to Mavvrik for cost tracking, attribution, and analysis.

Key Features

  • Zero-config startup — add callbacks: ["mavvrik"] and set three env vars; the proxy begins exporting automatically
  • Streaming export — fetches DB page-by-page (10k rows/page), gzip-compresses on-the-fly, uploads via GCS chunked resumable upload. No row limit, ~2MB peak RAM. Validated: 500k rows → 13MB / 84s
  • Idempotent by date — each calendar date gets its own GCS object; re-exporting the same date safely overwrites the previous upload
  • Catch-up on restart — back-fills all missed days automatically from the Mavvrik-owned marker on the next scheduled run
  • Pod-safe — Redis distributed lock prevents duplicate exports in multi-replica deployments
  • Encrypted credentials — API key stored AES-encrypted via LiteLLM's config store

Module Layout

File Responsibility
litellm/integrations/mavvrik/__init__.py Public Service facade — business logic for each endpoint
litellm/integrations/mavvrik/client.py Mavvrik REST API calls (register, signed URL, advance marker, report error)
litellm/integrations/mavvrik/exporter.py DB → DataFrame → CSV (OFFSET-paginated streaming)
litellm/integrations/mavvrik/uploader.py GCS resumable upload (bulk + streaming chunked)
litellm/integrations/mavvrik/orchestrator.py Pod lock + catch-up date loop + upload + advance marker
litellm/integrations/mavvrik/logger.py CustomLogger subclass — per-request cost logging
litellm/integrations/mavvrik/settings.py AES-encrypted credential persistence via LiteLLM config store
litellm/integrations/mavvrik/_http.py Shared httpx transport with retry + exponential backoff
litellm/proxy/spend_tracking/mavvrik_endpoints.py FastAPI router — thin dispatchers over Service
litellm/types/proxy/mavvrik_endpoints.py Pydantic request/response models

API Endpoints Added

All endpoints require PROXY_ADMIN role.

Method Endpoint Description
POST /mavvrik/init Store encrypted credentials + register background export job
GET /mavvrik/settings View current settings (API key masked)
PUT /mavvrik/settings Update one or more credential fields
DELETE /mavvrik/delete Remove all settings and deregister the background job
POST /mavvrik/dry-run Preview CSV records without uploading
POST /mavvrik/export Trigger a manual upload for a specific date

Quickstart

Step 1: Add mavvrik to your config.yaml

litellm_settings:
  callbacks: ["mavvrik"]

Step 2: Set env vars

export MAVVRIK_API_KEY="mav_xxxxxxxxxx"
export MAVVRIK_API_ENDPOINT="https://api.mavvrik.dev/<TENANT_ID>"
export MAVVRIK_CONNECTION_ID="litellm-prod"

Step 3: Start the proxy

litellm --config config.yaml

LiteLLM will automatically export spend data to Mavvrik on an hourly schedule.

Test Coverage

Unit tests in tests/test_litellm/integrations/mavvrik/:

  • test_client.py — REST calls + retry logic
  • test_exporter.py — DB query + CSV serialization
  • test_orchestrator.py — date-loop + pod-lock logic
  • test_settings.py — credential load/save/mask
  • test_transform.py — CSV field transforms
  • test_upload.py — GCS protocol steps
  • test_uploader.py — streaming chunked upload

Test Plan

  • make test-unit passes
  • Docker e2e: proxy starts, /mavvrik/init stores creds, background job schedules, /mavvrik/export uploads to GCS
  • GCS object created with gzip-compressed CSV for target date (validated: 500k rows → 13MB / 84s)
  • /mavvrik/dry-run returns CSV preview without uploading
  • Scheduler fires automatically and back-fills all missed dates

Related

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a complete Mavvrik integration that streams LiteLLM spend data from Postgres to GCS as gzip-compressed CSV, with encrypted credential persistence, a Redis pod lock, catch-up date backfill, and six new admin REST endpoints. The implementation follows the CloudZero/Vantage patterns in the codebase and the router + startup job are correctly registered. Remaining findings are all P2: routine pipeline progress messages are logged at WARNING rather than INFO throughout orchestrator.py, GzipFile is not explicitly closed in the no-data early-return path of _stream_upload, and update_settings on an env-var-only deployment without a connected database surfaces an opaque HTTP 500 instead of a helpful error.

Confidence Score: 5/5

Safe to merge — all findings are P2 style/UX issues with no impact on correctness or data integrity.

No P0 or P1 bugs found in the new code. The three flagged issues are: informational log messages at the wrong severity level, a minor GzipFile resource management inconsistency (no real leak), and a missing pre-check guard that produces a generic 500 instead of a clear error message for an edge-case deployment topology. All critical concerns raised in prior review rounds have been addressed in the current HEAD.

No files require special attention; the three P2 findings are spread across orchestrator.py, uploader.py, and integrations/mavvrik/init.py.

Important Files Changed

Filename Overview
litellm/integrations/mavvrik/init.py Service facade wiring all Mavvrik endpoints; update_settings may surface an opaque 500 on env-var-only + no-DB deployments.
litellm/integrations/mavvrik/orchestrator.py Pod-lock + date-loop pipeline; routine status messages logged at WARNING instead of INFO throughout.
litellm/integrations/mavvrik/uploader.py GCS resumable upload implementation; GzipFile not closed in the no-data early-return path (minor resource management inconsistency).
litellm/integrations/mavvrik/exporter.py DB → polars DataFrame → CSV with OFFSET pagination; correctly handles DB-unavailable paths with warnings.
litellm/integrations/mavvrik/client.py Mavvrik REST API client wrapping register, advance_marker, report_error, and get_signed_url; well-structured with best-effort error reporting.
litellm/integrations/mavvrik/settings.py AES-encrypted credential persistence via LiteLLM_Config; correct encryption/decryption with appropriate error handling for key mismatches.
litellm/proxy/spend_tracking/mavvrik_endpoints.py FastAPI router with thin dispatchers over Service; centralised exception mapping and admin-only access control applied consistently.
litellm/proxy/proxy_server.py Adds mavvrik_router registration and startup scheduling; correctly falls back to env vars when no DB row exists during startup.
litellm/integrations/mavvrik/_http.py Shared async HTTP transport with 3-attempt retry and exponential backoff; reuses the LiteLLM shared httpx client pool correctly.
litellm/types/proxy/mavvrik_endpoints.py Pydantic request/response models with appropriate field validators; correctly marks api_key as non-repr for logging safety.

Sequence Diagram

sequenceDiagram
    participant EP as mavvrik_endpoints.py
    participant SVC as Service
    participant ORCH as Orchestrator
    participant EXP as Exporter
    participant UPL as Uploader
    participant CLI as Client (Mavvrik API)
    participant GCS as GCS

    Note over EP,GCS: POST /mavvrik/init — store creds + schedule background job
    EP->>SVC: initialize(api_key, endpoint, connection_id)
    SVC->>SVC: Settings.save() [encrypt + upsert DB]
    SVC->>ORCH: scheduler.add_job(orchestrator.run, interval=60min)

    Note over EP,GCS: Scheduled export run (APScheduler)
    ORCH->>ORCH: acquire Redis pod lock
    ORCH->>CLI: register() → metricsMarker (start date)
    loop for each date in [start, yesterday]
        ORCH->>EXP: _stream_pages(date, page_size=10k)
        EXP->>EXP: DB query_raw LIMIT/OFFSET
        EXP-->>ORCH: AsyncGenerator[csv_chunk]
        ORCH->>UPL: _stream_upload(pages, date)
        UPL->>CLI: get_signed_url(date)
        CLI-->>UPL: GCS signed URL
        UPL->>GCS: POST signed_url (initiate resumable)
        GCS-->>UPL: session_uri
        loop per 256KB chunk
            UPL->>GCS: PUT session_uri (chunk)
        end
        UPL->>GCS: PUT session_uri (final chunk)
        ORCH->>CLI: advance_marker(next_date_epoch)
    end
    ORCH->>ORCH: release Redis pod lock

    Note over EP,GCS: POST /mavvrik/export — manual trigger
    EP->>SVC: export(date_str, limit)
    SVC->>EXP: export(date_str, limit) → DataFrame + CSV
    SVC->>UPL: upload(csv, date_str) [bulk path]
    UPL->>CLI: get_signed_url(date_str)
    UPL->>GCS: POST + PUT (initiate + finalize)
Loading

Reviews (14): Last reviewed commit: "feat(mavvrik): add Mavvrik integration f..." | Re-trigger Greptile

Comment thread litellm/litellm_core_utils/litellm_logging.py
Comment thread litellm/litellm_core_utils/litellm_logging.py
Comment thread litellm/integrations/mavvrik/exporter.py
Comment thread litellm/integrations/mavvrik/uploader.py
Comment thread litellm/integrations/mavvrik/__init__.py
@codecov

codecov Bot commented Apr 27, 2026

Copy link
Copy Markdown

Comment thread litellm/integrations/mavvrik/__init__.py
@pghuge-cloudwiz pghuge-cloudwiz force-pushed the mavvrik/berriai-pr branch 2 times, most recently from 2fb17ab to b40e754 Compare April 27, 2026 06:19
Comment thread litellm/litellm_core_utils/litellm_logging.py Outdated
@veria-ai

veria-ai Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Mavvrik spend export integration added

This PR adds admin-gated Mavvrik configuration endpoints, encrypted settings storage, scheduled/manual spend export, and a GCS upload client. I reviewed the new auth gates, raw SQL parameterization, outbound HTTP flow, settings encryption/decryption, and response models and did not identify security issues in the changes introduced by this PR.


Status: 6 open
Risk: 2/10

Comment thread litellm/integrations/mavvrik/exporter.py
Comment thread litellm/proxy/spend_tracking/mavvrik_endpoints.py
Comment thread litellm/integrations/mavvrik/exporter.py
Comment thread litellm/proxy/proxy_server.py Outdated
Comment thread litellm/integrations/mavvrik/__init__.py
Comment thread litellm/integrations/mavvrik/exporter.py
Comment thread litellm/integrations/mavvrik/exporter.py
Comment thread litellm/integrations/mavvrik/exporter.py
Comment thread litellm/integrations/mavvrik/exporter.py
@pghuge-cloudwiz pghuge-cloudwiz force-pushed the mavvrik/berriai-pr branch 5 times, most recently from f84425b to 01f7668 Compare April 28, 2026 01:50
Comment thread litellm/integrations/mavvrik/__init__.py Outdated
@krrish-berri-2

Copy link
Copy Markdown
Contributor

branch is out of sync with the base branch and must be rebased before it can even be considered

@krrish-berri-2

Copy link
Copy Markdown
Contributor

please remove any docs on this pr - and make the relevant pr on litellm-docs repo

@pghuge-cloudwiz pghuge-cloudwiz force-pushed the mavvrik/berriai-pr branch 2 times, most recently from 3466ab1 to 60a785d Compare May 9, 2026 00:19
Comment thread litellm/types/proxy/mavvrik_endpoints.py
Comment thread litellm/types/proxy/mavvrik_endpoints.py
@pghuge-cloudwiz pghuge-cloudwiz force-pushed the mavvrik/berriai-pr branch 2 times, most recently from 85fd9cf to bfc95a1 Compare May 11, 2026 04:34
Adds a complete integration with Mavvrik (https://help.mavvrik.ai/) for
automatically exporting LiteLLM proxy spend data to the Mavvrik AI cost
management platform.

- Zero-config startup — set MAVVRIK_API_KEY, MAVVRIK_API_ENDPOINT,
  MAVVRIK_CONNECTION_ID env vars; proxy begins exporting automatically
- Streaming export — fetches DB page-by-page (10k rows/page via OFFSET
  pagination with stable ORDER BY), gzip-compresses on-the-fly, uploads
  via GCS chunked resumable upload (256KB chunks). No row limit, ~2MB
  peak RAM. Validated: 500k rows → 13MB / 84s.
- Idempotent by date — each calendar date has its own GCS object
- Catch-up on restart — back-fills all missed days from Mavvrik marker
- Pod-safe — Redis distributed lock for multi-replica deployments
- Admin endpoints — init, settings, update, delete, dry-run, export

  litellm/integrations/mavvrik/
    _http.py        Shared HTTP transport (retry + exponential backoff)
    client.py       Mavvrik REST API (register, advance_marker, signed URL)
    uploader.py     GCS resumable upload (bulk + streaming, session cleanup)
    exporter.py     DB fetch (4-table JOIN, stable pagination) + CSV
    orchestrator.py Pipeline sequencing + pod lock
    settings.py     AES-encrypted credential persistence
    logger.py       CustomLogger marker for callback registry
    __init__.py     Service facade + lazy import to avoid polars at startup

- update_settings reschedules background job with new credentials
- delete works for env-var-only deployments (no DB row required)
- dry_run guards NULL spend and missing completion_tokens column
- GCS session cancelled on mid-stream _put_chunk failure
- DB connectivity guard in Service.export/dry_run
- Stable OFFSET pagination (ORDER BY includes dus.id as tiebreaker)
- mavvrik_endpoints uses lazy import to keep polars out of startup path

164 mock-based unit tests across 10 files covering all components.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@oss-pr-review-agent-shin oss-pr-review-agent-shin Bot changed the base branch from litellm_internal_staging to litellm_agent_oss_staging_05_11_2026 May 11, 2026 18:41
@oss-pr-review-agent-shin oss-pr-review-agent-shin Bot merged commit cf6fd9d into BerriAI:litellm_agent_oss_staging_05_11_2026 May 11, 2026
39 of 42 checks passed
@oss-pr-review-agent-shin

Copy link
Copy Markdown
Contributor

🤖 litellm-agent: Squash-merged into staging branch litellm_agent_oss_staging_05_11_2026. Staging PR: #27664


Triage Summary
Gathered PR data only — the triage LLM step did not produce a valid report, so failing-check classification and prior-signal reconciliation were skipped. 5676 line(s) across 27 file(s) (+5675/-1).

5676 lines across 27 files (+5675 / -1)

Merge Confidence: 5/5 ✅ READY
Ready to ship.

All checks green. Greptile 5/5, no blocking pattern findings, no CircleCI runs (OSS-typical).

pghuge-cloudwiz added a commit to cloudwizio/litellm that referenced this pull request Jun 10, 2026
pghuge-cloudwiz added a commit to cloudwizio/litellm that referenced this pull request Jun 11, 2026
pghuge-cloudwiz added a commit to cloudwizio/litellm that referenced this pull request Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants