Mistral AI Observability
Overview
Monitor Mistral AI API usage, latency, token consumption, error rates, and costs. Covers instrumented client wrapper, Prometheus metrics, Grafana dashboard panels, alerting rules, and structured logging.
Prerequisites
- Mistral API integration in production
- Prometheus or OpenTelemetry-compatible metrics backend
- Alerting system (Alertmanager, PagerDuty, or similar)
Instructions
Step 1: Instrumented Client Wrapper
import { Mistral } from '@mistralai/mistralai';
const PRICING: Record<string, { input: number; output: number }> = {
'mistral-small-latest': { input: 0.10, output: 0.30 },
'mistral-large-latest': { input: 0.50, output: 1.50 },
'codestral-latest': { input: 0.30, output: 0.90 },
'mistral-embed': { input: 0.10, output: 0 },
};
interface MetricsEvent {
model: string;
endpoint: string;
durationMs: number;
status: 'success' | 'error';
statusCode?: number;
inputTokens?: number;
outputTokens?: number;
costUsd?: number;
}
function emitMetrics(event: MetricsEvent): void {
// Push to your metrics backend (Prometheus, Datadog, etc.)
console.log(JSON.stringify({ type: 'mistral_metric', ...event }));
}
async function instrumentedChat(
client: Mistral,
model: string,
messages: any[],
options?: any,
) {
const start = performance.now();
try {
const response = await client.chat.complete({ model, messages, ...options });
const duration = Math.round(performance.now() - start);
const pricing = PRICING[model] ?? PRICING['mistral-small-latest'];
const pt = response.usage?.promptTokens ?? 0;
const ct = response.usage?.completionTokens ?? 0;
emitMetrics({
model,
endpoint: 'chat.complete',
durationMs: duration,
status: 'success',
inputTokens: pt,
outputTokens: ct,
costUsd: (pt / 1e6) * pricing.input + (ct / 1e6) * pricing.output,
});
return response;
} catch (error: any) {
emitMetrics({
model,
endpoint: 'chat.complete',
durationMs: Math.round(performance.now() - start),
status: 'error',
statusCode: error.status,
});
throw error;
}
}
Step 2: Prometheus Metrics
// Using prom-client
import { Counter, Histogram, Gauge } from 'prom-client';
const mistralRequests = new Counter({
name: 'mistral_requests_total',
help: 'Total Mistral API requests',
labelNames: ['model', 'endpoint', 'status'],
});
const mistralDuration = new Histogram({
name: 'mistral_request_duration_ms',
help: 'Mistral request duration in milliseconds',
labelNames: ['model', 'endpoint'],
buckets: [100, 250, 500, 1000, 2500, 5000, 10000],
});
const mistralTokens = new Counter({
name: 'mistral_tokens_total',
help: 'Total tokens consumed',
labelNames: ['model', 'direction'], // direction: input | output
});
const mistralCost = new Counter({
name: 'mistral_cost_usd_total',
help: 'Estimated cost in USD',
labelNames: ['model'],
});
const mistralErrors = new Counter({
name: 'mistral_errors_total',
help: 'Total Mistral errors',
labelNames: ['model', 'status_code'],
});
// Record metrics from instrumented wrapper
function recordPrometheusMetrics(event: MetricsEvent): void {
mistralRequests.inc({ model: event.model, endpoint: event.endpoint, status: event.status });
mistralDuration.observe({ model: event.model, endpoint: event.endpoint }, event.durationMs);
if (event.status === 'success') {
if (event.inputTokens) mistralTokens.inc({ model: event.model, direction: 'input' }, event.inputTokens);
if (event.outputTokens) mistralTokens.inc({ model: event.model, direction: 'output' }, event.outputTokens);
if (event.costUsd) mistralCost.inc({ model: event.model }, event.costUsd);
} else {
mistralErrors.inc({ model: event.model, status_code: String(event.statusCode ?? 'unknown') });
}
}
Step 3: Alerting Rules
# prometheus/mistral-alerts.yaml
groups:
- name: mistral
rules:
- alert: MistralHighErrorRate
expr: rate(mistral_errors_total[5m]) / rate(mistral_requests_total[5m]) > 0.05
for: 5m
labels: { severity: critical }
annotations:
summary: "Mistral error rate exceeds 5%"
runbook: "See mistral-incident-runbook skill"
- alert: MistralHighLatency
expr: histogram_quantile(0.95, rate(mistral_request_duration_ms_bucket[5m])) > 5000
for: 5m
labels: { severity: warning }
annotations:
summary: "Mistral P95 latency exceeds 5 seconds"
- alert: MistralRateLimited
expr: rate(mistral_errors_total{status_code="429"}[5m]) > 0
for: 2m
labels: { severity: warning }
annotations:
summary: "Mistral rate limiting detected"
- alert: MistralCostSpike
expr: increase(mistral_cost_usd_total[1h]) > 10
labels: { severity: warning }
annotations:
summary: "Mistral spend exceeds $10/hour"
- alert: MistralAuthFailure
expr: increase(mistral_errors_total{status_code="401"}[5m]) > 0
labels: { severity: critical }
annotations:
summary: "Mistral authentication failing — API key may be revoked"
Step 4: Grafana Dashboard Panels
Key panels to create:
| Panel |
Query |
Type |
| Request Rate |
rate(mistral_requests_total[5m]) |
Time series |
| P50/P95/P99 Latency |
histogram_quantile(0.95, rate(..._bucket[5m])) |
Time series |
| Token Velocity |
rate(mistral_tokens_total{direction="output"}[5m]) |
Time series |
| Hourly Cost |
increase(mistral_cost_usd_total[1h]) |
Stat |
| Error Rate |
rate(mistral_errors_total[5m]) by status_code |
Time series |
| Model Distribution |
sum by (model) (rate(mistral_requests_total[5m])) |
Pie chart |
Step 5: Structured Log Format
interface MistralLogEntry {
ts: string;
level: 'info' | 'warn' | 'error';
model: string;
endpoint: string;
durationMs: number;
inputTokens?: number;
outputTokens?: number;
costUsd?: number;
status: string;
statusCode?: number;
requestId?: string;
}
function logMistralRequest(entry: MistralLogEntry): void {
// Ship to SIEM, CloudWatch, or log aggregator
// NEVER log message content — PII risk
console.log(JSON.stringify(entry));
}
Error Handling
| Issue |
Cause |
Solution |
| Missing token counts |
Streaming not aggregated |
Sum tokens from stream chunks |
| Cost drift from bill |
Pricing table outdated |
Update PRICING map when rates change |
| Alert storm on 429s |
Rate limit burst |
Tune alert threshold, add request queue |
| High cardinality |
Per-request labels |
Never label by request ID or user ID |
Resources
Output
- Instrumented client wrapper with timing and cost tracking
- Prometheus metrics (requests, duration, tokens, cost, errors)
- Alerting rules for error rate, latency, rate limits, cost, auth
- Grafana dashboard panel specifications
- Structured logging format for SIEM integration
Source: jeremylongshore/claude-code-plugins-plus-skills → plugins/saas-packs/mistral-pack/skills/mistral-observability/SKILL.md
1---2name: mistral-observability3description: "'Set up comprehensive observability for Mistral AI with metrics, traces, and alerts. Use when implementing monitoring for Mistral AI operations, setting up dashboards, or configuring alerting for integration health. Trigger with phrases like \"mistral monitoring\", \"mistral metrics\", \"mistral observability\", \"monitor mistral\", \"mistral alerts\". '"4allowed-tools: "Read, Write, Edit"5category: devops-and-infra6source_repo: jeremylongshore/claude-code-plugins-plus-skills7source_path: "plugins/saas-packs/mistral-pack/skills/mistral-observability/SKILL.md"8source_url: https://github.com/jeremylongshore/claude-code-plugins-plus-skills/blob/HEAD/plugins/saas-packs/mistral-pack/skills/mistral-observability/SKILL.md9---1011# Mistral AI Observability1213## Overview1415Monitor Mistral AI API usage, latency, token consumption, error rates, and costs. Covers instrumented client wrapper, Prometheus metrics, Grafana dashboard panels, alerting rules, and structured logging.1617## Prerequisites1819- Mistral API integration in production20- Prometheus or OpenTelemetry-compatible metrics backend21- Alerting system (Alertmanager, PagerDuty, or similar)2223## Instructions2425### Step 1: Instrumented Client Wrapper2627```typescript28import { Mistral } from '@mistralai/mistralai';2930const PRICING: Record<string, { input: number; output: number }> = {31 'mistral-small-latest': { input: 0.10, output: 0.30 },32 'mistral-large-latest': { input: 0.50, output: 1.50 },33 'codestral-latest': { input: 0.30, output: 0.90 },34 'mistral-embed': { input: 0.10, output: 0 },35};3637interface MetricsEvent {38 model: string;39 endpoint: string;40 durationMs: number;41 status: 'success' | 'error';42 statusCode?: number;43 inputTokens?: number;44 outputTokens?: number;45 costUsd?: number;46}4748function emitMetrics(event: MetricsEvent): void {49 // Push to your metrics backend (Prometheus, Datadog, etc.)50 console.log(JSON.stringify({ type: 'mistral_metric', ...event }));51}5253async function instrumentedChat(54 client: Mistral,55 model: string,56 messages: any[],57 options?: any,58) {59 const start = performance.now();60 try {61 const response = await client.chat.complete({ model, messages, ...options });62 const duration = Math.round(performance.now() - start);63 const pricing = PRICING[model] ?? PRICING['mistral-small-latest'];64 const pt = response.usage?.promptTokens ?? 0;65 const ct = response.usage?.completionTokens ?? 0;6667 emitMetrics({68 model,69 endpoint: 'chat.complete',70 durationMs: duration,71 status: 'success',72 inputTokens: pt,73 outputTokens: ct,74 costUsd: (pt / 1e6) * pricing.input + (ct / 1e6) * pricing.output,75 });7677 return response;78 } catch (error: any) {79 emitMetrics({80 model,81 endpoint: 'chat.complete',82 durationMs: Math.round(performance.now() - start),83 status: 'error',84 statusCode: error.status,85 });86 throw error;87 }88}89```9091### Step 2: Prometheus Metrics9293```typescript94// Using prom-client95import { Counter, Histogram, Gauge } from 'prom-client';9697const mistralRequests = new Counter({98 name: 'mistral_requests_total',99 help: 'Total Mistral API requests',100 labelNames: ['model', 'endpoint', 'status'],101});102103const mistralDuration = new Histogram({104 name: 'mistral_request_duration_ms',105 help: 'Mistral request duration in milliseconds',106 labelNames: ['model', 'endpoint'],107 buckets: [100, 250, 500, 1000, 2500, 5000, 10000],108});109110const mistralTokens = new Counter({111 name: 'mistral_tokens_total',112 help: 'Total tokens consumed',113 labelNames: ['model', 'direction'], // direction: input | output114});115116const mistralCost = new Counter({117 name: 'mistral_cost_usd_total',118 help: 'Estimated cost in USD',119 labelNames: ['model'],120});121122const mistralErrors = new Counter({123 name: 'mistral_errors_total',124 help: 'Total Mistral errors',125 labelNames: ['model', 'status_code'],126});127128// Record metrics from instrumented wrapper129function recordPrometheusMetrics(event: MetricsEvent): void {130 mistralRequests.inc({ model: event.model, endpoint: event.endpoint, status: event.status });131 mistralDuration.observe({ model: event.model, endpoint: event.endpoint }, event.durationMs);132133 if (event.status === 'success') {134 if (event.inputTokens) mistralTokens.inc({ model: event.model, direction: 'input' }, event.inputTokens);135 if (event.outputTokens) mistralTokens.inc({ model: event.model, direction: 'output' }, event.outputTokens);136 if (event.costUsd) mistralCost.inc({ model: event.model }, event.costUsd);137 } else {138 mistralErrors.inc({ model: event.model, status_code: String(event.statusCode ?? 'unknown') });139 }140}141```142143### Step 3: Alerting Rules144145```yaml146# prometheus/mistral-alerts.yaml147groups:148 - name: mistral149 rules:150 - alert: MistralHighErrorRate151 expr: rate(mistral_errors_total[5m]) / rate(mistral_requests_total[5m]) > 0.05152 for: 5m153 labels: { severity: critical }154 annotations:155 summary: "Mistral error rate exceeds 5%"156 runbook: "See mistral-incident-runbook skill"157158 - alert: MistralHighLatency159 expr: histogram_quantile(0.95, rate(mistral_request_duration_ms_bucket[5m])) > 5000160 for: 5m161 labels: { severity: warning }162 annotations:163 summary: "Mistral P95 latency exceeds 5 seconds"164165 - alert: MistralRateLimited166 expr: rate(mistral_errors_total{status_code="429"}[5m]) > 0167 for: 2m168 labels: { severity: warning }169 annotations:170 summary: "Mistral rate limiting detected"171172 - alert: MistralCostSpike173 expr: increase(mistral_cost_usd_total[1h]) > 10174 labels: { severity: warning }175 annotations:176 summary: "Mistral spend exceeds $10/hour"177178 - alert: MistralAuthFailure179 expr: increase(mistral_errors_total{status_code="401"}[5m]) > 0180 labels: { severity: critical }181 annotations:182 summary: "Mistral authentication failing — API key may be revoked"183```184185### Step 4: Grafana Dashboard Panels186187Key panels to create:188189| Panel | Query | Type |190|-------|-------|------|191| Request Rate | `rate(mistral_requests_total[5m])` | Time series |192| P50/P95/P99 Latency | `histogram_quantile(0.95, rate(..._bucket[5m]))` | Time series |193| Token Velocity | `rate(mistral_tokens_total{direction="output"}[5m])` | Time series |194| Hourly Cost | `increase(mistral_cost_usd_total[1h])` | Stat |195| Error Rate | `rate(mistral_errors_total[5m])` by status_code | Time series |196| Model Distribution | `sum by (model) (rate(mistral_requests_total[5m]))` | Pie chart |197198### Step 5: Structured Log Format199200```typescript201interface MistralLogEntry {202 ts: string;203 level: 'info' | 'warn' | 'error';204 model: string;205 endpoint: string;206 durationMs: number;207 inputTokens?: number;208 outputTokens?: number;209 costUsd?: number;210 status: string;211 statusCode?: number;212 requestId?: string;213}214215function logMistralRequest(entry: MistralLogEntry): void {216 // Ship to SIEM, CloudWatch, or log aggregator217 // NEVER log message content — PII risk218 console.log(JSON.stringify(entry));219}220```221222## Error Handling223224| Issue | Cause | Solution |225|-------|-------|----------|226| Missing token counts | Streaming not aggregated | Sum tokens from stream chunks |227| Cost drift from bill | Pricing table outdated | Update PRICING map when rates change |228| Alert storm on 429s | Rate limit burst | Tune alert threshold, add request queue |229| High cardinality | Per-request labels | Never label by request ID or user ID |230231## Resources232233- [OpenLIT Mistral Monitoring](https://docs.mistral.ai/cookbooks/third_party-openlit-cookbook_mistral_opentelemetry/)234- [Prometheus Client](https://github.com/siimon/prom-client)235- [Grafana Dashboards](https://grafana.com/dashboards/)236237## Output238239- Instrumented client wrapper with timing and cost tracking240- Prometheus metrics (requests, duration, tokens, cost, errors)241- Alerting rules for error rate, latency, rate limits, cost, auth242- Grafana dashboard panel specifications243- Structured logging format for SIEM integration244245---246247**Source:** [`jeremylongshore/claude-code-plugins-plus-skills`](https://github.com/jeremylongshore/claude-code-plugins-plus-skills) → `plugins/saas-packs/mistral-pack/skills/mistral-observability/SKILL.md`