# @crvouga/mockingbird-service-otel 中文文档

规范地址：https://npmcn.com/package/%40crvouga/mockingbird-service-otel/

版本：3\.11\.9
npm 元数据更新时间：2026-11-03T01:35:05.159Z
中文译文更新时间：2026-11-11T02:23:57.620Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40crvouga/mockingbird-service-otel
原文对照：https://npmcn.com/package/%40crvouga/mockingbird-service-otel/?lang=original
项目主页：https://github.com/crvouga/mockingbird/tree/main/packages/service/otel#readme
源码仓库：https://github.com/crvouga/mockingbird

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：4.5 MB，18 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：2 个
- 首次发布：2026-09-22T23:56:04.404Z
- 最新版本发布：2026-11-03T01:35:04.834Z
- 近 30 天下载量：16397（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：42（近 12 个月 42 个）

## 中文简介

一个OTLP/HTTP收藏器(JSON和protobuf的痕迹和日志)的状态仿真器,以及在同一商店上的OpenObserve搜索API.

## 安装

```sh
npm install @crvouga/mockingbird-service-otel
```

也可以使用：`pnpm add @crvouga/mockingbird-service-otel`、`yarn add @crvouga/mockingbird-service-otel`、`bun add @crvouga/mockingbird-service-otel`

## README

# @crvouga/mockingbird-service-otel (英语)

> 本地模拟器。 真正的API合同. 部分 [嘲笑鸟](https://github.com/crvouga/mockingbird)。 。 。 .

国家模拟器 **OTLP/HTTP采集器** {\\fn华文仿宋\\fs16\\1chd1d1d1}在前面 **OpenObserve (O2) 搜索 API**, (中文(简体) ), 在一个商店。 当地和E2E公司停止向生产遥测基础设施出口,a 测试可以在结构化事件上断言:通过真实的OpenTelemotry SDK发射,然后读取 以相同的 SQL 日志返回, 我们的操作种子和调查代理发送( “调和语句) 发射 `initial_credit_reconcile_completed` 与 `granted=1`" (中文(简体) ).

-   行动范围: [支助](https://github.com/crvouga/mockingbird/blob/main/packages/service/otel/SUPPORT.md)
-   OTLP/HTTP 遵循开远- proto v1; O2 路径遵循 OpenObserve 的 API,被修剪为 我们的客户怎么称呼的.

## 安装

```bash
npm install -D @crvouga/mockingbird-service-otel
```

仅限无害环境管理。 节点 22或 Bun 1.2. 没有本地的依赖, 没有原始库( 最小) 有线格式解码器被建入). 给它服务 `npx mockingbird-otel serve`, (中文(简体) ), `createServer` 从 `./server` (节点),或 `createRuntime` 与任何获取服务器.

## 使用量

点 `OTEL_EXPORTER_OTLP_ENDPOINT` 在模拟器和设定中 `OTEL_TRACES_SAMPLER_ARG=1` (我们的SDK) 样本的10%的根部横跨。 点 `O2_BASE_URL` 在同一模拟器上; `O2_BASIC_AUTH` 实值 任何基础64 `user:password` 除非 `--search-auth` 已经设定.

```bash
npx mockingbird-otel serve --port 8809 --ingest-token "$OTEL_AUTH_TOKEN"
# a local collector that takes no credentials, with a browser exporter allowed in
npx mockingbird-otel serve --ingest-auth none --cors-origins http://localhost:5173
# a hosted OTLP gateway: Authorization: Basic base64(instanceId:token)
npx mockingbird-otel serve --ingest-basic-auth "$OTLP_INSTANCE_ID:$OTLP_TOKEN"
```

```ts
import { SeverityNumber } from "@opentelemetry/api-logs"
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http"
import { resourceFromAttributes } from "@opentelemetry/resources"
import { LoggerProvider, SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs"
import { createServer } from "@crvouga/mockingbird-service-otel/server"

const server = await createServer()

// The OpenTelemetry SDK your application already uses. Only the exporter's URL changes.
const exporter = new OTLPLogExporter({
  url: `${server.url}/v1/logs`,
  headers: { authorization: "Bearer ingest-token" },
})
const loggerProvider = new LoggerProvider({
  resource: resourceFromAttributes({ "service.name": "backend" }),
  processors: [new SimpleLogRecordProcessor(exporter)],
})
loggerProvider.getLogger("backend").emit({
  severityNumber: SeverityNumber.INFO,
  severityText: "info",
  body: "reconcile done", // dropped: bodies are never stored
  attributes: { event: "initial_credit_reconcile_completed", granted: 1 },
})
await loggerProvider.forceFlush()

// Test control: long-poll until the event lands.
await fetch(`${server.url}/__admin/wait`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ kind: "log", where: { event: "initial_credit_reconcile_completed" } }),
})

// Then query it the way our O2 clients do (OpenObserve's search API is plain HTTP).
const search = await fetch(`${server.url}/api/30rBqcDevOrg7Hn2KmQ4xW9sLtY/_search`, {
  method: "POST",
  headers: { "content-type": "application/json", authorization: `Basic ${btoa("agent:pw")}` },
  body: JSON.stringify({
    query: { sql: `SELECT * FROM "default" WHERE event = 'initial_credit_reconcile_completed'` },
  }),
})
console.log(await search.json())
// { hits: [{ service_name: "backend", event: "…", granted: 1, severity_text: "info", _timestamp }], … }

await loggerProvider.shutdown()
await server.close()
```

### 接收者

| 路线 | 行为 |
| --- | --- |
| `POST /v1/traces` | `ExportTraceServiceRequest`, (中文(简体) ), `application/json` 或者说 `application/x-protobuf` (可选择) `content-encoding: gzip`页:1 `200 {partialSuccess: {}}` (对原生取出请求的空原生取回. |
| `POST /v1/logs` | `ExportLogsServiceRequest`同样的编码和答案. |
| `POST /v1/metrics` | 接受和计算`GET /__admin/otlp-metrics`),从未被存储. |
| `OPTIONS /v1/traces`, (中文(简体) ), `/v1/logs`, (中文(简体) ), `/v1/metrics` | 浏览器导出者的 CORS 预飞, 当 `cors.allowedOrigins` 设置(参见 _浏览器 CORS_页:1 `405`。 。 。 . |

不可解码的有效载荷为400个,其他内容类型为415. 每个接收器错误都是 `google.rpc.Status` (单位:千美元)`{code, message}`)在请求的编码中: 二进制原生于 `application/x-protobuf` 请求, JSON 否则。 可选 `stream-name` 标题选择 流( 默认) `default`) (中文(简体) ).

