文档/APIv1

API 文档

日志文件上传、读取、Codex 分析与删除的 HTTP API 参考。

https://api.logshare.cn

概览

LogShare API 用于把 Minecraft/Hytale 日志文件上传到平台,并在之后读取文件内容、获取 Codex 结构化分析或删除日志。所有接口都通过 HTTPS 访问,当前版本为 v1。

项目说明
Base URLhttps://api.logshare.cn
API 版本当前稳定版本,所有接口路径都以 /v1 开头。
请求格式 上传接口支持 application/json 和 application/x-www-form-urlencoded;读取和删除接口使用标准 HTTP 方法。
响应格式 单文件 raw 接口返回 text/plain;多文件 raw 接口返回 JSON 文件列表;其余接口均返回 JSON。
认证 上传和读取接口不需要认证;删除日志时必须携带上传时返回的 Bearer token。
日志 ID 每次上传成功后生成,由 7 位字母和数字组成。
默认保留时间 默认至少保留 7 天。expires 是逻辑过期时间,实际删除可能因 TTL 回收延迟;仅访问日志元信息不会续期。
  • 成功响应使用 { success: true, message, ... },错误响应使用 { success: false, error, code }。客户端应先判断 HTTP 状态码,再读取 success 和 error 字段。
  • 请求体支持 br / gzip / deflate 压缩,最多 5 层;服务端响应优先 Brotli,可发送 Accept-Encoding: br, gzip。
  • GET /v1/log/{id} 不会续期。raw / insights 的任意成功读取(包括多文件时返回文件列表)都会延长日志的保留时间。

接入流程

每次上传会创建一条日志记录,这条记录可以包含一个或多个文件。客户端接入时,建议按照下面的顺序处理:

  1. 上传文件。 使用 POST /v1/log,把本次要分享的日志文件放入 files 数组。旧客户端也可以继续提交 content 字段,服务端会把它映射为 latest.log。上传成功后,响应会返回日志 ID、分享地址、主文件原文地址、删除 token 和文件列表。请立即保存 token,它只在这次响应中返回一次。
  2. 获取文件列表。 使用 GET /v1/log/{id} 获取日志元信息和文件列表。该接口不会续期,适合在打开日志页面时使用。
  3. 让用户选择文件。 如果响应中的 requiresFileSelection 为 true,说明这次上传包含多个文件。客户端应展示 files 列表,让用户选择要查看的文件,而不是自行假定某个文件是主日志。
  4. 读取或分析文件。 使用文件对象中的 name 作为 filename,请求 /v1/raw/{id}/{filename} 读取原文,或请求 /v1/insights/{id}/{filename} 获取 Codex 分析。
服务端会对「按名称排序后的文件集合 + source」计算内容指纹。如果命中已有日志,响应中的 id 会指向已有日志, deduplicated 为 true。此时返回的 token 是本次请求新生成的,并未写入存储,不能用于删除已有日志;删除凭证仍然属于第一次上传该内容的客户端。

快速开始

cURL
# 1. 上传文件列表
curl -X POST https://api.logshare.cn/v1/log \
  -H 'Content-Type: application/json' \
  -d '{
    "files": [
      {"name": "latest.log", "content": "<游戏主日志>"},
      {"name": "crash-reports/crash-01.txt", "content": "<崩溃报告>"}
    ],
    "source": "fcl/1.2.0",
    "metadata": [
      {"key": "version", "value": "1.21.9", "label": "Minecraft 版本"}
    ]
  }'

# 2. 获取文件列表
curl https://api.logshare.cn/v1/log/sAbCdEf

# 3. 选择文件后读取或分析
curl https://api.logshare.cn/v1/raw/sAbCdEf/latest.log
curl https://api.logshare.cn/v1/insights/sAbCdEf/latest.log

# 4. 删除日志
curl -X DELETE https://api.logshare.cn/v1/log/sAbCdEf \
  -H 'Authorization: Bearer <token>'

如果客户端只上传单个文件,也可以继续使用旧版 content 字段:服务端会把它映射为 latest.log,响应结构与 files 上传一致。

端点总览

