Gamma Observability
Overview
Implement monitoring, logging, and health checks for Gamma API integrations. Since Gamma does not expose rate limit headers or internal metrics, observability is built around your API call patterns, latency, error rates, credit consumption, and generation success rates.
Prerequisites
- Working Gamma integration (see
gamma-sdk-patterns)
- Monitoring stack (Prometheus/Grafana, Datadog, or CloudWatch)
- Logging infrastructure
Instructions
Step 1: Instrumented Client
// src/observability/gamma-metrics.ts
interface GammaMetrics {
requests: number;
errors: number;
generations: number;
completions: number;
failures: number;
totalCredits: number;
totalLatencyMs: number;
errorsByStatus: Record<number, number>;
}
const metrics: GammaMetrics = {
requests: 0, errors: 0,
generations: 0, completions: 0, failures: 0,
totalCredits: 0, totalLatencyMs: 0,
errorsByStatus: {},
};
export function createInstrumentedClient(apiKey: string) {
const base = "https://public-api.gamma.app/v1.0";
const headers = { "X-API-KEY": apiKey, "Content-Type": "application/json" };
async function instrumentedRequest(method: string, path: string, body?: unknown) {
metrics.requests++;
const start = Date.now();
try {
const res = await fetch(`${base}${path}`, {
method, headers,
body: body ? JSON.stringify(body) : undefined,
});
metrics.totalLatencyMs += Date.now() - start;
if (!res.ok) {
metrics.errors++;
metrics.errorsByStatus[res.status] = (metrics.errorsByStatus[res.status] || 0) + 1;
throw new Error(`Gamma ${res.status}: ${await res.text()}`);
}
return res.json();
} catch (err) {
if (!metrics.errorsByStatus[0]) metrics.errorsByStatus[0] = 0;
metrics.totalLatencyMs += Date.now() - start;
throw err;
}
}
return {
generate: async (body: any) => {
metrics.generations++;
return instrumentedRequest("POST", "/generations", body);
},
poll: (id: string) => instrumentedRequest("GET", `/generations/${id}`),
listThemes: () => instrumentedRequest("GET", "/themes"),
listFolders: () => instrumentedRequest("GET", "/folders"),
// Record completion metrics
recordCompletion: (creditsUsed: number) => {
metrics.completions++;
metrics.totalCredits += creditsUsed;
},
recordFailure: () => { metrics.failures++; },
};
}
export function getMetrics() {
return {
...metrics,
avgLatencyMs: metrics.requests > 0
? Math.round(metrics.totalLatencyMs / metrics.requests) : 0,
errorRate: metrics.requests > 0
? (metrics.errors / metrics.requests * 100).toFixed(2) + "%" : "0%",
completionRate: metrics.generations > 0
? (metrics.completions / metrics.generations * 100).toFixed(1) + "%" : "N/A",
avgCreditsPerGeneration: metrics.completions > 0
? Math.round(metrics.totalCredits / metrics.completions) : 0,
};
}