GET /api/stats
curl --request GET \
--url https://vij.example.com/api/statsimport requests
url = "https://vij.example.com/api/stats"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://vij.example.com/api/stats', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://vij.example.com/api/stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://vij.example.com/api/stats"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://vij.example.com/api/stats")
.asString();require 'uri'
require 'net/http'
url = URI("https://vij.example.com/api/stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"overview": {
"totalErrors": 15247,
"errorRate": 42.3,
"uniqueGroups": 347,
"newGroups": 23,
"affectedUsers": 2145
},
"bySeverity": {
"error": 12000,
"warning": 2800,
"info": 447
},
"byEnvironment": [
{ "environment": "production", "count": 12000 },
{ "environment": "staging", "count": 2500 },
{ "environment": "development", "count": 747 }
],
"byApplication": [
{ "appId": "frontend", "count": 8234 },
{ "appId": "backend-api", "count": 5123 },
{ "appId": "mobile-app", "count": 1890 }
],
"timeseries": [
{
"timestamp": "2024-01-01T00:00:00Z",
"count": 45,
"error": 35,
"warning": 8,
"info": 2
},
{
"timestamp": "2024-01-01T01:00:00Z",
"count": 67,
"error": 52,
"warning": 12,
"info": 3
}
],
"topErrors": [
{
"group": "abc123def456",
"message": "TypeError: Cannot read property 'map' of undefined",
"count": 2547,
"severity": "error",
"firstSeen": "2024-01-01T10:00:00Z",
"lastSeen": "2024-01-03T14:30:00Z"
},
{
"group": "def456ghi789",
"message": "Payment processing failed",
"count": 1234,
"severity": "error",
"firstSeen": "2024-01-02T08:00:00Z",
"lastSeen": "2024-01-03T15:00:00Z"
}
],
"trends": {
"totalChange": 12.5,
"errorRateChange": -5.2,
"newGroupsChange": 8.3
}
}
Analytics API
GET /api/stats
Retrieve error statistics and analytics
GET
/
api
/
stats
GET /api/stats
curl --request GET \
--url https://vij.example.com/api/statsimport requests
url = "https://vij.example.com/api/stats"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://vij.example.com/api/stats', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://vij.example.com/api/stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://vij.example.com/api/stats"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://vij.example.com/api/stats")
.asString();require 'uri'
require 'net/http'
url = URI("https://vij.example.com/api/stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"overview": {
"totalErrors": 15247,
"errorRate": 42.3,
"uniqueGroups": 347,
"newGroups": 23,
"affectedUsers": 2145
},
"bySeverity": {
"error": 12000,
"warning": 2800,
"info": 447
},
"byEnvironment": [
{ "environment": "production", "count": 12000 },
{ "environment": "staging", "count": 2500 },
{ "environment": "development", "count": 747 }
],
"byApplication": [
{ "appId": "frontend", "count": 8234 },
{ "appId": "backend-api", "count": 5123 },
{ "appId": "mobile-app", "count": 1890 }
],
"timeseries": [
{
"timestamp": "2024-01-01T00:00:00Z",
"count": 45,
"error": 35,
"warning": 8,
"info": 2
},
{
"timestamp": "2024-01-01T01:00:00Z",
"count": 67,
"error": 52,
"warning": 12,
"info": 3
}
],
"topErrors": [
{
"group": "abc123def456",
"message": "TypeError: Cannot read property 'map' of undefined",
"count": 2547,
"severity": "error",
"firstSeen": "2024-01-01T10:00:00Z",
"lastSeen": "2024-01-03T14:30:00Z"
},
{
"group": "def456ghi789",
"message": "Payment processing failed",
"count": 1234,
"severity": "error",
"firstSeen": "2024-01-02T08:00:00Z",
"lastSeen": "2024-01-03T15:00:00Z"
}
],
"trends": {
"totalChange": 12.5,
"errorRateChange": -5.2,
"newGroupsChange": 8.3
}
}
The GET
Result: One data point per hour
Result: One data point per day
Result: One data point per week
Use ETags for conditional requests:
If data hasn’t changed:
/api/stats endpoint provides aggregated statistics and metrics about your error logs for dashboard analytics and reporting.
Query Parameters
string
Filter stats from this date (ISO 8601).Example:
/api/stats?startDate=2024-01-01T00:00:00Zstring
Filter stats until this date (ISO 8601).Example:
/api/stats?endDate=2024-01-31T23:59:59Zstring
Filter stats by environment.Example:
/api/stats?environment=productionstring
Filter stats by application ID.Example:
/api/stats?appId=my-frontend-appstring
default:"1h"
Time interval for time-series data.Values:
1h (hourly), 1d (daily), 1w (weekly)Example: /api/stats?interval=1dResponse Fields
object
object
Breakdown by severity level.
{
"error": 12000,
"warning": 3500,
"info": 500
}
array
Breakdown by environment.
[
{ "environment": "production", "count": 10000 },
{ "environment": "staging", "count": 5000 },
{ "environment": "development", "count": 1000 }
]
array
Breakdown by application.
[
{ "appId": "frontend", "count": 8000 },
{ "appId": "backend-api", "count": 6000 },
{ "appId": "mobile-app", "count": 2000 }
]
array
Error counts over time.
[
{ "timestamp": "2024-01-01T00:00:00Z", "count": 45, "error": 35, "warning": 8, "info": 2 },
{ "timestamp": "2024-01-01T01:00:00Z", "count": 67, "error": 52, "warning": 12, "info": 3 }
]
array
object
Trend analysis compared to previous period.
{
"totalChange": 12.5, // Percentage change
"errorRateChange": -5.2, // Improvement
"newGroupsChange": 8.3
}
Example Requests
curl "https://vij.example.com/api/stats"
curl "https://vij.example.com/api/stats?startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z"
curl "https://vij.example.com/api/stats?environment=production"
curl "https://vij.example.com/api/stats?appId=my-frontend-app"
curl "https://vij.example.com/api/stats?interval=1d&startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z"
Example Response
{
"overview": {
"totalErrors": 15247,
"errorRate": 42.3,
"uniqueGroups": 347,
"newGroups": 23,
"affectedUsers": 2145
},
"bySeverity": {
"error": 12000,
"warning": 2800,
"info": 447
},
"byEnvironment": [
{ "environment": "production", "count": 12000 },
{ "environment": "staging", "count": 2500 },
{ "environment": "development", "count": 747 }
],
"byApplication": [
{ "appId": "frontend", "count": 8234 },
{ "appId": "backend-api", "count": 5123 },
{ "appId": "mobile-app", "count": 1890 }
],
"timeseries": [
{
"timestamp": "2024-01-01T00:00:00Z",
"count": 45,
"error": 35,
"warning": 8,
"info": 2
},
{
"timestamp": "2024-01-01T01:00:00Z",
"count": 67,
"error": 52,
"warning": 12,
"info": 3
}
],
"topErrors": [
{
"group": "abc123def456",
"message": "TypeError: Cannot read property 'map' of undefined",
"count": 2547,
"severity": "error",
"firstSeen": "2024-01-01T10:00:00Z",
"lastSeen": "2024-01-03T14:30:00Z"
},
{
"group": "def456ghi789",
"message": "Payment processing failed",
"count": 1234,
"severity": "error",
"firstSeen": "2024-01-02T08:00:00Z",
"lastSeen": "2024-01-03T15:00:00Z"
}
],
"trends": {
"totalChange": 12.5,
"errorRateChange": -5.2,
"newGroupsChange": 8.3
}
}
Use Cases
Dashboard Overview
Display key metrics on your dashboard:const stats = await fetch('https://vij.example.com/api/stats').then(r => r.json());
// Display metrics
document.getElementById('total-errors').textContent = stats.overview.totalErrors;
document.getElementById('error-rate').textContent = stats.overview.errorRate;
document.getElementById('unique-groups').textContent = stats.overview.uniqueGroups;
Time-Series Chart
Generate error trends chart:const stats = await fetch(
'https://vij.example.com/api/stats?interval=1d&startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z'
).then(r => r.json());
// Use with Chart.js
new Chart(ctx, {
type: 'line',
data: {
labels: stats.timeseries.map(t => t.timestamp),
datasets: [
{
label: 'Errors',
data: stats.timeseries.map(t => t.error),
borderColor: 'red'
},
{
label: 'Warnings',
data: stats.timeseries.map(t => t.warning),
borderColor: 'orange'
}
]
}
});
Application Comparison
Compare error rates across apps:const stats = await fetch('https://vij.example.com/api/stats').then(r => r.json());
stats.byApplication.forEach(app => {
console.log(`${app.appId}: ${app.count} errors`);
});
// Output:
// frontend: 8234 errors
// backend-api: 5123 errors
// mobile-app: 1890 errors
Alerting
Set up automated alerts:const stats = await fetch('https://vij.example.com/api/stats').then(r => r.json());
// Alert if error rate too high
if (stats.overview.errorRate > 100) {
sendAlert({
severity: 'critical',
message: `High error rate: ${stats.overview.errorRate}/hour`,
details: stats
});
}
// Alert on new error groups
if (stats.overview.newGroups > 10) {
sendAlert({
severity: 'warning',
message: `${stats.overview.newGroups} new error groups detected`,
details: stats.topErrors
});
}
Weekly Report
Generate weekly summary:const oneWeekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
const stats = await fetch(
`https://vij.example.com/api/stats?startDate=${oneWeekAgo}`
).then(r => r.json());
const report = `
Weekly Error Report
Total Errors: ${stats.overview.totalErrors}
Average Rate: ${stats.overview.errorRate}/hour
New Error Groups: ${stats.overview.newGroups}
Top Errors:
${stats.topErrors.map((e, i) => `${i + 1}. ${e.message} (${e.count} occurrences)`).join('\n')}
Trend: ${stats.trends.totalChange > 0 ? '↑' : '↓'} ${Math.abs(stats.trends.totalChange)}%
`;
sendEmail(report);
Filtering by Time Range
Last 24 Hours
startDate=$(date -u -d '1 day ago' +%Y-%m-%dT%H:%M:%SZ)
curl "https://vij.example.com/api/stats?startDate=$startDate"
Last 7 Days
startDate=$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)
curl "https://vij.example.com/api/stats?startDate=$startDate"
Specific Month
curl "https://vij.example.com/api/stats?startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z"
Year to Date
startDate=$(date -u +%Y-01-01T00:00:00Z)
curl "https://vij.example.com/api/stats?startDate=$startDate"
Time-Series Intervals
Hourly (1h)
Best for: Last 24-48 hourscurl "https://vij.example.com/api/stats?interval=1h&startDate=2024-01-01T00:00:00Z&endDate=2024-01-02T00:00:00Z"
Daily (1d)
Best for: Last 30-90 dayscurl "https://vij.example.com/api/stats?interval=1d&startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z"
Weekly (1w)
Best for: Last 3-12 monthscurl "https://vij.example.com/api/stats?interval=1w&startDate=2024-01-01T00:00:00Z&endDate=2024-12-31T23:59:59Z"
Performance Optimization
Use appropriate time ranges
Use appropriate time ranges
# Good - last 30 days
startDate=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ)
# Slow - all time
# No time filter
Choose right interval
Choose right interval
# Good - hourly for 24h
interval=1h&startDate=$(date -u -d '1 day ago' +%Y-%m-%dT%H:%M:%SZ)
# Good - daily for 30d
interval=1d&startDate=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ)
# Bad - hourly for 1 year (too many data points)
interval=1h&startDate=$(date -u -d '1 year ago' +%Y-%m-%dT%H:%M:%SZ)
Filter by app or environment
Filter by app or environment
# Faster - single app
curl "https://vij.example.com/api/stats?appId=my-app"
# Slower - all apps
curl "https://vij.example.com/api/stats"
Cache results
Cache results
Stats change infrequently - cache for 1-5 minutes:
const CACHE_TTL = 60 * 1000; // 1 minute
let statsCache = null;
let cacheTime = 0;
async function getStats() {
if (Date.now() - cacheTime < CACHE_TTL) {
return statsCache;
}
statsCache = await fetch('/api/stats').then(r => r.json());
cacheTime = Date.now();
return statsCache;
}
Client Implementation
TypeScript
interface StatsQuery {
startDate?: string;
endDate?: string;
environment?: string;
appId?: string;
interval?: '1h' | '1d' | '1w';
}
interface Stats {
overview: {
totalErrors: number;
errorRate: number;
uniqueGroups: number;
newGroups: number;
affectedUsers: number;
};
bySeverity: {
error: number;
warning: number;
info: number;
};
byEnvironment: Array<{ environment: string; count: number }>;
byApplication: Array<{ appId: string; count: number }>;
timeseries: Array<{
timestamp: string;
count: number;
error: number;
warning: number;
info: number;
}>;
topErrors: Array<{
group: string;
message: string;
count: number;
severity: string;
firstSeen: string;
lastSeen: string;
}>;
trends: {
totalChange: number;
errorRateChange: number;
newGroupsChange: number;
};
}
async function fetchStats(query: StatsQuery = {}): Promise<Stats> {
const params = new URLSearchParams(
Object.entries(query)
.filter(([_, v]) => v !== undefined)
.map(([k, v]) => [k, String(v)])
);
const response = await fetch(
`https://vij.example.com/api/stats?${params}`
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
Caching Headers
Stats responses include cache headers:Cache-Control: public, max-age=60
ETag: "abc123def456"
curl -H 'If-None-Match: "abc123def456"' \
https://vij.example.com/api/stats
304 Not Modified
Related Endpoints
GET /api/logs
Retrieve individual error logs
GET /api/groups
Retrieve error groups
Analytics Guide
Learn about VIJ analytics
Dashboard Features
Explore dashboard visualizations