方法路径说明
POST/v1/log上传一个或多个日志文件(也兼容旧版单文件 content),创建日志记录,并返回日志 ID、分享地址、删除 token 和文件列表。
GET/v1/log/{id}获取日志的元信息、公开 metadata 和文件列表。
GET/v1/raw/{id}读取日志原文。当同一个 ID 下只有一个文件时直接返回文本;存在多个文件时返回文件列表,客户端需要先选择文件。
GET/v1/raw/{id}/{filename}读取指定文件的原文。文件名可以包含子路径。
GET/v1/insights/{id}获取 Codex 分析。当同一个 ID 下只有一个文件时直接返回分析结果;存在多个文件时返回文件列表。
GET/v1/insights/{id}/{filename}对指定文件执行 Codex 分析,并返回结构化结果。
DELETE/v1/log/{id}删除一个或多个日志。需要上传时返回的删除 token。
GET/v1/limits获取当前上传限制,包括文件数、总大小、请求体大小和保留时间。
GET/返回当前可用的端点列表,可用于健康检查或能力发现。
POST/v1/log

上传日志

该接口用于上传一个或多个日志文件。新客户端应把文件放入 files 数组;旧版单文件字段 content 仍然可用,服务端会把它映射为主文件(优先 latest.log,重名时使用 main.log、latest (2).log 等名称),已对接旧接口的客户端不需要修改。这个主文件同样占用文件数配额并计入总大小。每次上传会创建一条日志记录;平台会对每个文件单独执行脱敏,并在识别为 Minecraft 日志时执行 SpinYarn 反混淆。Codex 全文分析不会在上传时执行,而是在之后请求某个文件的分析接口时按需执行。

Content-Type: 上传接口支持 application/json 和 application/x-www-form-urlencoded 两种请求格式。推荐使用 JSON,便于同时提交文件、metadata 和 source。如果 Content-Type 缺失或不是上述两种,服务端会按 urlencoded 尝试解析。

Content-Encoding: 如果请求体较大,可以使用 br / gzip / x-gzip / deflate 压缩请求体,最多支持 5 层编码;每一层解压后的输出都不能超过 32 MiB。gzip、x-gzip 和 deflate 由 PHP 内置 zlib 支持,br 需要服务端安装 ext-brotli,缺少扩展时返回 501。服务端返回响应时会优先使用 Brotli 压缩,客户端可以发送 Accept-Encoding: br, gzip。

请求字段

字段类型必填说明
filesarray<FileInput>否*日志文件数组,每个元素是一个 FileInput 对象。一次最多上传 200 个文件;所有文件展开后的总大小不能超过 20 MiB。与 content 至少提供一个。
contentstring否*旧版单文件字段。非空时会映射为主文件(优先 latest.log,重名时使用 main.log、latest (2).log 等);与 files 同时提交时作为主文件。它同样占用文件数配额并计入总大小。
metadataarray<MetadataEntry>否可选。结构化元数据数组,最多 100 条。服务端会使用日志识别结果补充 version 和 loader;如果客户端提交了同名 key,则以客户端值为准。
sourcestring否可选。来源标识,最长 64 字节。推荐使用「启动器标识/版本号」格式,例如 fcl/1.2.0。省略时服务端会尝试从 User-Agent 推断启动器来源,无法识别时记为「未指定」。该字段也会参与内容去重。

files 和 content 至少提供一个。两者同时提供时, content 作为主文件:服务端优先使用 latest.log,如果该名称已被 files 占用,则依次尝试 main.log、 latest (2).log 等名称。

FileInput

字段类型必填说明
namestring是必填。文件名或相对路径,例如 latest.log 或 crash-reports/crash-01.txt。最长 512 字节,超长会返回 400。如果文件名以 .zip 结尾,服务端会把 content 当作 ZIP 压缩包并展开。
contentstring是必填。文件内容。普通日志直接传文本;ZIP 文件传压缩包字节内容。

MetadataEntry

