npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

logger-sdk

v1.0.4

Published

日志系统 SDK - 客户端日志记录和上报工具

Readme

Logger SDK

一个轻量级的客户端日志记录和上报 SDK,支持 TypeScript。

特性

  • 🚀 轻量级,无依赖(仅依赖必要的运行时库)
  • 📝 支持多级别日志(DEBUG, INFO, WARN, ERROR, FATAL)
  • 💾 本地存储日志(LocalStorage)
  • 📤 日志上报(支持 ZIP 压缩)
  • 🖼️ 支持附件上传(图片、视频、文件)
  • 📸 支持截图功能
  • 🪵 自动捕获全局错误
  • 🌍 全局单例模式
  • 💯 TypeScript 支持
  • 🔄 自动重试 + 离线队列保障上报成功率

安装

npm install logger-sdk

快速开始

import { Logger } from 'logger-sdk'

// 初始化配置
Logger.config({
  appId: 'your-app-id',
  serverUrl: 'https://your-api.com/api/reports',
  apiKey: 'your-api-key'
})

// 记录日志
Logger.info('用户登录', { userId: '123' })
Logger.error('API 请求失败', { url: '/api/users', status: 500 })

配置选项

Logger.config({
  appId: string           // 应用 ID
  appVersion?: string     // 应用版本(默认: '1.0.0')
  userId?: string         // 用户 ID
  serverUrl?: string      // 上报服务器地址(配置后启用上报)
  apiKey?: string         // API Key(上报时需要)
  disableErrorCapture?: boolean  // 是否禁用自动错误捕获(默认: false)
})

API

日志方法

Logger.debug(message: string, data?: Record<string, any>)
Logger.info(message: string, data?: Record<string, any>)
Logger.warn(message: string, data?: Record<string, any>)
Logger.error(message: string, data?: Record<string, any>)
Logger.fatal(message: string, data?: Record<string, any>)

其他方法

// 设置用户信息
Logger.setUserInfo(userId: string)

// 获取 Storage 实例
const storage = Logger.getStorage()
const logs = storage.getLogs()

// 获取 Reporter 实例(配置了 serverUrl 后可用)
const reporter = Logger.getReporter()
await reporter.report({
  title: '问题标题',
  type: 'bug',
  description: '问题描述'
})

日志上报

const reporter = Logger.getReporter()

// 上报日志(默认配置)
await reporter.report({
  title: '问题标题',
  type: 'bug',        // 'bug' | 'feature' | 'experience' | 'other'
  description: '详细描述',
  days: 7             // 最近几天的日志
})

// 带选项的上报(重试、超时控制)
await reporter.report({
  title: '问题标题',
  type: 'bug',
  description: '详细描述'
}, {
  maxRetries: 3,          // 最大重试次数(默认: 3)
  retryDelay: 1000,       // 重试延迟基数 ms(默认: 1000,指数退避)
  timeout: 30000,         // 请求超时时间 ms(默认: 30000)
  enableOfflineQueue: true // 失败时加入离线队列(默认: true)
})

// 添加附件
await reporter.addImage(file)
await reporter.addVideo(file)
await reporter.addFile(file)

// 截图
await reporter.captureScreenshot()

// 清空附件
reporter.clearAttachments()

可靠性保障

SDK 内置了多层机制确保上报成功:

  1. 自动重试 - 上报失败时自动重试(默认 3 次),使用指数退避策略
  2. 超时控制 - 使用 AbortController 防止请求长时间挂起
  3. 离线队列 - 失败的上报会存储在 localStorage 中,网络恢复时自动重试
  4. 响应验证 - 兼容多种后端响应格式,确保正确识别成功状态
// 查看离线队列状态
const status = reporter.getOfflineQueueStatus()
console.log(`待上报数量: ${status.size}`)

// 手动触发离线队列处理
await reporter.processOfflineQueue()

// 清空离线队列
reporter.clearOfflineQueue()

服务端接口规范

如果你要接收 SDK 的上报数据,需要按照以下规范实现接口。

接口概览

| 属性 | 值 | |------|-----| | 请求方法 | POST | | Content-Type | multipart/form-data | | 认证方式 | Header: X-API-Key |

请求格式

Headers

Content-Type: multipart/form-data
X-API-Key: your-api-key-here

Body (multipart/form-data)

