Skip to main content

AI Gateway Analytics

DreamFactory's AI Gateway provides org-wide visibility into AI usage, cost, and performance. Every request through an AI Connection (direct API calls, AI Chat sessions, and OpenAI-compatible endpoint traffic) is logged with full attribution: which user, role, app, provider, model, and service handled the request, along with token counts, cost, latency, and status.

The Gateway analytics are available through admin API endpoints and power the admin dashboard's AI section.

Commercial Feature

AI Gateway Analytics requires a DreamFactory commercial license (Gold or Platinum).

Usage Logging

Every AI provider call writes a row to the ai_usage_log table with:

ColumnDescription
service_idWhich AI Connection handled the request
user_idThe DreamFactory user who made the request
role_idThe role in effect
app_idThe application (API key) used
resourceRequest type: chat, completion, chat-session, data-chat, openai_compat
providerUpstream provider (anthropic, openai, xai, ollama, openai_compatible)
modelModel used (e.g. gpt-4o, claude-sonnet-4-5-20250929)
input_tokensTokens consumed in the request
output_tokensTokens generated in the response
cost_usdEstimated cost in USD (computed at log time from per-model rates, service rates, or provider defaults)
latency_msRound-trip time in milliseconds
tool_call_countNumber of tool calls in agentic loops
statussuccess, partial (streaming disconnect), or error
error_messageError details (for failed requests)
request_idUUID correlating usage, prompt log, and audit events

Status Types

  • success: The provider returned a complete response.
  • partial: A streaming request where the client disconnected before completion. Tokens consumed up to the disconnect are still counted.
  • error: The provider returned an error or the connection failed. Cost is zero for error rows.

Analytics Dashboard API

GET /_internal/ai/usage (admin only)

Returns the full analytics payload for the dashboard. Supports filtering and period-over-period comparison.

Query Parameters

ParameterDefaultDescription
period7dTime window: 24h, 7d, 30d, 90d, or any {n}d / {n}h format
compare0Set to 1 to include a previous block with the same metrics for the immediately preceding window
providerFilter by provider name
service_idFilter by AI Connection service ID
modelFilter by model name
user_idFilter by user ID
role_idFilter by role ID
app_idFilter by app ID
resourceFilter by resource type
statusFilter by status

Response Shape

{
"period": "7d",
"since": "2026-05-25T00:00:00+00:00",
"total_requests": 15420,
"total_input_tokens": 2345670,
"total_output_tokens": 890120,
"total_cost_usd": 47.23,
"errors": 31,
"partials": 8,
"avg_latency_ms": 1340,
"latency_p50_ms": 980,
"latency_p95_ms": 3200,
"latency_p99_ms": 8500,
"by_service": [...],
"by_user": [...],
"by_role": [...],
"by_app": [...],
"by_provider": [...],
"by_model": [...],
"by_resource": [...],
"by_error_class": [...],
"series": [...],
"series_by_model": [...],
"series_by_user": [...],
"series_by_app": [...],
"series_by_provider": [...],
"most_expensive_calls": [...],
"budgets": [...],
"default_rates": {...},
"filters": {...}
}

Key Sections

Latency percentiles (latency_p50_ms, latency_p95_ms, latency_p99_ms): Cross-database compatible. Useful for identifying whether latency issues affect the median user or just tail requests.

By-model breakdown (by_model): Includes cost_per_1k_tokens for each model, showing the effective rate you are paying. Helps answer "is this premium model worth its rate?"

Error classification (by_error_class): Errors are automatically classified into categories: timeout, rate_limit, auth, model_not_found, context_overflow, connectivity, provider_5xx, provider_4xx, other. Helps identify whether an error spike is a rate-limit problem or a provider outage.

Time series (series, series_by_model, series_by_user, series_by_app, series_by_provider): Daily-bucketed cost-over-time breakdowns. The series_by_* variants show top-10 spenders plus an __other__ bucket so stacked charts don't silently undercount.

Most expensive calls (most_expensive_calls): Top 10 costliest individual requests in the window. Surfaces outliers (e.g. a single 200K-token request) that averages hide.

Period comparison (when compare=1): The previous block contains the same summary metrics (totals, percentiles) for the window immediately before the current one. Powers period-over-period delta indicators.

Budget Management

Per-Service Monthly Budgets

Set monthly_budget_usd on an AI Connection to enable spend projection. The dashboard's budgets array returns:

{
"service_id": 5,
"monthly_budget_usd": 500.00,
"spent_month_usd": 187.42,
"projected_month_end_usd": 374.84,
"days_into_month": 15,
"days_in_month": 30,
"on_track": true
}

Services are sorted by risk (highest projected overshoot first).

Multi-Dimensional Budget Rules

For fine-grained control, create rows in the ai_budget table:

FieldDescription
dimension_typeglobal, service, user, role, or app
dimension_idThe ID of the target entity (null for global)
periodhourly, daily, or monthly
budget_usdSpend cap in USD
hard_stopWhen true, requests are blocked (HTTP 429) once the cap is reached
alert_webhook_urlURL to receive threshold-crossing notifications
alert_webhook_auth_headerOptional Authorization header for the webhook
labelHuman-readable label for alerts

Budget Alerts

When a budget crosses 50%, 80%, or 100% utilization, the configured webhook fires with a structured payload:

{
"event": "ai.budget.threshold_crossed",
"threshold_pct": 80,
"budget": {
"id": 3,
"label": "Engineering team monthly",
"dimension_type": "role",
"dimension_id": 7,
"period": "monthly",
"budget_usd": 1000.00,
"hard_stop": false
},
"spend": {
"spend_usd": 812.45,
"remaining_usd": 187.55,
"utilization": 0.8125
},
"@timestamp": "2026-06-01T14:30:00+00:00"
}