字段类型必填说明
keystring是必填。元数据键,去除首尾空白后不能为空;超过 64 个字符会截断。
valuestring | number | boolean | object是必填。元数据值。字符串超过 1024 个字符会截断;数组、对象会先 JSON 序列化,再按同样长度截断,公开接口返回的是 JSON 字符串。value 为 null 的条目会被丢弃。
labelstring否可选。展示名称,超过 128 个字符会截断。
visibleboolean否可选。是否在公开元信息接口中返回,默认 true。设置为 false 后,GET /v1/log/{id} 不会返回该条目。

服务端会用日志识别结果补写 version / loader 元数据;客户端提交同名 key 时以客户端值为准。重复 key 以首次出现为准。

响应字段

字段类型说明
successboolean请求是否成功。
messagestring服务端返回的结果说明。
idstring本次创建的日志 ID。如果命中内容去重,该 ID 指向已有日志。
urlstring可以直接分享给用户的页面地址。
filesUrlstring该日志的文件列表接口地址。
rawstring主文件原文地址。单文件日志指向 /v1/raw/{id};多文件日志如果上传时提供了 content,则指向 content 映射出的主文件,否则指向按文件名排序后的第一个文件。
tokenstring删除该日志所需的凭证。只在本次上传响应中返回一次,请立即保存。
deduplicatedboolean是否命中内容去重。为 true 时,本次响应中的 token 不能用于删除已有日志。
fileCountnumber本次日志包含的文件数量。
requiresFileSelectionboolean是否需要在多个文件中选择。文件数大于 1 时为 true。
filesarray<FileObject>文件列表,每个元素是一个 FileObject。

FileObject

字段类型说明
namestring文件名或相对路径。后续读取或分析该文件时,需要把这个值作为 filename 参数。
sizenumber文件字节数,仅用于展示,不参与上传限制。
linesnumber文件行数,按换行符计算,仅用于展示,不参与上传限制。
rawstring该文件的原文接口地址。
insightsstring该文件的 Codex 分析接口地址。
响应示例
{
  "success": true,
  "message": "Log submitted successfully",
  "id": "sAbCdEf",
  "url": "https://logshare.cn/sAbCdEf",
  "filesUrl": "https://api.logshare.cn/v1/log/sAbCdEf",
  "raw": "https://api.logshare.cn/v1/raw/sAbCdEf/latest.log",
  "token": "3f9c1a7d...",
  "deduplicated": false,
  "fileCount": 2,
  "requiresFileSelection": true,
  "files": [
    {
      "name": "latest.log",
      "size": 2048,
      "lines": 40,
      "raw": "https://api.logshare.cn/v1/raw/sAbCdEf/latest.log",
      "insights": "https://api.logshare.cn/v1/insights/sAbCdEf/latest.log"
    },
    {
      "name": "crash-reports/crash-01.txt",
      "size": 2048,
      "lines": 80,
      "raw": "https://api.logshare.cn/v1/raw/sAbCdEf/crash-reports/crash-01.txt",
      "insights": "https://api.logshare.cn/v1/insights/sAbCdEf/crash-reports/crash-01.txt"
    }
  ]
}
  • 如果文件是 ZIP 压缩包,服务端会展开压缩包并保留内部相对路径。展开后的每个文件都会单独脱敏和反混淆。同名文件会自动改名为 name (2).ext、 name (3).ext,避免覆盖。
  • 一次上传最多包含 200 个文件;所有文件展开后的总大小不能超过 20 MiB。旧版 content 映射出的主文件也计入这两个限制。单个文件本身没有大小或行数限制;ZIP 压缩包自身大小不计入 20 MiB,但原始 ZIP 字节仍受 32 MiB 请求体限制。
  • 文件名最长 512 字节,超过会返回 400。文件名中的子路径需要按路径段做 URL 编码,服务端只按存储名称精确匹配。
  • 如果同时提交了 content 和 files,content 会作为主文件,响应中的 raw 指向该文件;files 中的其余文件仍会出现在 files 列表。
  • 上传接口会返回删除 token。请把它保存在安全的位置;服务端不保存明文 token,丢失后无法找回。
GET/v1/log/{id}

日志元信息

该接口用于获取一条日志的元信息、公开 metadata 和文件列表。上传成功后,客户端通常应先获取一次元信息,确认日志包含哪些文件,以及是否需要让用户选择文件。