| 字段名 | 类型 | 必填 | 说明 | |--------|------|------|------| | appId | string | 是 | 应用标识 | | appVersion | string | 是 | 应用版本号 | | title | string | 是 | 上报标题 | | type | string | 是 | 上报类型(bug/feature/experience/other) | | description | string | 否 | 详细描述 | | deviceId | string | 是 | 设备唯一标识 | | deviceInfo | string | 是 | 设备信息(如:Windows / Chrome) | | userAgent | string | 是 | 浏览器 User-Agent | | url | string | 是 | 当前页面 URL | | logs | File (.zip) | 是 | 日志压缩包(ZIP 格式) | | attachments | File | 否 | 附件文件(可能有多个) |

响应格式

成功响应

{
  "success": true,
  "data": {
    "reportId": "507f1f77bcf86cd799439011"
  },
  "message": "上报成功"
}

或简化格式:

{
  "success": true,
  "reportId": "507f1f77bcf86cd799439011"
}

SDK 会兼容以下响应格式:

  • success: truecode: 0status: 'success'
  • reportId 可能在 data.reportIdreportIdiddata.id

错误响应

{
  "success": false,
  "message": "错误描述"
}

HTTP 状态码建议:

  • 200 - 成功
  • 400 - 请求参数错误
  • 401 - API Key 无效
  • 413 - 文件过大
  • 500 - 服务器内部错误

后端实现示例

Node.js + formidable

import formidable from 'formidable'

export async function handler(req, res) {
  // 1. 验证 API Key
  const apiKey = req.headers['x-api-key']
  if (apiKey !== process.env.API_KEY) {
    return res.status(401).json({ success: false, message: 'Invalid API Key' })
  }

  // 2. 解析 multipart/form-data
  const form = formidable({
    maxFileSize: 50 * 1024 * 1024, // 50MB
    multiples: true
  })

  const [fields, files] = await form.parse(req)

  // 3. 提取字段
  const appId = fields.appId?.[0]
  const title = fields.title?.[0]
  const type = fields.type?.[0]
  const logsFile = files.logs?.[0]

  // 4. 保存文件、存储到数据库...

  // 5. 返回成功响应
  return res.status(201).json({
    success: true,
    data: { reportId: '生成的上报ID' },
    message: '上报成功'
  })
}

Express + multer

import multer from 'multer'

const upload = multer({
  dest: 'uploads/',
  limits: { fileSize: 50 * 1024 * 1024 }
})

app.post('/api/reports',
  upload.fields([
    { name: 'logs', maxCount: 1 },
    { name: 'attachments', maxCount: 10 }
  ]),
  (req, res) => {
    const apiKey = req.headers['x-api-key']
    const { appId, title, type } = req.body
    const logsFile = req.files.logs?.[0]
    const attachments = req.files.attachments || []

    // ... 保存逻辑

    res.json({
      success: true,
      data: { reportId: 'xxx' },
      message: '上报成功'
    })
  }
)

日志 ZIP 文件格式

ZIP 文件包含以下内容:

  • 有日志时:包含一个或多个 logs.txtlogs_001.txtlogs_002.txt 等文件
  • 无日志时:包含 logs.txt,内容为 No logs available

日志文件格式示例:

2025-02-19 10:30:45.123 INFO 用户登录 {"userId":"123"}
2025-02-19 10:30:50.456 ERROR API请求失败 {"url":"/api/users","status":500"}

安全建议

  1. API Key 验证 - 务必验证 X-API-Key 请求头
  2. 文件大小限制 - 限制单个文件大小(建议 50MB)
  3. 文件类型验证 - 检查文件扩展名和 MIME 类型
  4. 速率限制 - 防止滥发上报
  5. 文件清理 - 定期清理旧的日志文件

使用 cURL 测试

curl -X POST https://your-api.com/api/reports \
  -H "X-API-Key: your-api-key" \
  -F "appId=test-app" \
  -F "appVersion=1.0.0" \
  -F "title=测试上报" \
  -F "type=bug" \
  -F "description=测试描述" \
  -F "deviceId=test-device-123" \
  -F "deviceInfo=Windows / Chrome" \
  -F "userAgent=Mozilla/5.0..." \
  -F "url=https://example.com" \
  -F "logs=@./test.zip"

License

MIT