@cnpinsight/cnpclawinsights 2.0.1 → 2.0.2
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/README.md +63 -0
- package/dist/cli.mjs +206 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -20,6 +20,69 @@ openclaw plugins install @cnpinsight/cnpclawinsights
|
|
|
20
20
|
openclaw plugins install @cnpinsight/cnpclawinsights@2.0.0
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## 安装器
|
|
24
|
+
|
|
25
|
+
如果你不想手动编辑 `openclaw.json`,可以使用安装器命令自动写入插件配置。
|
|
26
|
+
|
|
27
|
+
最简单的方式:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm exec -y --package=@cnpinsight/cnpclawinsights -- \
|
|
31
|
+
cnpclawinsights-install \
|
|
32
|
+
--non-interactive
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
这会自动把配置写入默认的 `~/.openclaw/openclaw.json`,并生成:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"plugins": {
|
|
40
|
+
"entries": {
|
|
41
|
+
"cnpclawinsights": {
|
|
42
|
+
"enabled": true,
|
|
43
|
+
"config": {
|
|
44
|
+
"otel": {
|
|
45
|
+
"endpoint": "http://127.0.0.1:4318"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
指定 endpoint 并开启 logs:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm exec -y --package=@cnpinsight/cnpclawinsights -- \
|
|
58
|
+
cnpclawinsights-install \
|
|
59
|
+
--non-interactive \
|
|
60
|
+
--endpoint http://127.0.0.1:4318 \
|
|
61
|
+
--logs
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
指定 service name 和 header:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm exec -y --package=@cnpinsight/cnpclawinsights -- \
|
|
68
|
+
cnpclawinsights-install \
|
|
69
|
+
--non-interactive \
|
|
70
|
+
--service-name openclaw \
|
|
71
|
+
--header Authorization="Bearer <token>"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
安装器支持的主要参数:
|
|
75
|
+
|
|
76
|
+
- `--config-path <path>`:指定 `openclaw.json` 路径
|
|
77
|
+
- `--endpoint <url>`:设置 OTLP endpoint
|
|
78
|
+
- `--service-name <name>`:设置 OTel service name
|
|
79
|
+
- `--logs` / `--no-logs`:开启或关闭 logs 导出
|
|
80
|
+
- `--traces` / `--no-traces`:开启或关闭 traces 导出
|
|
81
|
+
- `--metrics` / `--no-metrics`:开启或关闭 metrics 导出
|
|
82
|
+
- `--sample-rate <0..1>`:设置 trace 采样率
|
|
83
|
+
- `--flush-interval-ms <ms>`:设置导出刷新间隔
|
|
84
|
+
- `--header <k=v>`:追加请求头,可重复传入
|
|
85
|
+
|
|
23
86
|
## 最小配置
|
|
24
87
|
|
|
25
88
|
在 `openclaw.json` 中添加:
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
const PLUGIN_ID = "cnpclawinsights";
|
|
8
|
+
const LEGACY_PLUGIN_ID = "cnpclawinsight";
|
|
9
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), ".openclaw", "openclaw.json");
|
|
10
|
+
const DEFAULT_ENDPOINT = "http://127.0.0.1:4318";
|
|
11
|
+
|
|
12
|
+
function printHelp() {
|
|
13
|
+
console.log(`Usage:
|
|
14
|
+
cnpclawinsights-install [options]
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
--config-path <path> Path to openclaw.json
|
|
18
|
+
--endpoint <url> OTLP endpoint, default: ${DEFAULT_ENDPOINT}
|
|
19
|
+
--service-name <name> OpenTelemetry service name
|
|
20
|
+
--logs Enable logs export
|
|
21
|
+
--no-logs Disable logs export
|
|
22
|
+
--traces Enable traces export
|
|
23
|
+
--no-traces Disable traces export
|
|
24
|
+
--metrics Enable metrics export
|
|
25
|
+
--no-metrics Disable metrics export
|
|
26
|
+
--sample-rate <0..1> Trace sampling rate
|
|
27
|
+
--flush-interval-ms <ms> Export flush interval
|
|
28
|
+
--header <k=v> Add OTLP header, repeatable
|
|
29
|
+
--non-interactive Run without prompts
|
|
30
|
+
--help Show this help
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function fail(message) {
|
|
35
|
+
console.error(`cnpclawinsights-install: ${message}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseArgs(argv) {
|
|
40
|
+
const options = {
|
|
41
|
+
configPath: DEFAULT_CONFIG_PATH,
|
|
42
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
43
|
+
headers: {}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
47
|
+
const arg = argv[i];
|
|
48
|
+
switch (arg) {
|
|
49
|
+
case "--config-path":
|
|
50
|
+
options.configPath = argv[++i];
|
|
51
|
+
break;
|
|
52
|
+
case "--endpoint":
|
|
53
|
+
options.endpoint = argv[++i];
|
|
54
|
+
break;
|
|
55
|
+
case "--service-name":
|
|
56
|
+
options.serviceName = argv[++i];
|
|
57
|
+
break;
|
|
58
|
+
case "--logs":
|
|
59
|
+
options.logs = true;
|
|
60
|
+
break;
|
|
61
|
+
case "--no-logs":
|
|
62
|
+
options.logs = false;
|
|
63
|
+
break;
|
|
64
|
+
case "--traces":
|
|
65
|
+
options.traces = true;
|
|
66
|
+
break;
|
|
67
|
+
case "--no-traces":
|
|
68
|
+
options.traces = false;
|
|
69
|
+
break;
|
|
70
|
+
case "--metrics":
|
|
71
|
+
options.metrics = true;
|
|
72
|
+
break;
|
|
73
|
+
case "--no-metrics":
|
|
74
|
+
options.metrics = false;
|
|
75
|
+
break;
|
|
76
|
+
case "--sample-rate":
|
|
77
|
+
options.sampleRate = Number(argv[++i]);
|
|
78
|
+
break;
|
|
79
|
+
case "--flush-interval-ms":
|
|
80
|
+
options.flushIntervalMs = Number(argv[++i]);
|
|
81
|
+
break;
|
|
82
|
+
case "--header": {
|
|
83
|
+
const raw = argv[++i];
|
|
84
|
+
const eqIndex = raw.indexOf("=");
|
|
85
|
+
if (eqIndex <= 0) fail(`invalid --header value: ${raw}`);
|
|
86
|
+
const key = raw.slice(0, eqIndex).trim();
|
|
87
|
+
const value = raw.slice(eqIndex + 1).trim();
|
|
88
|
+
if (!key || !value) fail(`invalid --header value: ${raw}`);
|
|
89
|
+
options.headers[key] = value;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "--non-interactive":
|
|
93
|
+
options.nonInteractive = true;
|
|
94
|
+
break;
|
|
95
|
+
case "--help":
|
|
96
|
+
case "-h":
|
|
97
|
+
options.help = true;
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
fail(`unknown argument: ${arg}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return options;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function ensureParentDir(filePath) {
|
|
108
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function readConfig(configPath) {
|
|
112
|
+
if (!fs.existsSync(configPath)) {
|
|
113
|
+
return {};
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
117
|
+
} catch (error) {
|
|
118
|
+
fail(`failed to parse config file ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function normalizePluginEntry(entries) {
|
|
123
|
+
const pluralEntry = entries[PLUGIN_ID];
|
|
124
|
+
if (pluralEntry && typeof pluralEntry === "object") {
|
|
125
|
+
return pluralEntry;
|
|
126
|
+
}
|
|
127
|
+
const legacyEntry = entries[LEGACY_PLUGIN_ID];
|
|
128
|
+
if (legacyEntry && typeof legacyEntry === "object") {
|
|
129
|
+
delete entries[LEGACY_PLUGIN_ID];
|
|
130
|
+
entries[PLUGIN_ID] = legacyEntry;
|
|
131
|
+
return legacyEntry;
|
|
132
|
+
}
|
|
133
|
+
const entry = {};
|
|
134
|
+
entries[PLUGIN_ID] = entry;
|
|
135
|
+
return entry;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function buildPluginConfig(options) {
|
|
139
|
+
const otel = {
|
|
140
|
+
endpoint: options.endpoint
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
if (options.logs !== undefined) otel.logs = options.logs;
|
|
144
|
+
if (options.traces !== undefined) otel.traces = options.traces;
|
|
145
|
+
if (options.metrics !== undefined) otel.metrics = options.metrics;
|
|
146
|
+
if (options.serviceName) otel.serviceName = options.serviceName;
|
|
147
|
+
if (options.sampleRate !== undefined) otel.sampleRate = options.sampleRate;
|
|
148
|
+
if (options.flushIntervalMs !== undefined) otel.flushIntervalMs = options.flushIntervalMs;
|
|
149
|
+
if (Object.keys(options.headers).length > 0) otel.headers = options.headers;
|
|
150
|
+
|
|
151
|
+
return { otel };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function writeConfig(configPath, config) {
|
|
155
|
+
ensureParentDir(configPath);
|
|
156
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function main() {
|
|
160
|
+
const options = parseArgs(process.argv.slice(2));
|
|
161
|
+
if (options.help) {
|
|
162
|
+
printHelp();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (options.sampleRate !== undefined && (!Number.isFinite(options.sampleRate) || options.sampleRate < 0 || options.sampleRate > 1)) {
|
|
167
|
+
fail("--sample-rate must be a number between 0 and 1");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (options.flushIntervalMs !== undefined && (!Number.isInteger(options.flushIntervalMs) || options.flushIntervalMs < 1000)) {
|
|
171
|
+
fail("--flush-interval-ms must be an integer >= 1000");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const config = readConfig(options.configPath);
|
|
175
|
+
if (!config.plugins || typeof config.plugins !== "object" || Array.isArray(config.plugins)) {
|
|
176
|
+
config.plugins = {};
|
|
177
|
+
}
|
|
178
|
+
if (!config.plugins.entries || typeof config.plugins.entries !== "object" || Array.isArray(config.plugins.entries)) {
|
|
179
|
+
config.plugins.entries = {};
|
|
180
|
+
}
|
|
181
|
+
const entry = normalizePluginEntry(config.plugins.entries);
|
|
182
|
+
entry.enabled = true;
|
|
183
|
+
entry.config = {
|
|
184
|
+
...(entry.config && typeof entry.config === "object" && !Array.isArray(entry.config) ? entry.config : {}),
|
|
185
|
+
...buildPluginConfig(options)
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
if (!Array.isArray(config.plugins.allow)) {
|
|
189
|
+
config.plugins.allow = [];
|
|
190
|
+
}
|
|
191
|
+
if (!config.plugins.allow.includes(PLUGIN_ID)) {
|
|
192
|
+
config.plugins.allow.push(PLUGIN_ID);
|
|
193
|
+
}
|
|
194
|
+
config.plugins.allow = config.plugins.allow.filter((value, index, values) => value !== LEGACY_PLUGIN_ID || values.indexOf(PLUGIN_ID) === -1);
|
|
195
|
+
|
|
196
|
+
writeConfig(options.configPath, config);
|
|
197
|
+
|
|
198
|
+
console.log(`Updated ${options.configPath}`);
|
|
199
|
+
console.log(`Configured plugins.entries.${PLUGIN_ID}.enabled = true`);
|
|
200
|
+
console.log(`Configured plugins.entries.${PLUGIN_ID}.config.otel.endpoint = ${options.endpoint}`);
|
|
201
|
+
if (options.logs !== undefined) {
|
|
202
|
+
console.log(`Configured plugins.entries.${PLUGIN_ID}.config.otel.logs = ${String(options.logs)}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cnpinsight/cnpclawinsights",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "OpenClaw insights OpenTelemetry exporter",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/openclaw/openclaw"
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"cnpclawinsights-install": "dist/cli.mjs"
|
|
12
|
+
},
|
|
10
13
|
"dependencies": {
|
|
11
14
|
"@opentelemetry/api": "1.9.1",
|
|
12
15
|
"@opentelemetry/api-logs": "0.218.0",
|