如果响应中的 requiresFileSelection 为 true,说明这条日志包含多个文件。客户端应展示 files 列表,让用户选择要查看的文件。

字段类型说明
idstring日志 ID,由 7 位字母和数字组成。
fileCountnumber该日志包含的文件数量。
requiresFileSelectionboolean是否需要在多个文件中选择。文件数大于 1 时为 true。
sizenumber所有文件合计的字节数。
linesnumber所有文件合计的行数。
creatednumber日志创建或最近一次续期的时间,Unix 秒。
expiresnumber逻辑过期时间,值为 created + storageTime,Unix 秒。实际删除可能因 TTL 回收延迟而晚于这个时间。
metadataarray<MetadataEntry>公开元数据数组。visible=false 的条目不会出现在这个字段中;数组/对象类型的 value 会以 JSON 字符串返回。
sourcestring上传时提交的来源标识;省略时可能由服务端从 User-Agent 推断,无法识别时为「未指定」。
filesUrlstring该日志的文件列表接口地址。
rawstring单文件日志指向 /v1/raw/{id};多文件日志指向按文件名排序后的第一个文件的 raw 地址,不保证是上传时 content 映射出的主文件。
filesarray<FileObject>文件列表。每个元素包含文件名、大小、行数以及该文件的 raw/insights 地址。

该接口不会续期。raw / insights 的任意成功读取(包括多文件时返回文件列表)都会重新计算过期时间;仅仅打开元信息页面不会延长日志的保留时间。

多文件响应中的 raw 指向按文件名排序后的第一个文件,不保证是上传时 content 映射出的主文件。如果客户端依赖主文件,请使用上传响应的 raw,或 files 中对应文件的 URL。

响应示例
{
  "success": true,
  "message": "Log metadata retrieved successfully",
  "id": "sAbCdEf",
  "fileCount": 2,
  "requiresFileSelection": true,
  "size": 4096,
  "lines": 120,
  "created": 1755200000,
  "expires": 1755804800,
  "metadata": [],
  "source": "fcl/1.2.0",
  "filesUrl": "https://api.logshare.cn/v1/log/sAbCdEf",
  "raw": "https://api.logshare.cn/v1/raw/sAbCdEf/latest.log",
  "files": [
    {
      "name": "latest.log",
      "size": 2048,
      "lines": 40,
      "raw": "https://api.logshare.cn/v1/raw/sAbCdEf/latest.log",
      "insights": "https://api.logshare.cn/v1/insights/sAbCdEf/latest.log"
    },
    {
      "name": "crash-reports/crash-01.txt",
      "size": 2048,
      "lines": 80,
      "raw": "https://api.logshare.cn/v1/raw/sAbCdEf/crash-reports/crash-01.txt",
      "insights": "https://api.logshare.cn/v1/insights/sAbCdEf/crash-reports/crash-01.txt"
    }
  ]
}

读取文件

读取文件时,需要先判断日志是否包含多个文件。单文件日志可以直接读取;多文件日志必须先获取文件列表,并使用文件名请求指定文件。

GET/v1/raw/{id}

当同一个 ID 下只有一个文件时,该接口会直接返回 text/plain 正文。如果该 ID 下存在多个文件,接口不会自动选择文件,而是返回文件列表;客户端需要先让用户选择文件,再使用带 filename 的接口。

GET/v1/raw/{id}/{filename}

该接口用于读取指定文件的原文。filename 必须与文件列表中的 name 完全一致。如果文件名包含子路径,例如 crash-reports/crash-01.txt,需要对每个路径段进行 URL 编码,但保留斜杠分隔符。服务端只按数据库中的文件名精确匹配,不会把它当作文件系统路径。

读取成功时返回 200 text/plain; charset=utf-8;文件不存在时返回 404。读取成功会续期日志的保留时间。

示例
curl 'https://api.logshare.cn/v1/raw/sAbCdEf/crash-reports/crash-01.txt'

分析文件

Codex 分析按文件执行。上传时不会立即分析全文,只有在请求某个文件的分析接口时才会执行。

GET/v1/insights/{id}