**收集者认证.** 接收者认证输出它所代表的收藏家的方式 因此,出口商在接受测试时保留其真正的信头。 模式是 `ingestAuth` 设置 (单位:千美元)`createRuntime({settings})`, (中文(简体) ), `PUT /__admin/settings` 每个命名空间,或 `--ingest-auth`:

| `ingestAuth` | 导出需要 | 被缩小 |
| --- | --- | --- |
| `bearer` (默认) | `Authorization: Bearer <token>`\- 任何标志,401没有. | `ingestTokens` 编号 : `--ingest-token`:只有那些标志. |
| `basic` | `Authorization: Basic base64(user:password)`,一个主机OTLP网关所取头条(Grafana Cloud: `instanceId:token`:任何证书,401没有. | `ingestUsers: [{username, password}]` 编号 : `--ingest-basic-auth <user:password>`:只有这些. |
| `none` | 没什么 本地收藏家 一个 `Authorization` 仍然发送的出口商信头被忽略 . | —— 说 |

拒绝的导出是 `401 {"code": 16, "message": "Unauthenticated"}`模式只需要它自己的 计划(无记名代号为401) `basic` 模式和反向),在前检查证书 有效载荷被解析,在每一种模式下,一个可接受的有效载荷被解析并以同样的方式储存. 只有接收器会改变:O2搜索总是想要Basic Certain.

**浏览器 CORS.** 默认关闭 : `OPTIONS /v1/*` 实值 `405` 并且没有带CORS信头. 设定 `cors` (同为三地; `--cors-origins`, (中文(简体) ), `--cors-headers`)将浏览器导出者回答为 打开数位收集器 `cors:` 块执行 :

```ts
import { createRuntime } from "@crvouga/mockingbird-service-otel"

createRuntime({
  settings: {
    ingestAuth: "none",
    cors: {
      allowedOrigins: ["https://app.example.test", "https://*.preview.example.test"], // or "*"
      allowedHeaders: ["authorization", "content-type", "traceparent", "tracestate"], // or "*"
      allowedMethods: ["POST"], // default GET, POST, HEAD
      exposedHeaders: [], // Access-Control-Expose-Headers on the export
      maxAge: 600, // Access-Control-Max-Age, seconds
    },
  },
})
```