Each threshold fires once per period. Thresholds reset automatically at the start of each new period.

Prompt Logging

Prompt logging records the full request and response text for AI calls. It is off by default and must be enabled per AI Connection.

Configuration

Prompt logging is controlled at two levels:

  1. Global kill switch: Set df-ai.prompt_logging.global_enabled to false in the config to disable prompt logging across the entire instance. Use this for deployments that legally cannot store prompts.

  2. Per-connection opt-in: On each AI Connection, enable these fields (available in the config model):

    • prompt_logging_enabled (default: false) -- master switch
    • prompt_redact_pii (default: true) -- apply built-in PII patterns before storage
    • prompt_redaction_rules -- JSON array of custom regex patterns

PII Redaction

When PII redaction is enabled, the following patterns are automatically scrubbed from prompts and responses before storage:

PatternDescription
Credit card numbers13-19 digit sequences with Luhn validation (reduces false positives)
SSNUS Social Security Numbers in 3-2-4 dashed format
Email addressesRFC-5322-ish pattern
US phone numbersNANP format with separators
Medical Record Numbers"MRN" or "Medical Record Number" followed by an alphanumeric ID

These built-in patterns prioritize low false-positive rates over completeness. For comprehensive DLP coverage (passports, driver's licenses, IBANs, etc.), configure custom redaction rules or integrate a cloud DLP service.

Custom Redaction Rules

Add custom patterns via the prompt_redaction_rules field (JSON array):

[
{"pattern": "/\\bACCT-\\d{6,10}\\b/", "label": "ACCOUNT_ID"},
{"pattern": "/\\bPATIENT-\\w{8}\\b/i", "label": "PATIENT_ID", "replacement": "[REMOVED]"}
]

Each rule has:

  • pattern: A PHP regex pattern
  • label (optional): The label used in the replacement placeholder. Default: CUSTOM
  • replacement (optional): Custom replacement text. Default: [REDACTED:{label}]

Prompt Log Schema

Logged prompts are stored in ai_prompt_log with:

ColumnDescription
request_idCorrelates to the ai_usage_log row for the same call
service_idAI Connection service ID
user_id, role_id, app_idAttribution
provider, model, resourceRequest metadata
request_payloadRedacted request text
response_payloadRedacted response text
redaction_countTotal PII replacements made (for "what % of traffic triggers redaction" analytics)
original_size_bytesPre-redaction payload size
statussuccess, partial, or error

SIEM Integration

DreamFactory supports both push-based and pull-based SIEM integration for AI audit events.

Push: Webhook Dispatch

Configure audit_webhook_url on an AI Connection to push ECS-shaped audit events to your SIEM after every AI call.

FieldDescription
audit_webhook_urlEndpoint URL for the webhook
audit_webhook_formatEvent format: ecs (default), splunk_hec, or datadog
audit_webhook_auth_headerOptional Authorization header value

Webhook dispatch is best-effort with a 5-second timeout. Failures are logged as warnings but never break the AI response. The ai_usage_log + ai_prompt_log tables remain the source of truth.

Push: File Sink

Enable audit_file_sink_enabled on an AI Connection to append NDJSON events to a log file. Default path: /var/log/dreamfactory/ai-audit.log.

This works well with Logstash's file input plugin for a zero-configuration SIEM pipeline.

Pull: Audit Stream Endpoint

GET /_internal/ai/audit-stream (admin only)

Returns a newline-delimited JSON (NDJSON) stream of ECS-shaped audit events. Designed for Logstash's http_poller input, Splunk's HTTP input, Datadog HTTP intake, or any pull-based pipeline.

Query parameters:

ParameterDefaultDescription
since5 minutes agoISO-8601 start timestamp
untilnowISO-8601 end timestamp
limit1000Max events (capped at 5000)

Response headers:

Content-Type: application/x-ndjson

Example Logstash configuration:

input {
http_poller {
urls => {
dreamfactory_ai => {
url => "https://df.example/_internal/ai/audit-stream?since=<last_max_timestamp>"
headers => {
"X-DreamFactory-API-Key" => "your-admin-api-key"
"X-DreamFactory-Session-Token" => "your-session-token"
}
}
}
schedule => { cron => "* * * * *" }
codec => "json_lines"
}
}

Event Formats

All audit events follow the Elastic Common Schema (ECS) base shape. The audit_webhook_format setting controls the envelope:

  • ecs (default): Raw ECS event. Works with Elastic/Logstash directly.
  • splunk_hec: Wrapped in Splunk HTTP Event Collector format with event, time, source, sourcetype fields.
  • datadog: Wrapped in Datadog log intake format with ddsource, ddtags, message fields.

Test Connection

POST /_internal/ai/test-connection (admin only)

Validates provider credentials before saving a service. Attempts to list models from the provider with the given config. Useful for the admin UI's "Test Connection" button.

Request:

{
"provider": "anthropic",
"api_key": "sk-ant-...",
"service_id": 5
}

When service_id is provided and api_key is blank, the endpoint falls back to the saved credentials, so admins can test without re-entering secrets.

Cost Calculation

Cost is computed at log time using a three-tier lookup:

  1. Per-model rate sheet on the AI Connection (most specific)
  2. Service-level flat rates (cost_per_1k_input, cost_per_1k_output)
  3. Built-in provider defaults maintained by DreamFactory

Because cost is computed and stored at log time, price changes do not retroactively rewrite historical data.

Data Retention

Usage and prompt logs can be pruned via artisan commands:

php artisan ai:prune-usage-logs    # Default retention: 90 days
php artisan ai:prune-prompt-logs

Schedule these commands via cron to keep database size manageable in high-volume deployments.