脚本如何统计接口报错次数

wen 实用脚本 27

本文目录导读:

脚本如何统计接口报错次数

  1. 前端统计方案
  2. 后端统计方案
  3. 综合监控方案
  4. 实用辅助工具

前端统计方案

使用 Axios 拦截器

// 全局错误计数器
const errorCounter = {
  total: 0,
  byStatus: {},
  byUrl: {},
  add(url, status) {
    this.total++
    this.byStatus[status] = (this.byStatus[status] || 0) + 1
    this.byUrl[url] = (this.byUrl[url] || 0) + 1
  },
  report() {
    console.table({
      total: this.total,
      byStatus: this.byStatus,
      byUrl: this.byUrl
    })
  }
}
// Axios 拦截器
axios.interceptors.response.use(
  response => response,
  error => {
    const config = error.config
    const status = error.response?.status || 0
    errorCounter.add(config.url, status)
    // 当错误达到阈值时报告
    if (errorCounter.total % 10 === 0) {
      errorCounter.report()
      // 可以发送到服务器
      sendToServer(errorCounter)
    }
    return Promise.reject(error)
  }
)

使用 Fetch API 封装

class ApiMonitor {
  constructor() {
    this.errors = {
      total: 0,
      recent: [], // 最近100条错误记录
      byEndpoint: {},
      byStatusCode: {}
    }
  }
  async fetch(url, options = {}) {
    try {
      const response = await fetch(url, options)
      if (!response.ok) {
        this.recordError(url, response.status)
      }
      return response
    } catch (error) {
      this.recordError(url, 0, error.message)
      throw error
    }
  }
  recordError(url, status, message = '') {
    this.errors.total++
    this.errors.recent.unshift({
      url,
      status,
      message,
      timestamp: Date.now()
    })
    // 只保留最近100条
    if (this.errors.recent.length > 100) {
      this.errors.recent.pop()
    }
    // 按端点统计
    this.errors.byEndpoint[url] = (this.errors.byEndpoint[url] || 0) + 1
    // 按状态码统计
    this.errors.byStatusCode[status] = (this.errors.byStatusCode[status] || 0) + 1
  }
  getStats() {
    return {
      ...this.errors,
      recent: this.errors.recent.slice(0, 10) // 只返回最近10条
    }
  }
}
// 使用
const api = new ApiMonitor()
const data = await api.fetch('/api/users')

后端统计方案

Node.js + Express 中间件

const errorStats = {
  total: 0,
  byRoute: {},
  byStatusCode: {},
  byHour: {},
  // 每小时轮转
  rotateHourly() {
    const hour = new Date().getHours()
    if (!this.byHour[hour]) {
      this.byHour[hour] = { total: 0, errors: {} }
    }
  }
}
// 错误统计中间件
const errorMonitor = (err, req, res, next) => {
  errorStats.total++
  // 按路由统计
  const route = req.baseUrl + req.path
  if (!errorStats.byRoute[route]) {
    errorStats.byRoute[route] = 0
  }
  errorStats.byRoute[route]++
  // 按状态码统计
  const status = err.status || 500
  if (!errorStats.byStatusCode[status]) {
    errorStats.byStatusCode[status] = 0
  }
  errorStats.byStatusCode[status]++
  // 按小时统计
  const hour = new Date().getHours()
  if (!errorStats.byHour[hour]) {
    errorStats.byHour[hour] = 0
  }
  errorStats.byHour[hour]++
  next(err)
}
// 获取统计信息接口
app.get('/api/stats/errors', (req, res) => {
  res.json(errorStats)
})
// 重置统计
app.delete('/api/stats/errors', (req, res) => {
  Object.assign(errorStats, {
    total: 0,
    byRoute: {},
    byStatusCode: {},
    byHour: {}
  })
  res.sendStatus(200)
})

综合监控方案

使用装饰器模式