飞行前`OPTIONS` 与 `Origin` 财务报告和审定财务报表 `Access-Control-Request-Method`) 之前已回答 认证, 总是 `204`。当来源、要求的方法和每个名称在 `Access-Control-Request-Headers` 允许携带 `Access-Control-Allow-Origin` (单位:千美元) 来源,或 `*`, (中文(简体) ), `-Allow-Methods`, (中文(简体) ), `-Allow-Headers` (两者都响应请求), `-Allow-Credentials: true` 财务报告和审定财务报表 `-Max-Age`不然,它不携带任何物 在浏览器中失败 。 包含错误的导出反应 `Access-Control-Allow-Origin`, (中文(简体) ), `-Allow-Credentials` 财务报告和审定财务报表 `Vary: Origin` 被允许的来源. 与 `allowedHeaders` 未设置 `accept`, (中文(简体) ), `content-type` 财务报告和审定财务报表 `x-requested-with` 通过;一旦 列表是准确的,所以名称 `content-type` (OTLP内容类型从来不是CORS-安全列表) 和你们的出口者所加的推广信头。 飞行前没有证书 名称空间: 它读取默认的名称空间设置, 除非端点使用 `/__admin/ns/<name>` 前缀( 设置传递给 `createRuntime` 适用于每个命名空间.

**储存,因为氧气储存它.** 每个字段名称都小写并平分(`clientUserId` → `clientuserid`, (中文(简体) ), `http.status_code` → `http_status_code`,与 `_`; 资源 属性获得一个 `service_` 前缀( e)`service_service_version`, (中文(简体) ), `service_deployment_environment_name`) 除外 `service.name` → `service_name`; 无字段为 掉下来了 日志携带 `_timestamp` (单位), `severity_text`, (中文(简体) ), `severity_number`, (中文(简体) ), `trace_id`, (中文(简体) ), `span_id` 及其属性`event`...)斯潘斯携带 `operation_name`, (中文(简体) ), `trace_id`, (中文(简体) ), `span_id`, (中文(简体) ), `reference_parent_span_id`, (中文(简体) ), `span_kind`, (中文(简体) ), `span_status` (单位:千美元)`UNSET`编号 :`OK`编号 :`ERROR`, (中文(简体) ), `start_time` 编号 : `end_time` (数量), `duration` (单位), `events` (JSON:每个事件的名称、时间和属性)和 其属性,其标识与导出完全相同. **记录机构被丢弃** 除非 `--keep-bodies` (一躯体可以持有即时或PHI;截取不是保护) `body` 栏仍然存在于图中,因此选择它继续工作的食谱.

**鄂尔克通路.** `deployment.environment.name` (或 `deployment.environment`(中文(简体) ) `production` 土地 输入 `production` org; 任何其它内容 `development`就像收藏家的dev -org默认. 默认值 : `default`, (中文(简体) ), `development` (单位:千美元)`30rBqcDevOrg7Hn2KmQ4xW9sLtY`, (中文(简体) ), `production` (单位:千美元)`3HSzeProdOrg5Jd8VpN1cR6gTfB`) (中文(简体) ).

### 氧气搜索

| 路线 | 行为 |
| --- | --- |
| `GET /api/organizations` | `{data: [{id, identifier, name, type}]}`: 显示名称-标识符. |
| `GET /api/{org}/streams?type=logs|traces` | `{list: [{name, stream_type, stats: {doc_num}}]}`。 。 。 . |
| `GET /api/{org}/streams/{stream}/schema?type=logs|traces` | `{name, stream_type, schema: [{name, type}]}`:每个领域都摄入了非核. 摄入前404个. |
| `POST /api/{org}/_search?type=logs|traces` | `{query: {sql, start_time, end_time (µs), from, size}}` → `{took, hits, total, from, size, scan_records, is_partial}`。 。 。 . |

需要基本的认证( E)`401 Unauthorized Access`页:1. `{org}` 必须是 org **标识符**: 显示名称 (`/api/production/_search`如释放导体所发送的) 同样的赤出401个真正的O2答案,这样bug就保持可见.

SQL 子集 : `SELECT * | expr [AS alias], … FROM "<stream>" [WHERE …] [GROUP BY …] [HAVING …] [ORDER BY expr [ASC|DESC], …] [LIMIT n [OFFSET m]]` 与 `AND`编号 :`OR`编号 :`NOT`, (中文(简体) ), `=`, (中文(简体) ), `!=`编号 :`<>`, (中文(简体) ), `<`, (中文(简体) ), `<=`, (中文(简体) ), `>`, (中文(简体) ), `>=`, (中文(简体) ), `IS [NOT] NULL`, (中文(简体) ), `[NOT] IN`, (中文(简体) ), `[NOT] LIKE`编号 :`ILIKE`, (中文(简体) ), `[NOT] BETWEEN` (ISO 字符串比较 `_timestamp`),以及 `str_match`, (中文(简体) ), `str_match_ignore_case`, (中文(简体) ), `match_all`, (中文(简体) ), `re_match`, (中文(简体) ), `lower`, (中文(简体) ), `upper`, (中文(简体) ), `tostring`, (中文(简体) ), `length`, (中文(简体) ), `coalesce`, (中文(简体) ), `count(*)`, (中文(简体) ), `count([DISTINCT] x)`, (中文(简体) ), `min`, (中文(简体) ), `max`, (中文(简体) ), `sum`, (中文(简体) ), `avg`外侧行 `start_time`– 说吧 –`end_time` 除外,默认命令是 `_timestamp DESC`, (中文(简体) ), `LIMIT` 应用 在此之前 `from`编号 :`size` 呼唤. **列名称对大小写敏感,必须存在于流中 计划**数字 : `clientUserId` 或者从未被摄入的一栏是 `400 … No field named …`作为我们的客户 等着吧 在无数据流上的查询会解答空打.