当同一个 ID 下只有一个文件时,该接口会直接返回该文件的 Codex 分析 JSON;如果该 ID 下存在多个文件,接口会返回文件列表,客户端需要先让用户选择文件,再请求 /v1/insights/{id}/{filename} 获取指定文件的分析结果。

GET/v1/insights/{id}/{filename}

响应字段

字段类型说明
idstringCodex 识别出的日志类型标识,例如 vanilla/server。
namestring日志类型名称。
typestring日志类别,例如 Server Log 或 Crash Report。
versionstring识别出的 Minecraft 版本。
titlestring分析标题。部分日志类型可能不返回这个字段。
analysis.problemsarray<Problem>检测到的问题列表。每个问题包含问题描述、出现次数和解决建议。
analysis.informationarray<Information>提取到的环境与版本信息列表。每条信息包含标签、值和出现次数。
Problem
messagestring问题描述。
counternumber该问题在文件中出现的次数。
solutionsarray<{ message: string }>解决建议列表。每个建议是一个对象,message 字段为建议内容。
Information
messagestring信息文本。
counternumber该信息出现的次数。
labelstring信息标签,例如 Minecraft version。
valuestring信息值。
响应示例
{
  "id": "vanilla/server",
  "name": "Vanilla",
  "type": "Server Log",
  "version": "1.21.9",
  "title": "Vanilla 1.21.9 Server Log",
  "analysis": {
    "problems": [
      {
        "message": "Could not load chunk",
        "counter": 3,
        "solutions": [
          { "message": "检查世界存档完整性并恢复备份" }
        ]
      }
    ],
    "information": [
      {
        "message": "Minecraft version: 1.21.9",
        "counter": 1,
        "label": "Minecraft version",
        "value": "1.21.9"
      }
    ]
  }
}

分析结果会按文件内容哈希缓存在服务端进程内。相同内容的文件重复请求时会直接返回缓存结果,不会重复执行 Codex。缓存有容量上限,服务重启后失效。

DELETE/v1/log/{id}

删除日志

该接口用于删除日志。删除时需要上传时返回的 token;服务端只保存 token 的哈希值,因此 token 丢失后无法找回。请求头中需要携带 Authorization: Bearer <token>。

路径中的 {id} 可以是一个日志 ID,也可以是多个用逗号分隔的日志 ID,例如 DELETE /v1/log/id1,id2。服务端会逐个校验日志是否存在,以及 token 是否匹配。

响应字段

字段类型说明
successboolean请求是否成功。只要至少有一个日志删除成功,这个字段就是 true。
messagestring服务端返回的结果说明。
deletedstring[]删除成功的日志 ID 列表。
failedarray<{ id, message, code }>删除失败的日志列表。每个元素包含 id、message 和 code。
totalnumber本次请求包含的日志总数。
deletedCountnumber删除成功的日志数量。
failedCountnumber删除失败的日志数量。
响应示例
{
  "success": true,
  "message": "Log deletion completed",
  "deleted": ["sAbCdEf"],
  "failed": [],
  "total": 1,
  "deletedCount": 1,
  "failedCount": 0
}
  • 如果所有 ID 都删除失败,接口返回 400,failed 数组会列出每个 ID 的失败原因和状态码。
  • 如果只有部分 ID 删除成功,接口返回 200,失败项仍然会出现在 failed 数组中。
  • 缺少 Authorization 请求头时返回 401;token 与日志不匹配时返回 403。
GET/v1/limits

上传限制

该接口返回当前部署的上传限制。客户端应在选择文件或上传前读取这些值,避免提交明显超过限制的内容。

字段类型说明
storageTimenumber日志保留时间,单位为秒。默认 604800 秒,即至少保留 7 天;expires 是逻辑过期时间,实际删除可能延迟。
maxFilesnumber一次上传允许包含的最大文件数。旧版 content 映射出的主文件也计入这个配额。
maxTotalBytesnumber所有文件展开后的总字节数上限。ZIP 压缩包自身大小不计入,但原始 ZIP 字节仍受 maxRequestBodyBytes 限制。
maxRequestBodyBytesnumber请求体(原始和解压后)的最大字节数。多层 Content-Encoding 会逐层解压,每一层输出都不能超过这个值。
响应示例
{
  "storageTime": 604800,
  "maxFiles": 200,
  "maxTotalBytes": 20971520,
  "maxRequestBodyBytes": 33554432
}