class ApiMonitor {
  constructor(options = {}) {
    this.options = {
      reportInterval: 60000, // 1分钟报告一次
      maxErrorsBeforeAlert: 10, // 10次错误触发告警
      ...options
    }
    this.stats = this.initStats()
    this.startReporting()
  }
  initStats() {
    return {
      total: 0,
      successful: 0,
      failed: 0,
      lastMinuteErrors: 0,
      errorRate: 0,
      endpoints: {}
    }
  }
  wrap(endpoint, handler) {
    return async (...args) => {
      const startTime = Date.now()
      try {
        const result = await handler(...args)
        this.recordSuccess(endpoint, Date.now() - startTime)
        return result
      } catch (error) {
        this.recordError(endpoint, error)
        throw error
      }
    }
  }
  recordSuccess(endpoint, duration) {
    if (!this.stats.endpoints[endpoint]) {
      this.stats.endpoints[endpoint] = {
        total: 0,
        errors: 0,
        avgDuration: 0
      }
    }
    const ep = this.stats.endpoints[endpoint]
    ep.total++
    ep.avgDuration = (ep.avgDuration * (ep.total - 1) + duration) / ep.total
    this.stats.total++
    this.stats.successful++
  }
  recordError(endpoint, error) {
    if (!this.stats.endpoints[endpoint]) {
      this.stats.endpoints[endpoint] = {
        total: 0,
        errors: 0,
        lastError: null
      }
    }
    const ep = this.stats.endpoints[endpoint]
    ep.total++
    ep.errors++
    ep.lastError = {
      message: error.message,
      timestamp: Date.now()
    }
    this.stats.total++
    this.stats.failed++
    this.stats.lastMinuteErrors++
    // 检查是否需要告警
    if (ep.errors >= this.options.maxErrorsBeforeAlert) {
      this.triggerAlert(endpoint, ep)
    }
  }
  triggerAlert(endpoint, stats) {
    console.warn(`⚠️ API Alert: ${endpoint} has ${stats.errors} errors`)
    // 发送告警通知
    this.sendAlert({
      endpoint,
      errors: stats.errors,
      lastError: stats.lastError,
      timestamp: new Date()
    })
  }
  startReporting() {
    setInterval(() => {
      this.stats.errorRate = (this.stats.lastMinuteErrors / (this.stats.total || 1)) * 100
      console.table({
        'Total Requests': this.stats.total,
        'Failed': this.stats.failed,
        'Error Rate': `${this.stats.errorRate.toFixed(2)}%`,
        'Last Minute Errors': this.stats.lastMinuteErrors
      })
      // 重置每分钟统计
      this.stats.lastMinuteErrors = 0
      // 发送到监控系统
      this.sendToMonitoring(this.stats)
    }, this.options.reportInterval)
  }
  async sendToMonitoring(stats) {
    // 发送到你的监控系统
    await fetch('/api/monitoring', {
      method: 'POST',
      body: JSON.stringify(stats)
    })
  }
}
// 使用
const monitor = new ApiMonitor({ maxErrorsBeforeAlert: 5 })
const apiHandler = {
  getUser: monitor.wrap('/api/users', async (id) => {
    const response = await fetch(`/api/users/${id}`)
    return response.json()
  })
}

实用辅助工具

错误率仪表板

class ErrorDashboard {
  constructor() {
    this.errors = []
    this.MAX_RECORDS = 1000
  }
  addError(error) {
    this.errors.push({
      ...error,
      timestamp: new Date()
    })
    if (this.errors.length > this.MAX_RECORDS) {
      this.errors.shift()
    }
  }
  getErrorRate(timeWindow = 60000) { // 默认最近1分钟
    const now = Date.now()
    const recent = this.errors.filter(e => 
      now - e.timestamp.getTime() < timeWindow
    )
    return {
      count: recent.length,
      rate: (recent.length / (timeWindow / 1000)).toFixed(2) + '/s'
    }
  }
  getTopErrors(limit = 5) {
    const errorCounts = {}
    this.errors.forEach(e => {
      const key = `${e.url}:${e.status}`
      errorCounts[key] = (errorCounts[key] || 0) + 1
    })
    return Object.entries(errorCounts)
      .sort((a, b) => b[1] - a[1])
      .slice(0, limit)
      .map(([key, count]) => ({
        endpoint: key.split(':')[0],
        status: key.split(':')[1],
        count
      }))
  }
}

使用示例

// 全局监控
const monitor = new ApiMonitor()
const dashboard = new ErrorDashboard()
// 在请求封装中使用
async function request(url, options) {
  try {
    const response = await fetch(url, options)
    return response
  } catch (error) {
    monitor.recordError(url, error)
    dashboard.addError({
      url,
      status: error.status || 500,
      message: error.message
    })
    // 检查错误率
    const errorRate = dashboard.getErrorRate()
    if (errorRate.count > 10) {
      console.warn(`High error rate detected: ${errorRate.rate}`)
    }
    throw error
  }
}

这些方案可以根据你的具体需求进行组合和定制,关键是要:

  1. 统一拦截所有请求
  2. 记录详细的错误信息
  3. 按需生成统计报告
  4. 设置告警阈值

抱歉,评论功能暂时关闭!