### 管理员(超过标准合同)

| 路线 | 效果 |
| --- | --- |
| `GET /__admin/logs?service=&event=&severity=&trace_id=&org=` | 已存储日志行( 有 `_org`, (中文(简体) ), `_stream`) (中文(简体) ). |
| `GET /__admin/spans?service=&name=&trace_id=&org=` | 存储横行. |
| `POST /__admin/wait` | `{kind: "log"|"span", where: {event: "…", …}, count?: 1, timeoutMs?: 5000, org?}`: 长波到 `count` 行匹配( 200) `{matched, count}`)或出局次数(408次与匹配次数). `where` 键可能被拼写为已放出( e)`clientUserId`, (中文(简体) ), `service.name`)或为所储存. |
| `GET /__admin/otlp-metrics` | `{requests, bytes, metrics}` 页:1 `/v1/metrics`。 。 。 . |
| `GET /__admin/settings` | 调用命名空间的设置 . |
| `PUT /__admin/settings` | `{ingestAuth?: "bearer"|"basic"|"none", ingestTokens?, ingestUsers?: [{username, password}], cors?: {allowedOrigins, allowedHeaders?, allowedMethods?, exposedHeaders?, maxAge?}, searchUsers?: [{username, password}], organizations?: [{identifier, name}], routing?: {byEnvironment, default}, keepBodies?}` 用于调用命名空间;只有密钥发出更改. |

`/__admin/spans`, (中文(简体) ), `/__admin/logs` 财务报告和审定财务报表 `/__admin/wait` 是导出所摄入的: 每个跨度或日志记录的正则行数,每个属性保存(参见 _存储_ (见上文)。 原画 OTLP请求批次没有保留 `GET /__admin/requests` 记录每个导出,而不包含其 躯体.

错误预设( E)`POST /__admin/faults {"preset": "<name>", "count"?: n}`: `rate_limited` (429个+) `retry-after: 1`, (中文(简体) ), `bad_gateway` (502个), `unavailable` (503个), `gateway_timeout` (504个)——全部 被SDK重审.. `server_error` (500个)和 `unauthorized` (401),即SDK下降, `partial_success` (200个拒绝每个项目,只有JSON)和 `search_unavailable` (O2搜索503). 它们在每个认证模式下工作 并且使导出有问题 `POST` 只有,没有CORS飞行前 尸体是JSON 无论要求的编码.

### 命名空间

`x-mockingbird-namespace`页:1 `/__admin/ns/<name>` 前缀在端点和基址上,或者通过证书: `PUT /__admin/credentials {"credentials": {"<OTEL_AUTH_TOKEN>": "w1", "<O2 username>": "w1"}}` (图 使一个工人的出口 和搜索满足)。 单位 `basic` 模式 用户名( 实例编号); in `none` 模式没有,所以使用标题或路径前缀.

### 故意不模拟

-   gRPC OTLP(4317号口);只有OTLP/HTTP.
-   计量存储和O2度量/PromQL API:仅计算计量出口.
-   O2的全SQL方言(DataFusion):相接,子克,窗口功能,算术, `histogram()`, (中文(简体) ), `approx_*`; 只有上面的子集.
-   氧气通过 `/api/{org}/{stream}/_json` 或者说 `/api/{org}/v1/logs`、仪表板、警报和 (b) 收集器本身的分批、尾部取样和变压处理器.
-   `partialSuccess` 用于 protobuf 请求(发送空成功响应).
-   原OTLP批次,无行所持的跨字段:链接,痕量状态,旗帜 状态信息、范围版本和已丢弃的项目计数. `start_time` 编号 : `end_time` 为: JSON 数字,所以 纳米秒超过 2^53 个回合(`_timestamp` 财务报告和审定财务报表 `duration`),用μs表示,准确.
-   主机网关的地表: `/otlp` 路径前缀( 在模拟器上指定导出者) root,或设置每个符号终点),其符号范围和其401的措辞. 401号是 oTLP号 `Status` 见上文.
-   收集器的 CORS 库也拒绝飞行前 `Access-Control-Request-Headers` 不是小写, 已排序的列表浏览器发送; 这里的名称按顺序和大小写匹配 .
-   默认日志机构(参见 `--keep-bodies`) (中文(简体) ).