当前版本只返回上述四个字段。如果某个实例仍返回 maxLength / maxLines,说明它尚未升级到当前版本;客户端应以四个字段为准,并处理旧实例的差异。

平台在边缘层进行限流:nginx limit_req 按 IP 30 r/s(burst 60),OpenLiteWaf 再叠加 10 秒窗口 240 次的 CC 限流。触发 CC 限流时返回 429,并带有 Retry-After 响应头;触发 nginx limit_req 时返回 503。

错误与状态码

所有错误响应都使用相同的 JSON 结构。调用方应先检查 HTTP 状态码,再读取 error 字段;不要只依赖 message 字段,因为部分错误可能只返回 error。

错误响应
{
  "success": false,
  "error": "错误描述",
  "code": 400
}
状态码说明
200请求成功。多文件日志返回文件列表时也使用 200。
400请求参数错误、必填字段缺失、内容为空或文件名校验失败。
401删除请求缺少 Authorization: Bearer token。
403删除 token 不匹配,或客户端 IP 已被封禁。
404指定的日志或文件不存在。
405当前路径不支持该 HTTP 方法。
413请求体、文件数量或文件总大小超过限制;边缘 nginx 的 210 MB 请求体上限也返回 413。
415请求使用了不支持的 Content-Encoding。Content-Type 缺失或未知时会按 urlencoded 尝试解析,不返回 415。
429触发了 WAF CC 限流。响应会带 Retry-After 头,客户端应等待后重试。
500服务端内部错误。
501服务端未安装 Brotli 扩展,无法解压 br 请求体。
503触发了 nginx limit_req 限流。

根端点 GET / 返回当前部署支持的端点列表。它不需要认证,适合用于健康检查或确认服务能力。

GET / 响应示例
{
  "success": true,
  "message": "LogShare API",
  "endpoints": [
    "POST /v1/log",
    "GET /v1/log/{id}",
    "GET /v1/raw/{id}",
    "GET /v1/raw/{id}/{filename}",
    "GET /v1/insights/{id}",
    "GET /v1/insights/{id}/{filename}",
    "DELETE /v1/log/{id}",
    "GET /v1/limits"
  ]
}

SDK

v3.1.0

我们提供 JavaScript、PHP、Java 和 C#/.NET 四个 SDK。它们封装了上传、文件列表、读取、分析和删除接口,方法命名基本一致。下载后直接引入即可使用。JavaScript SDK 支持浏览器和 Node.js 18+;PHP 需要 7.4+;Java 需要 11+;.NET 需要 6+。

方法说明
submit(files, options)上传文件列表,返回日志对象
getMeta(id)获取日志元信息与文件列表,用于确定文件名以及是否需要让用户选择文件。
getRaw(id)读取单文件日志原文。仅当该日志只有一个文件时使用;多文件请使用 getRawFile。
getRawFile(id, filename)读取指定文件原文;filename 使用文件列表中的 name。
getInsights(id)分析单文件日志。仅当该日志只有一个文件时使用;多文件请使用 getInsightsFile。
getInsightsFile(id, filename)分析指定文件;filename 使用文件列表中的 name。
getLimits()获取上传限制
delete(id, token)删除一个或多个日志

JavaScript、PHP 和 Java 使用 camelCase 方法名;.NET 使用 PascalCase,并在异步方法后加 Async 后缀。四个 SDK 返回的数据结构与本文档一致;raw 文件接口返回字符串。

JavaScript 示例
import { LogShareSDK } from './mclogs.js'

const sdk = new LogShareSDK()

const result = await sdk.submit([
  { name: 'latest.log', content: logText },
  { name: 'crash-reports/crash-01.txt', content: crashText }
], {
  source: 'fcl/1.2.0',
  metadata: [{ key: 'version', value: '1.21.9', label: 'Minecraft 版本' }]
})

const meta = await sdk.getMeta(result.id)
const file = meta.files[0].name

const raw = await sdk.getRawFile(result.id, file)
const analysis = await sdk.getInsightsFile(result.id, file)