Skip to main content
GET
https://vij.example.com
/
api
/
stats
GET /api/stats
curl --request GET \
  --url https://vij.example.com/api/stats
{
  "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 /api/stats endpoint provides aggregated statistics and metrics about your error logs for dashboard analytics and reporting.

Query Parameters

startDate
string
Filter stats from this date (ISO 8601).Example: /api/stats?startDate=2024-01-01T00:00:00Z
endDate
string
Filter stats until this date (ISO 8601).Example: /api/stats?endDate=2024-01-31T23:59:59Z
environment
string
Filter stats by environment.Example: /api/stats?environment=production
appId
string
Filter stats by application ID.Example: /api/stats?appId=my-frontend-app
interval
string
default:"1h"
Time interval for time-series data.Values: 1h (hourly), 1d (daily), 1w (weekly)Example: /api/stats?interval=1d

Response Fields

overview
object
High-level statistics.
bySeverity
object
Breakdown by severity level.
{
  "error": 12000,
  "warning": 3500,
  "info": 500
}
byEnvironment
array
Breakdown by environment.
[
  { "environment": "production", "count": 10000 },
  { "environment": "staging", "count": 5000 },
  { "environment": "development", "count": 1000 }
]
byApplication
array
Breakdown by application.
[
  { "appId": "frontend", "count": 8000 },
  { "appId": "backend-api", "count": 6000 },
  { "appId": "mobile-app", "count": 2000 }
]
timeseries
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 }
]
topErrors
array
Most frequent error groups.
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"

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 hours
curl "https://vij.example.com/api/stats?interval=1h&startDate=2024-01-01T00:00:00Z&endDate=2024-01-02T00:00:00Z"
Result: One data point per hour

Daily (1d)

Best for: Last 30-90 days
curl "https://vij.example.com/api/stats?interval=1d&startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z"
Result: One data point per day

Weekly (1w)

Best for: Last 3-12 months
curl "https://vij.example.com/api/stats?interval=1w&startDate=2024-01-01T00:00:00Z&endDate=2024-12-31T23:59:59Z"
Result: One data point per week

Performance Optimization

# Good - last 30 days
startDate=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ)

# Slow - all time
# No time filter
# 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)
# Faster - single app
curl "https://vij.example.com/api/stats?appId=my-app"

# Slower - all apps
curl "https://vij.example.com/api/stats"
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"
Use ETags for conditional requests:
curl -H 'If-None-Match: "abc123def456"' \
  https://vij.example.com/api/stats
If data hasn’t changed: 304 Not Modified