## API 密码

| 导出 | 仁爱 | 说明 |
| --- | --- | --- |
| `OtelAPI` | 类 | 进程模拟器 : `fetch(request)`, (中文(简体) ), `reset()`, (中文(简体) ), `logs()`, (中文(简体) ), `spans()`, (中文(简体) ), `state`选项: `sqlite`, (中文(简体) ), `now`, (中文(简体) ), `namespace`, (中文(简体) ), `settings`。 。 。 . |
| `createRuntime` | 函数 | 全面服务合同的仿真器(保健、管理员、等待、命名空间、证书、预设)。 选项 : `settings` (单位:千美元)`ingestAuth`, (中文(简体) ), `ingestTokens`, (中文(简体) ), `ingestUsers`, (中文(简体) ), `cors`, (中文(简体) ), `searchUsers`, (中文(简体) ), `organizations`, (中文(简体) ), `routing`, (中文(简体) ), `keepBodies`, (中文(简体) ), `clock`, (中文(简体) ), `seed`, (中文(简体) ), `adminKey`, (中文(简体) ), `onLog`, (中文(简体) ), `sqlite`。 。 。 . |
| `OTEL_PRESETS` | 对象 | 每个命名的断层预设. |
| `OTEL_NAMESPACE` | 字符串 | 服务名称, `"otel"`。 。 。 . |
| `otelCredential` | 函数 | OTLP无记名符号或 Basic 用户名( 如何将证书映射到命名空间) . |
| `adminRow` | 函数 | 管理员路线显示的存储行( A)`_org`, (中文(简体) ), `_stream` 页:1. |
| `DEFAULT_ORGANIZATIONS`, (中文(简体) ), `DEFAULT_SETTINGS`, (中文(简体) ), `INGEST_AUTH_MODES` | 数值 | 被播种的野兽和设置( E)`ingestAuth: "bearer"`和认证模式. |
| `logRows`, (中文(简体) ), `spanRows`, (中文(简体) ), `formatKey` | 函数 | OTLP/JSON导出 → O2行,而 O2 的字段名正态化. |
| `decodeLogsRequest`, (中文(简体) ), `decodeTraceRequest`, (中文(简体) ), `ProtobufError` | 函数,类 | 原生出出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自. |
| `parseSql`, (中文(简体) ), `execute`, (中文(简体) ), `referencedColumns`, (中文(简体) ), `SqlError` | 函数,类 | SQL 子集: 解析, 运行在行上, 列出所读查询的列 . |
| `document`, (中文(简体) ), `operationIds`, (中文(简体) ), `supportedOperationIds` | 数值 | OpenAPI合同及其操作代号. |
| `createServer`, (中文(简体) ), `serveTarget`, (中文(简体) ), `DEFAULT_PORT` (单位:千美元)`./server`(中文(简体) ) | 节点 | 服务过来 `node:http`; 数据 `serve` CLI目标; 第8809口. |

部分 [嘲笑鸟](https://github.com/crvouga/mockingbird)。 。 。 .

## 常见问题

### @crvouga/mockingbird-service-otel 是什么？

一个OTLP/HTTP收藏器\(JSON和protobuf的痕迹和日志\)的状态仿真器,以及在同一商店上的OpenObserve搜索API\.

### 如何安装 @crvouga/mockingbird-service-otel？

在项目目录运行 npm install @crvouga/mockingbird-service-otel，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-otel，可以用 npx mockingbird-otel 直接运行。

### @crvouga/mockingbird-service-otel 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @crvouga/mockingbird-service-otel 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @crvouga/mockingbird-service-otel 可以商用吗？

@crvouga/mockingbird-service-otel 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @crvouga/mockingbird-service-otel 的下载量有多少？

根据 npm 官方下载统计，@crvouga/mockingbird-service-otel 在 2026/10/11 – 2026/11/09 这 30 天内被下载 16,397 次，日均约 547 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @crvouga/mockingbird-service-otel 还在维护吗？

最新版本 3\.11\.9 发布于 2026/11/03（8 天前）；至今共发布 42 个版本，其中过去 12 个月发布了 42 个；首次发布于 2026/09/23。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

