@deepseek-ai/dsh-otel 0.2.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +37 -0
- package/README.md +70 -0
- package/README.zh.md +70 -0
- package/lib/index.js +399 -0
- package/lib/types/event-log.d.ts +52 -0
- package/lib/types/event-transport.d.ts +12 -0
- package/lib/types/index.d.ts +30 -0
- package/lib/types/session-log.d.ts +68 -0
- package/lib/types/transport.d.ts +21 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/telemetry/otel/README.md
|
|
5
|
+
/:
|
|
6
|
+
en: 49f35d8bc0fe3689
|
|
7
|
+
zh: ef2fd903cca7d129
|
|
8
|
+
/deepseek-ai-dsh-otel:
|
|
9
|
+
en: 925bc4650e9895d6
|
|
10
|
+
zh: 02f8917c4048f6e2
|
|
11
|
+
/deepseek-ai-dsh-otel/summary:
|
|
12
|
+
en: e32c122f34c04593
|
|
13
|
+
zh: bea48183ab438454
|
|
14
|
+
/deepseek-ai-dsh-otel/table-of-contents:
|
|
15
|
+
en: 23386452a66b2fbd
|
|
16
|
+
zh: 55b2121ae6059425
|
|
17
|
+
/deepseek-ai-dsh-otel/use-this-package:
|
|
18
|
+
en: f141a9d909c555d8
|
|
19
|
+
zh: e4f5b690ccb1337c
|
|
20
|
+
/deepseek-ai-dsh-otel/understand-the-implementation:
|
|
21
|
+
en: 0976ab2c661529bb
|
|
22
|
+
zh: 9653db33fc70195d
|
|
23
|
+
/deepseek-ai-dsh-otel/further-exploration:
|
|
24
|
+
en: ee17b991de098cc0
|
|
25
|
+
zh: f90257e411921f2b
|
|
26
|
+
/deepseek-ai-dsh-otel/model-experience:
|
|
27
|
+
en: 5b364b9451ced69f
|
|
28
|
+
zh: 025feb91ef96bdb8
|
|
29
|
+
/deepseek-ai-dsh-otel/model-experience/kv-cache-effect:
|
|
30
|
+
en: 8be9251f0d5256ed
|
|
31
|
+
zh: d46143a02855c8bc
|
|
32
|
+
/deepseek-ai-dsh-otel/known-limitations-and-deferred-work:
|
|
33
|
+
en: 5c3e29312d45ee52
|
|
34
|
+
zh: b148e3a6decc0f7d
|
|
35
|
+
/deepseek-ai-dsh-otel/known-limitations-and-deferred-work/dev-note:
|
|
36
|
+
en: 0a1253c6f7b5e8b9
|
|
37
|
+
zh: 9f56528562c7c914
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Create independent OTLP reporting channels through the shared Cordis OTel service."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-otel
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
Mount one `otel` service to create ordinary-event and Session-log reporting channels. Each channel has its own exporter, resource, instrumentation scope, and queue. Mounting alone creates no transport or identity and sends nothing. Business consumers own authorization, redaction, field selection, and their channel's disposal.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
<a id="use-this-package"></a>
|
|
24
|
+
## Use this package
|
|
25
|
+
|
|
26
|
+
The base bundle mounts `@deepseek-ai/dsh-otel`. Independent compositions must mount it before consumers that inject `otel`. Call `ctx.otel.createEventReporter(options)` for ordinary analytics or `ctx.otel.createSessionLogReporter(options)` for complete Session events. Options explicitly supply endpoint, scope, resource attributes, queue settings, and a diagnostic callback; the service has no deployment defaults or automatic collection policy of its own.
|
|
27
|
+
|
|
28
|
+
The returned channel belongs to the consumer. Ordinary-event `shutdown(signal)` cancels requests and retry waits when the supplied signal aborts, and resolves after transport cleanup. Register shutdown with the consumer's Cordis fiber and bound the complete drain with its configured deadline. Injection makes service replacement unload dependent consumers. Do not retain a channel after its consumer unloads. The product and Session adapters implement this ownership for UI and feedback callers.
|
|
29
|
+
|
|
30
|
+
Ordinary channels use SDK count-based batching. Session channels preserve one complete event per record with `eventName: "session-log"`, `sessionId`, and a JSON string `content`, and enforce at most 4,000,000 uncompressed request bytes. Their byte limits, single-record rejection, serial transport settlement, and shutdown behavior are specified by the [Session adapter](../../session/session-telemetry-otel/README.md). A Session channel never shares a request or queue with ordinary events.
|
|
31
|
+
|
|
32
|
+
Headers are explicit. The service does not add a channel header or inherit ambient authorization headers or TLS identity. Agent factories configure their returned agents, including keepAlive. Ordinary-event channels destroy their agent on shutdown; factories must provide a dedicated agent for each channel. Scope names and versions are supplied by each consumer, so transport sharing does not change event attribution.
|
|
33
|
+
|
|
34
|
+
<a id="understand-the-implementation"></a>
|
|
35
|
+
## Understand the implementation
|
|
36
|
+
|
|
37
|
+
`src/index.ts` registers the service; `event-log.ts` owns ordinary SDK batching; `session-log.ts` owns byte/count scheduling; `transport.ts` supplies the Session SDK JSON HTTP delegate; `event-transport.ts` uses Got for cancellable ordinary-event HTTP requests and retry waits with SDK serialization and export accounting. No global OTel provider is installed. The Session processor measures each record once, groups conservative sizes, and waits for the SDK concurrency queue to clear after every callback before sending another request.
|
|
38
|
+
|
|
39
|
+
No runtime invariant companion is published: channel creation registers no independent domain state, and collector delivery cannot be inferred from local queues. Composition tests exercise independent channels and service removal; adapter tests cover dependent-fiber cleanup and feedback authorization.
|
|
40
|
+
|
|
41
|
+
<a id="further-exploration"></a>
|
|
42
|
+
## Further Exploration
|
|
43
|
+
|
|
44
|
+
- [OTel subsystem](../../../docs/subsystems/otel.md) — service ownership and API.
|
|
45
|
+
- [Product adapter](../../host/product-telemetry-otel/README.md) — explicit analytics policy and configuration.
|
|
46
|
+
- [Session adapter](../../session/session-telemetry-otel/README.md) — feedback authorization and configured upload limits.
|
|
47
|
+
|
|
48
|
+
<a id="model-experience"></a>
|
|
49
|
+
## Model Experience
|
|
50
|
+
|
|
51
|
+
None, as the service delivers caller-selected records without changing model context.
|
|
52
|
+
|
|
53
|
+
#### KV Cache effect
|
|
54
|
+
|
|
55
|
+
None; reporting does not change model requests.
|
|
56
|
+
|
|
57
|
+
## Known Limitations and Deferred Work
|
|
58
|
+
|
|
59
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
60
|
+
|
|
61
|
+
Channels provide best-effort, memory-only delivery with the following limits.
|
|
62
|
+
|
|
63
|
+
- The caller owns consent, redaction, resource identity, renderer-to-host RPC, and the outer shutdown deadline.
|
|
64
|
+
- Queue overflow, oversized Session events, transport failure, and process exit can lose records. There is no durable outbox or warehouse acknowledgement.
|
|
65
|
+
- Ordinary-event channels batch by count; their consumers must select event and batch sizes suitable for the collector.
|
|
66
|
+
|
|
67
|
+
<a id="dev-note"></a>
|
|
68
|
+
### Dev Note
|
|
69
|
+
|
|
70
|
+
None.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "通过共享 Cordis OTel 服务创建独立的 OTLP 上报通道。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-otel
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
挂载一个 `otel` 服务即可创建普通事件和 Session 日志上报通道。每个通道拥有独立的 exporter、resource、instrumentation scope 和队列。仅挂载不会创建传输、身份或发送数据。业务调用方负责授权、脱敏、字段选择及通道销毁。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与后续工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
<a id="use-this-package"></a>
|
|
24
|
+
## 使用本包
|
|
25
|
+
|
|
26
|
+
base bundle 挂载 `@deepseek-ai/dsh-otel`。独立组合必须在注入 `otel` 的调用方之前挂载它。普通埋点调用 `ctx.otel.createEventReporter(options)`,完整 Session 事件调用 `ctx.otel.createSessionLogReporter(options)`。选项显式提供 endpoint、scope、resource attributes、队列设置和诊断回调;服务本身没有部署默认值或自动采集策略。
|
|
27
|
+
|
|
28
|
+
返回的通道由调用方持有。普通事件 `shutdown(signal)` 在传入信号中止时取消请求和重试等待,并在传输清理完成后返回。将关闭注册到调用方的 Cordis fiber,并用配置的期限约束完整清空过程。注入机制使服务替换时卸载依赖方。调用方卸载后不得继续保留通道。产品和 Session 适配器为 UI 和反馈调用方实现这些职责。
|
|
29
|
+
|
|
30
|
+
普通通道使用 SDK 按条数聚合。Session 通道将每条完整事件保留为一个记录,包含 `eventName: "session-log"`、`sessionId` 和 JSON 字符串 `content`,并保证未压缩请求不超过 4,000,000 字节。字节限制、单条拒绝、串行传输结束和关闭行为见 [Session 适配器](../../session/session-telemetry-otel/README.zh.md)。Session 通道不会与普通事件共享请求或队列。
|
|
31
|
+
|
|
32
|
+
Header 显式提供。服务不会附加 channel header,也不继承环境中的授权 header 或 TLS 身份。Agent factory 配置返回的 agent,包括 keepAlive。普通事件通道在关闭时销毁自己的 agent;factory 必须为每个通道提供独立 agent。每个调用方提供 scope 名称和版本,因此共享传输不会改变事件归属。
|
|
33
|
+
|
|
34
|
+
<a id="understand-the-implementation"></a>
|
|
35
|
+
## 理解实现
|
|
36
|
+
|
|
37
|
+
`src/index.ts` 注册服务;`event-log.ts` 负责普通事件的 SDK 聚合;`session-log.ts` 负责字节和条数调度;`transport.ts` 提供 Session 的 SDK JSON HTTP delegate;`event-transport.ts` 使用 Got 实现可取消的普通事件 HTTP 请求和重试等待,序列化与导出计数仍由 SDK 负责。不安装全局 OTel provider。Session processor 对每条记录只计量一次,按保守大小组包,并在每次回调后等待 SDK 并发队列清理完成才发送下一请求。
|
|
38
|
+
|
|
39
|
+
不发布运行时不变式伴生入口:通道创建不注册独立领域状态,无法从本地队列推断 collector 是否收到记录。组合测试覆盖独立通道和服务移除;适配器测试覆盖依赖 fiber 清理与反馈授权。
|
|
40
|
+
|
|
41
|
+
<a id="further-exploration"></a>
|
|
42
|
+
## 进一步探索
|
|
43
|
+
|
|
44
|
+
- [OTel 子系统](../../../docs/subsystems/otel.zh.md) — 服务职责与 API。
|
|
45
|
+
- [产品适配器](../../host/product-telemetry-otel/README.zh.md) — 显式埋点策略与配置。
|
|
46
|
+
- [Session 适配器](../../session/session-telemetry-otel/README.zh.md) — 反馈授权和上传限制配置。
|
|
47
|
+
|
|
48
|
+
<a id="model-experience"></a>
|
|
49
|
+
## 模型体验
|
|
50
|
+
|
|
51
|
+
无,因为服务只投递调用方选择的记录,不改变模型上下文。
|
|
52
|
+
|
|
53
|
+
#### KV Cache 影响
|
|
54
|
+
|
|
55
|
+
无;上报不改变模型请求。
|
|
56
|
+
|
|
57
|
+
## 已知限制与后续工作
|
|
58
|
+
|
|
59
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
60
|
+
|
|
61
|
+
通道提供尽力而为的纯内存投递,具有以下限制。
|
|
62
|
+
|
|
63
|
+
- 调用方负责同意、脱敏、resource 身份、renderer 到 host 的 RPC 及外层关闭期限。
|
|
64
|
+
- 队列溢出、Session 事件超限、传输失败和进程退出可能丢失记录。不提供持久 outbox 或仓库确认。
|
|
65
|
+
- 普通事件通道按条数聚合;调用方必须选择适合 collector 的事件和批次大小。
|
|
66
|
+
|
|
67
|
+
<a id="dev-note"></a>
|
|
68
|
+
### 开发备注
|
|
69
|
+
|
|
70
|
+
无。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { Service } from "@deepseek-ai/cordis";
|
|
2
|
+
import { addAbortListener } from "node:events";
|
|
3
|
+
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
4
|
+
import { ExportResultCode } from "@opentelemetry/core";
|
|
5
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
6
|
+
import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
|
|
7
|
+
import { gzipSync } from "node:zlib";
|
|
8
|
+
import got from "got";
|
|
9
|
+
import { OTLPExporterBase, createOtlpNetworkExportDelegate, getSharedConfigurationDefaults, mergeOtlpSharedConfigurationWithDefaults } from "@opentelemetry/otlp-exporter-base";
|
|
10
|
+
import { JsonLogsSerializer } from "@opentelemetry/otlp-transformer";
|
|
11
|
+
import { createOtlpHttpExportDelegate, getSharedConfigurationFromEnvironment, httpAgentFactoryFromOptions } from "@opentelemetry/otlp-exporter-base/node-http";
|
|
12
|
+
//#region lib/types/transport.js
|
|
13
|
+
/** Explicit OTLP JSON transport for feedback-authorized Session logs. */
|
|
14
|
+
/**
|
|
15
|
+
* Create an SDK JSON exporter without inheriting another collector's headers or TLS identity.
|
|
16
|
+
* @param options - explicit endpoint, headers, agent, and SDK transport settings.
|
|
17
|
+
* @returns the exporter owned by one independent log pipeline.
|
|
18
|
+
*/
|
|
19
|
+
function createLogExporter(options) {
|
|
20
|
+
return new OTLPExporterBase(createOtlpHttpExportDelegate(logTransportOptions(options), JsonLogsSerializer));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve collector-local headers and agents with shared SDK timeout and compression defaults.
|
|
24
|
+
* @param options - explicit endpoint and SDK HTTP settings.
|
|
25
|
+
* @returns resolved transport settings without ambient credentials.
|
|
26
|
+
*/
|
|
27
|
+
function logTransportOptions(options) {
|
|
28
|
+
return {
|
|
29
|
+
...mergeOtlpSharedConfigurationWithDefaults(options, getSharedConfigurationFromEnvironment("LOGS"), getSharedConfigurationDefaults()),
|
|
30
|
+
url: options.url,
|
|
31
|
+
headers: async () => ({
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
...typeof options.headers === "function" ? await options.headers() : options.headers
|
|
34
|
+
}),
|
|
35
|
+
agentFactory: typeof options.httpAgentOptions === "function" ? options.httpAgentOptions : httpAgentFactoryFromOptions({
|
|
36
|
+
keepAlive: options.keepAlive ?? true,
|
|
37
|
+
...options.httpAgentOptions
|
|
38
|
+
}),
|
|
39
|
+
...options.userAgent === void 0 ? {} : { userAgent: options.userAgent }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region lib/types/event-transport.js
|
|
44
|
+
/**
|
|
45
|
+
* Create a channel-owned exporter whose cancellation releases requests and retry timers.
|
|
46
|
+
* @param options - explicit collector and SDK HTTP settings.
|
|
47
|
+
* @param signal - channel cancellation, shared by current and future batch exports.
|
|
48
|
+
* @returns the SDK exporter; shutdown also destroys its owned HTTP agent.
|
|
49
|
+
*/
|
|
50
|
+
function createEventLogExporter(options, signal) {
|
|
51
|
+
const config = logTransportOptions(options);
|
|
52
|
+
let agent;
|
|
53
|
+
const exporter = new OTLPExporterBase(createOtlpNetworkExportDelegate(config, JsonLogsSerializer, {
|
|
54
|
+
async send(data, timeoutMillis) {
|
|
55
|
+
signal.throwIfAborted();
|
|
56
|
+
agent ??= config.agentFactory(new URL(config.url).protocol);
|
|
57
|
+
const selectedAgent = await agent;
|
|
58
|
+
const headers = await config.headers();
|
|
59
|
+
signal.throwIfAborted();
|
|
60
|
+
const compressed = config.compression === "gzip";
|
|
61
|
+
const request = got.post(config.url, {
|
|
62
|
+
body: compressed ? gzipSync(data) : Buffer.from(data),
|
|
63
|
+
headers: {
|
|
64
|
+
...headers,
|
|
65
|
+
...compressed ? { "content-encoding": "gzip" } : {},
|
|
66
|
+
...config.userAgent === void 0 ? {} : { "user-agent": config.userAgent }
|
|
67
|
+
},
|
|
68
|
+
agent: new URL(config.url).protocol === "https:" ? { https: selectedAgent } : { http: selectedAgent },
|
|
69
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(timeoutMillis)]),
|
|
70
|
+
followRedirect: false,
|
|
71
|
+
retry: {
|
|
72
|
+
limit: 5,
|
|
73
|
+
methods: ["POST"],
|
|
74
|
+
statusCodes: [
|
|
75
|
+
429,
|
|
76
|
+
502,
|
|
77
|
+
503,
|
|
78
|
+
504
|
|
79
|
+
],
|
|
80
|
+
errorCodes: [],
|
|
81
|
+
backoffLimit: 5e3
|
|
82
|
+
},
|
|
83
|
+
responseType: "buffer"
|
|
84
|
+
});
|
|
85
|
+
request.on("downloadProgress", ({ transferred }) => {
|
|
86
|
+
if (transferred > 4 * 1024 * 1024) request.cancel();
|
|
87
|
+
});
|
|
88
|
+
const response = await request;
|
|
89
|
+
if (response.statusCode >= 300) throw new Error(`OTLP collector returned HTTP ${response.statusCode}`);
|
|
90
|
+
return {
|
|
91
|
+
status: "success",
|
|
92
|
+
data: response.body
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
shutdown() {}
|
|
96
|
+
}));
|
|
97
|
+
let shutdown;
|
|
98
|
+
return {
|
|
99
|
+
export: (records, callback) => {
|
|
100
|
+
exporter.export(records, callback);
|
|
101
|
+
},
|
|
102
|
+
forceFlush: () => exporter.forceFlush(),
|
|
103
|
+
shutdown() {
|
|
104
|
+
shutdown ??= (async () => {
|
|
105
|
+
try {
|
|
106
|
+
await exporter.shutdown();
|
|
107
|
+
} finally {
|
|
108
|
+
(await agent)?.destroy();
|
|
109
|
+
}
|
|
110
|
+
})();
|
|
111
|
+
return shutdown;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region lib/types/event-log.js
|
|
117
|
+
/** One caller-owned ordinary-event queue, independent of every Session-log queue. */
|
|
118
|
+
var EventLogReporter = class {
|
|
119
|
+
exporter;
|
|
120
|
+
provider;
|
|
121
|
+
logger;
|
|
122
|
+
cancellation = new AbortController();
|
|
123
|
+
/** @param options - explicit transport, resource, scope, queue, and diagnostic settings. */
|
|
124
|
+
constructor(options) {
|
|
125
|
+
const exporter = createEventLogExporter(options.exporter, this.cancellation.signal);
|
|
126
|
+
this.exporter = exporter;
|
|
127
|
+
this.provider = new LoggerProvider({
|
|
128
|
+
resource: resourceFromAttributes(options.resourceAttributes),
|
|
129
|
+
processors: [new BatchLogRecordProcessor({
|
|
130
|
+
...options.processor,
|
|
131
|
+
exporter: {
|
|
132
|
+
export: (records, callback) => {
|
|
133
|
+
exporter.export(records, (result) => {
|
|
134
|
+
if (result.code !== ExportResultCode.SUCCESS) options.onFailure("Product telemetry export failed", result.error);
|
|
135
|
+
callback(result);
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
forceFlush: () => exporter.forceFlush(),
|
|
139
|
+
shutdown: () => exporter.shutdown()
|
|
140
|
+
}
|
|
141
|
+
})]
|
|
142
|
+
});
|
|
143
|
+
this.logger = this.provider.getLogger(options.scope.name, options.scope.version);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Enqueue caller-selected analytics fields without acknowledging delivery.
|
|
147
|
+
* @param record - the ordinary event to report.
|
|
148
|
+
*/
|
|
149
|
+
emit(record) {
|
|
150
|
+
const severityNumber = record.severityNumber ?? SeverityNumber.INFO;
|
|
151
|
+
this.logger.emit({
|
|
152
|
+
...record,
|
|
153
|
+
observedTimestamp: Date.now(),
|
|
154
|
+
severityNumber,
|
|
155
|
+
severityText: SeverityNumber[severityNumber]
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Drain the queue and release its transport, cancelling remaining exports when the caller aborts.
|
|
160
|
+
* @param signal - optional shutdown deadline; abort discards pending exports and cancels retry waits.
|
|
161
|
+
* @returns completion of SDK shutdown and transport cleanup.
|
|
162
|
+
*/
|
|
163
|
+
async shutdown(signal) {
|
|
164
|
+
const abort = () => {
|
|
165
|
+
this.cancellation.abort(signal?.reason);
|
|
166
|
+
};
|
|
167
|
+
const listener = signal === void 0 ? void 0 : addAbortListener(signal, abort);
|
|
168
|
+
if (signal?.aborted) abort();
|
|
169
|
+
try {
|
|
170
|
+
await this.provider.shutdown();
|
|
171
|
+
} finally {
|
|
172
|
+
try {
|
|
173
|
+
await this.exporter.shutdown();
|
|
174
|
+
} finally {
|
|
175
|
+
listener?.[Symbol.dispose]();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region lib/types/session-log.js
|
|
182
|
+
/** Collector request ceiling in uncompressed UTF-8 bytes, including the OTLP envelope. */
|
|
183
|
+
const SESSION_LOG_MAX_REQUEST_BYTES = 4e6;
|
|
184
|
+
/**
|
|
185
|
+
* Validate byte and queue settings before constructing an SDK pipeline.
|
|
186
|
+
* @param options - Session-specific limits supplied by the owning composition.
|
|
187
|
+
* @returns the resolved collector request limit.
|
|
188
|
+
*/
|
|
189
|
+
function resolveSessionLogLimits(options) {
|
|
190
|
+
const limit = options.maxRequestBytes ?? 4e6;
|
|
191
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 4e6) throw new Error(`session log maxRequestBytes must be an integer between 1 and ${SESSION_LOG_MAX_REQUEST_BYTES}`);
|
|
192
|
+
for (const key of [
|
|
193
|
+
"maxQueueSize",
|
|
194
|
+
"maxExportBatchSize",
|
|
195
|
+
"scheduledDelayMillis",
|
|
196
|
+
"exportTimeoutMillis"
|
|
197
|
+
]) {
|
|
198
|
+
const value = options.processor?.[key];
|
|
199
|
+
if (value !== void 0 && (!Number.isSafeInteger(value) || value < 1 || value > 2147483647)) throw new Error(`session log processor.${key} must be a positive integer no greater than 2147483647`);
|
|
200
|
+
}
|
|
201
|
+
const queue = options.processor?.maxQueueSize ?? 2048;
|
|
202
|
+
if ((options.processor?.maxExportBatchSize ?? 512) > queue) throw new Error("session log maxExportBatchSize must not exceed maxQueueSize");
|
|
203
|
+
return limit;
|
|
204
|
+
}
|
|
205
|
+
/** Byte/count batching with one transport request in flight, including after a watchdog warning. */
|
|
206
|
+
var SessionLogProcessor = class {
|
|
207
|
+
exporter;
|
|
208
|
+
limit;
|
|
209
|
+
config;
|
|
210
|
+
warn;
|
|
211
|
+
queue = [];
|
|
212
|
+
bytes = 0;
|
|
213
|
+
timer;
|
|
214
|
+
active;
|
|
215
|
+
shutdownPromise;
|
|
216
|
+
stopped = false;
|
|
217
|
+
constructor(exporter, limit, config, warn) {
|
|
218
|
+
this.exporter = exporter;
|
|
219
|
+
this.limit = limit;
|
|
220
|
+
this.config = config;
|
|
221
|
+
this.warn = warn;
|
|
222
|
+
}
|
|
223
|
+
onEmit(record) {
|
|
224
|
+
if (this.stopped) return;
|
|
225
|
+
if (this.queue.length >= this.config.maxQueueSize) {
|
|
226
|
+
this.warn("Session log queue is full; record rejected");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
let bytes;
|
|
230
|
+
try {
|
|
231
|
+
const serialized = JsonLogsSerializer.serializeRequest([record]);
|
|
232
|
+
if (serialized === void 0) throw new Error("Session log serialization produced no request");
|
|
233
|
+
bytes = serialized.byteLength;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
this.warn("Session log serialization failed; record rejected", error instanceof Error ? error : new Error(String(error)));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (bytes > this.limit) {
|
|
239
|
+
this.warn("Session log record rejected; content was not truncated", /* @__PURE__ */ new Error(`Session log record exceeds maxRequestBytes: ${bytes} > ${this.limit}`));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this.queue.push({
|
|
243
|
+
record,
|
|
244
|
+
bytes
|
|
245
|
+
});
|
|
246
|
+
this.bytes += bytes;
|
|
247
|
+
if (this.active !== void 0) return;
|
|
248
|
+
if (this.queue.length >= this.config.maxExportBatchSize || this.bytes >= this.limit) this.forceFlush();
|
|
249
|
+
else if (this.timer === void 0) {
|
|
250
|
+
this.timer = setTimeout(() => {
|
|
251
|
+
this.forceFlush();
|
|
252
|
+
}, this.config.scheduledDelayMillis);
|
|
253
|
+
this.timer.unref();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
forceFlush() {
|
|
257
|
+
clearTimeout(this.timer);
|
|
258
|
+
this.timer = void 0;
|
|
259
|
+
if (this.active !== void 0) return this.active;
|
|
260
|
+
if (this.queue.length === 0) return Promise.resolve();
|
|
261
|
+
this.active = this.drain();
|
|
262
|
+
return this.active;
|
|
263
|
+
}
|
|
264
|
+
async drain() {
|
|
265
|
+
try {
|
|
266
|
+
while (!this.stopped && this.queue.length > 0) {
|
|
267
|
+
let bytes = 0;
|
|
268
|
+
let count = 0;
|
|
269
|
+
for (const entry of this.queue) {
|
|
270
|
+
if (count === this.config.maxExportBatchSize || bytes + entry.bytes > this.limit) break;
|
|
271
|
+
bytes += entry.bytes;
|
|
272
|
+
count++;
|
|
273
|
+
}
|
|
274
|
+
const records = this.queue.splice(0, count).map((entry) => entry.record);
|
|
275
|
+
this.bytes -= bytes;
|
|
276
|
+
await this.send(records);
|
|
277
|
+
await this.exporter.forceFlush();
|
|
278
|
+
}
|
|
279
|
+
} finally {
|
|
280
|
+
this.active = void 0;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
send(records) {
|
|
284
|
+
return new Promise((resolve) => {
|
|
285
|
+
const timer = setTimeout(() => {
|
|
286
|
+
this.warn("Session log request exceeded exportTimeoutMillis; waiting for transport settlement");
|
|
287
|
+
}, this.config.exportTimeoutMillis);
|
|
288
|
+
timer.unref();
|
|
289
|
+
const finish = (error) => {
|
|
290
|
+
clearTimeout(timer);
|
|
291
|
+
if (error !== void 0) this.warn("Session log export failed", error);
|
|
292
|
+
resolve();
|
|
293
|
+
};
|
|
294
|
+
try {
|
|
295
|
+
this.exporter.export(records, (result) => {
|
|
296
|
+
finish(result.code === ExportResultCode.SUCCESS ? void 0 : result.error ?? /* @__PURE__ */ new Error("Session log HTTP export failed"));
|
|
297
|
+
});
|
|
298
|
+
} catch (error) {
|
|
299
|
+
finish(error instanceof Error ? error : new Error(String(error)));
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
stopPending() {
|
|
304
|
+
this.stopped = true;
|
|
305
|
+
this.queue.length = 0;
|
|
306
|
+
this.bytes = 0;
|
|
307
|
+
clearTimeout(this.timer);
|
|
308
|
+
this.timer = void 0;
|
|
309
|
+
}
|
|
310
|
+
shutdown() {
|
|
311
|
+
this.shutdownPromise ??= this.forceFlush().then(() => this.exporter.shutdown());
|
|
312
|
+
return this.shutdownPromise;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
/** Owns feedback-authorized Session logs; no product-event provider or queue is mounted. */
|
|
316
|
+
var SessionLogReporter = class {
|
|
317
|
+
provider;
|
|
318
|
+
processor;
|
|
319
|
+
logger;
|
|
320
|
+
/** @param options - explicit transport, resource identity, queue limits, and diagnostics. */
|
|
321
|
+
constructor(options) {
|
|
322
|
+
const limit = resolveSessionLogLimits(options);
|
|
323
|
+
this.processor = new SessionLogProcessor(createLogExporter(options.exporter), limit, {
|
|
324
|
+
maxQueueSize: options.processor?.maxQueueSize ?? 2048,
|
|
325
|
+
maxExportBatchSize: options.processor?.maxExportBatchSize ?? 512,
|
|
326
|
+
scheduledDelayMillis: options.processor?.scheduledDelayMillis ?? 1e3,
|
|
327
|
+
exportTimeoutMillis: options.processor?.exportTimeoutMillis ?? 3e4
|
|
328
|
+
}, options.onFailure);
|
|
329
|
+
this.provider = new LoggerProvider({
|
|
330
|
+
logRecordLimits: {
|
|
331
|
+
attributeValueLengthLimit: Infinity,
|
|
332
|
+
attributeCountLimit: Infinity
|
|
333
|
+
},
|
|
334
|
+
resource: resourceFromAttributes(options.resourceAttributes),
|
|
335
|
+
processors: [this.processor]
|
|
336
|
+
});
|
|
337
|
+
this.logger = this.provider.getLogger(options.scope.name, options.scope.version);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Enqueue one complete event without acknowledging network delivery.
|
|
341
|
+
* @param record - event with redacted data and its original Session id.
|
|
342
|
+
*/
|
|
343
|
+
reportSessionLog(record) {
|
|
344
|
+
const severityNumber = record.severityNumber ?? SeverityNumber.INFO;
|
|
345
|
+
this.logger.emit({
|
|
346
|
+
eventName: "session-log",
|
|
347
|
+
body: "session-log",
|
|
348
|
+
timestamp: record.event.time,
|
|
349
|
+
observedTimestamp: record.event.time,
|
|
350
|
+
severityNumber,
|
|
351
|
+
severityText: SeverityNumber[severityNumber],
|
|
352
|
+
attributes: {
|
|
353
|
+
...record.attributes,
|
|
354
|
+
sessionId: record.sessionId,
|
|
355
|
+
content: JSON.stringify(record.event)
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
/** Stop queued requests after the owning backend's shutdown deadline; an active transport may still settle. */
|
|
360
|
+
stopPending() {
|
|
361
|
+
this.processor.stopPending();
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Drain queued requests and release the SDK transport.
|
|
365
|
+
* @returns completion after queued requests settle and the SDK transport shuts down.
|
|
366
|
+
*/
|
|
367
|
+
shutdown() {
|
|
368
|
+
return this.provider.shutdown();
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region lib/types/index.js
|
|
373
|
+
/** Cordis entry for independent ordinary-event and Session-log OTLP channels. */
|
|
374
|
+
/** Shared transport provider. Mounting creates no queue, identity, or network connection. */
|
|
375
|
+
var OTel = class extends Service {
|
|
376
|
+
constructor(ctx) {
|
|
377
|
+
super(ctx, "otel");
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Create an independent ordinary-event channel with count-based batching.
|
|
381
|
+
* The injected consumer must drain it during its fiber disposal.
|
|
382
|
+
* @param options - transport, scope, resource, queue, and diagnostic settings selected by the consumer.
|
|
383
|
+
* @returns the caller-owned channel; no state is shared with other channels.
|
|
384
|
+
*/
|
|
385
|
+
createEventReporter(options) {
|
|
386
|
+
return new EventLogReporter(options);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Create an independent byte-bounded Session-log channel.
|
|
390
|
+
* Authorization and redaction precede reporting; the consumer owns shutdown and its outer deadline.
|
|
391
|
+
* @param options - transport, scope, resource, queue, and diagnostic settings selected by the consumer.
|
|
392
|
+
* @returns the caller-owned channel, preserving complete accepted events within the request byte ceiling.
|
|
393
|
+
*/
|
|
394
|
+
createSessionLogReporter(options) {
|
|
395
|
+
return new SessionLogReporter(options);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
//#endregion
|
|
399
|
+
export { OTel as default };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Ordinary event SDK batching over a cancellable HTTP transport. */
|
|
2
|
+
import type { Attributes } from '@opentelemetry/api';
|
|
3
|
+
import { SeverityNumber } from '@opentelemetry/api-logs';
|
|
4
|
+
import type { BatchLogRecordProcessorOptions } from '@opentelemetry/sdk-logs';
|
|
5
|
+
import type { SessionLogOptions } from './session-log.ts';
|
|
6
|
+
/** Scalar values accepted by the collector's Arrow attributes map. */
|
|
7
|
+
export type OTelEventScalar = string | number | boolean;
|
|
8
|
+
/** Explicitly selected analytics fields; object values may contain scalars only. */
|
|
9
|
+
export interface OTelEventRecord {
|
|
10
|
+
/** Product/DA-owned event name. */
|
|
11
|
+
eventName: string;
|
|
12
|
+
/** Human-readable summary; never a prompt, response, credential, or file contents. */
|
|
13
|
+
body: string;
|
|
14
|
+
/** Event occurrence time in Unix milliseconds. Observation time is assigned on enqueue. */
|
|
15
|
+
timestamp: number;
|
|
16
|
+
/** OTel severity; omitted values use INFO. */
|
|
17
|
+
severityNumber?: SeverityNumber;
|
|
18
|
+
/** Business fields selected by the caller; no automatic device or account identity. */
|
|
19
|
+
attributes?: Record<string, OTelEventScalar | Record<string, OTelEventScalar>>;
|
|
20
|
+
}
|
|
21
|
+
/** Ordinary-event transport, resource, scope, and count-batching options. */
|
|
22
|
+
export interface EventLogOptions {
|
|
23
|
+
exporter: SessionLogOptions['exporter'];
|
|
24
|
+
resourceAttributes: Attributes;
|
|
25
|
+
scope: {
|
|
26
|
+
name: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
};
|
|
29
|
+
processor: Omit<BatchLogRecordProcessorOptions, 'exporter'>;
|
|
30
|
+
onFailure: SessionLogOptions['onFailure'];
|
|
31
|
+
}
|
|
32
|
+
/** One caller-owned ordinary-event queue, independent of every Session-log queue. */
|
|
33
|
+
export declare class EventLogReporter {
|
|
34
|
+
private readonly exporter;
|
|
35
|
+
private readonly provider;
|
|
36
|
+
private readonly logger;
|
|
37
|
+
private readonly cancellation;
|
|
38
|
+
/** @param options - explicit transport, resource, scope, queue, and diagnostic settings. */
|
|
39
|
+
constructor(options: EventLogOptions);
|
|
40
|
+
/**
|
|
41
|
+
* Enqueue caller-selected analytics fields without acknowledging delivery.
|
|
42
|
+
* @param record - the ordinary event to report.
|
|
43
|
+
*/
|
|
44
|
+
emit(record: OTelEventRecord): void;
|
|
45
|
+
/**
|
|
46
|
+
* Drain the queue and release its transport, cancelling remaining exports when the caller aborts.
|
|
47
|
+
* @param signal - optional shutdown deadline; abort discards pending exports and cancels retry waits.
|
|
48
|
+
* @returns completion of SDK shutdown and transport cleanup.
|
|
49
|
+
*/
|
|
50
|
+
shutdown(signal?: AbortSignal): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=event-log.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
|
|
2
|
+
import type { LogRecordExporter } from '@opentelemetry/sdk-logs';
|
|
3
|
+
/**
|
|
4
|
+
* Create a channel-owned exporter whose cancellation releases requests and retry timers.
|
|
5
|
+
* @param options - explicit collector and SDK HTTP settings.
|
|
6
|
+
* @param signal - channel cancellation, shared by current and future batch exports.
|
|
7
|
+
* @returns the SDK exporter; shutdown also destroys its owned HTTP agent.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createEventLogExporter(options: OTLPExporterNodeConfigBase & {
|
|
10
|
+
url: string;
|
|
11
|
+
}, signal: AbortSignal): LogRecordExporter;
|
|
12
|
+
//# sourceMappingURL=event-transport.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Cordis entry for independent ordinary-event and Session-log OTLP channels. */
|
|
2
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
3
|
+
import { EventLogReporter, type EventLogOptions } from './event-log.ts';
|
|
4
|
+
import { SessionLogReporter, type SessionLogOptions } from './session-log.ts';
|
|
5
|
+
declare module '@deepseek-ai/cordis' {
|
|
6
|
+
interface Context {
|
|
7
|
+
otel: OTel;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** Shared transport provider. Mounting creates no queue, identity, or network connection. */
|
|
11
|
+
export default class OTel extends Service {
|
|
12
|
+
constructor(ctx: Context);
|
|
13
|
+
/**
|
|
14
|
+
* Create an independent ordinary-event channel with count-based batching.
|
|
15
|
+
* The injected consumer must drain it during its fiber disposal.
|
|
16
|
+
* @param options - transport, scope, resource, queue, and diagnostic settings selected by the consumer.
|
|
17
|
+
* @returns the caller-owned channel; no state is shared with other channels.
|
|
18
|
+
*/
|
|
19
|
+
createEventReporter(options: EventLogOptions): EventLogReporter;
|
|
20
|
+
/**
|
|
21
|
+
* Create an independent byte-bounded Session-log channel.
|
|
22
|
+
* Authorization and redaction precede reporting; the consumer owns shutdown and its outer deadline.
|
|
23
|
+
* @param options - transport, scope, resource, queue, and diagnostic settings selected by the consumer.
|
|
24
|
+
* @returns the caller-owned channel, preserving complete accepted events within the request byte ceiling.
|
|
25
|
+
*/
|
|
26
|
+
createSessionLogReporter(options: SessionLogOptions): SessionLogReporter;
|
|
27
|
+
}
|
|
28
|
+
export type { EventLogOptions, OTelEventRecord, OTelEventScalar, EventLogReporter } from './event-log.ts';
|
|
29
|
+
export type { SessionLogRecord, SessionLogOptions, SessionLogReporter } from './session-log.ts';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** Session-log records in an independent byte-bounded OTLP queue. */
|
|
2
|
+
import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session';
|
|
3
|
+
import type { Attributes } from '@opentelemetry/api';
|
|
4
|
+
import { SeverityNumber } from '@opentelemetry/api-logs';
|
|
5
|
+
import type { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
|
|
6
|
+
import { type BatchLogRecordProcessorOptions } from '@opentelemetry/sdk-logs';
|
|
7
|
+
/** Collector request ceiling in uncompressed UTF-8 bytes, including the OTLP envelope. */
|
|
8
|
+
export declare const SESSION_LOG_MAX_REQUEST_BYTES = 4000000;
|
|
9
|
+
/** One canonical event with its separately owned Session identity and redacted payload. */
|
|
10
|
+
export interface SessionLogRecord {
|
|
11
|
+
sessionId: SessionId;
|
|
12
|
+
/** Complete event envelope; data is the capture policy's exported copy. */
|
|
13
|
+
event: Omit<SessionEvent, 'data'> & {
|
|
14
|
+
data: unknown;
|
|
15
|
+
};
|
|
16
|
+
/** Additional capture metadata; sessionId and content are always assigned by the reporter. */
|
|
17
|
+
attributes?: Attributes;
|
|
18
|
+
/** Omitted values use INFO. */
|
|
19
|
+
severityNumber?: SeverityNumber;
|
|
20
|
+
}
|
|
21
|
+
/** Session-log transport and byte/count queue settings. */
|
|
22
|
+
export interface SessionLogOptions {
|
|
23
|
+
/** Explicit destination and SDK transport options. */
|
|
24
|
+
exporter: OTLPExporterNodeConfigBase & {
|
|
25
|
+
/** Full HTTP(S) logs destination. */
|
|
26
|
+
url: string;
|
|
27
|
+
};
|
|
28
|
+
/** Session-only queue settings, independent of product-event aggregation. */
|
|
29
|
+
processor?: Omit<BatchLogRecordProcessorOptions, 'exporter'>;
|
|
30
|
+
/** May lower, but never exceed, the collector's 4,000,000-byte limit. */
|
|
31
|
+
maxRequestBytes?: number;
|
|
32
|
+
/** Instrumentation scope supplied by the business owner. */
|
|
33
|
+
scope: {
|
|
34
|
+
name: string;
|
|
35
|
+
version?: string;
|
|
36
|
+
};
|
|
37
|
+
/** Application and anonymous identity carried on the OTLP resource. */
|
|
38
|
+
resourceAttributes: Attributes;
|
|
39
|
+
/** Report rejected single records and network failures without recording their content. */
|
|
40
|
+
onFailure: (message: string, error?: Error) => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Validate byte and queue settings before constructing an SDK pipeline.
|
|
44
|
+
* @param options - Session-specific limits supplied by the owning composition.
|
|
45
|
+
* @returns the resolved collector request limit.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveSessionLogLimits(options: Pick<SessionLogOptions, 'maxRequestBytes' | 'processor'>): number;
|
|
48
|
+
/** Owns feedback-authorized Session logs; no product-event provider or queue is mounted. */
|
|
49
|
+
export declare class SessionLogReporter {
|
|
50
|
+
private readonly provider;
|
|
51
|
+
private readonly processor;
|
|
52
|
+
private readonly logger;
|
|
53
|
+
/** @param options - explicit transport, resource identity, queue limits, and diagnostics. */
|
|
54
|
+
constructor(options: SessionLogOptions);
|
|
55
|
+
/**
|
|
56
|
+
* Enqueue one complete event without acknowledging network delivery.
|
|
57
|
+
* @param record - event with redacted data and its original Session id.
|
|
58
|
+
*/
|
|
59
|
+
reportSessionLog(record: SessionLogRecord): void;
|
|
60
|
+
/** Stop queued requests after the owning backend's shutdown deadline; an active transport may still settle. */
|
|
61
|
+
stopPending(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Drain queued requests and release the SDK transport.
|
|
64
|
+
* @returns completion after queued requests settle and the SDK transport shuts down.
|
|
65
|
+
*/
|
|
66
|
+
shutdown(): Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=session-log.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Explicit OTLP JSON transport for feedback-authorized Session logs. */
|
|
2
|
+
import { createOtlpHttpExportDelegate } from '@opentelemetry/otlp-exporter-base/node-http';
|
|
3
|
+
import { type OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
|
|
4
|
+
import type { LogRecordExporter } from '@opentelemetry/sdk-logs';
|
|
5
|
+
/**
|
|
6
|
+
* Create an SDK JSON exporter without inheriting another collector's headers or TLS identity.
|
|
7
|
+
* @param options - explicit endpoint, headers, agent, and SDK transport settings.
|
|
8
|
+
* @returns the exporter owned by one independent log pipeline.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createLogExporter(options: OTLPExporterNodeConfigBase & {
|
|
11
|
+
url: string;
|
|
12
|
+
}): LogRecordExporter;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve collector-local headers and agents with shared SDK timeout and compression defaults.
|
|
15
|
+
* @param options - explicit endpoint and SDK HTTP settings.
|
|
16
|
+
* @returns resolved transport settings without ambient credentials.
|
|
17
|
+
*/
|
|
18
|
+
export declare function logTransportOptions(options: OTLPExporterNodeConfigBase & {
|
|
19
|
+
url: string;
|
|
20
|
+
}): Parameters<typeof createOtlpHttpExportDelegate>[0];
|
|
21
|
+
//# sourceMappingURL=transport.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepseek-ai/dsh-otel",
|
|
3
|
+
"description": "Cordis service for independent ordinary-event and byte-bounded Session-log OTLP channels",
|
|
4
|
+
"version": "0.2.0-rc.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/telemetry/otel"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./src/*": "./src/*",
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"lib/index.js",
|
|
26
|
+
"lib/types/**/*.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@opentelemetry/api": "^1.9.1",
|
|
31
|
+
"@opentelemetry/api-logs": "^0.220.0",
|
|
32
|
+
"@opentelemetry/otlp-exporter-base": "^0.220.0",
|
|
33
|
+
"@opentelemetry/resources": "^2.9.0",
|
|
34
|
+
"@opentelemetry/sdk-logs": "^0.220.0",
|
|
35
|
+
"@opentelemetry/core": "2.9.0",
|
|
36
|
+
"@opentelemetry/otlp-transformer": "^0.220.0",
|
|
37
|
+
"got": "^14.6.6"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
41
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
45
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.1"
|
|
46
|
+
}
|
|
47
|
+
}
|