rl-rockcli 0.0.7 → 0.0.8

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.
Files changed (74) hide show
  1. package/index.js +15 -5
  2. package/package.json +2 -2
  3. package/commands/log/core/constants.js +0 -237
  4. package/commands/log/core/display.js +0 -370
  5. package/commands/log/core/search.js +0 -330
  6. package/commands/log/core/tail.js +0 -216
  7. package/commands/log/core/utils.js +0 -424
  8. package/commands/log.js +0 -298
  9. package/commands/sandbox/core/log-bridge.js +0 -119
  10. package/commands/sandbox/core/replay/analyzer.js +0 -311
  11. package/commands/sandbox/core/replay/batch-orchestrator.js +0 -536
  12. package/commands/sandbox/core/replay/batch-task.js +0 -369
  13. package/commands/sandbox/core/replay/concurrent-display.js +0 -70
  14. package/commands/sandbox/core/replay/concurrent-orchestrator.js +0 -170
  15. package/commands/sandbox/core/replay/data-source.js +0 -86
  16. package/commands/sandbox/core/replay/display.js +0 -231
  17. package/commands/sandbox/core/replay/executor.js +0 -634
  18. package/commands/sandbox/core/replay/history-fetcher.js +0 -124
  19. package/commands/sandbox/core/replay/index.js +0 -338
  20. package/commands/sandbox/core/replay/loghouse-data-source.js +0 -177
  21. package/commands/sandbox/core/replay/pid-mapping.js +0 -26
  22. package/commands/sandbox/core/replay/request.js +0 -109
  23. package/commands/sandbox/core/replay/worker.js +0 -166
  24. package/commands/sandbox/core/session.js +0 -346
  25. package/commands/sandbox/log-bridge.js +0 -2
  26. package/commands/sandbox/ray.js +0 -2
  27. package/commands/sandbox/replay/analyzer.js +0 -311
  28. package/commands/sandbox/replay/batch-orchestrator.js +0 -536
  29. package/commands/sandbox/replay/batch-task.js +0 -369
  30. package/commands/sandbox/replay/concurrent-display.js +0 -70
  31. package/commands/sandbox/replay/concurrent-orchestrator.js +0 -170
  32. package/commands/sandbox/replay/display.js +0 -231
  33. package/commands/sandbox/replay/executor.js +0 -634
  34. package/commands/sandbox/replay/history-fetcher.js +0 -118
  35. package/commands/sandbox/replay/index.js +0 -338
  36. package/commands/sandbox/replay/pid-mapping.js +0 -26
  37. package/commands/sandbox/replay/request.js +0 -109
  38. package/commands/sandbox/replay/worker.js +0 -166
  39. package/commands/sandbox/replay.js +0 -2
  40. package/commands/sandbox/session.js +0 -2
  41. package/commands/sandbox-original.js +0 -1393
  42. package/commands/sandbox.js +0 -499
  43. package/help/help.json +0 -1071
  44. package/help/middleware.js +0 -71
  45. package/help/renderer.js +0 -800
  46. package/lib/plugin-context.js +0 -40
  47. package/sdks/sandbox/core/client.js +0 -845
  48. package/sdks/sandbox/core/config.js +0 -70
  49. package/sdks/sandbox/core/types.js +0 -74
  50. package/sdks/sandbox/httpLogger.js +0 -251
  51. package/sdks/sandbox/index.js +0 -9
  52. package/utils/asciiArt.js +0 -138
  53. package/utils/bun-compat.js +0 -59
  54. package/utils/ciPipelines.js +0 -138
  55. package/utils/cli.js +0 -17
  56. package/utils/command-router.js +0 -79
  57. package/utils/configManager.js +0 -503
  58. package/utils/dependency-resolver.js +0 -135
  59. package/utils/eagleeye_traceid.js +0 -151
  60. package/utils/envDetector.js +0 -78
  61. package/utils/execution_logger.js +0 -415
  62. package/utils/featureManager.js +0 -68
  63. package/utils/firstTimeTip.js +0 -44
  64. package/utils/hook-manager.js +0 -125
  65. package/utils/http-logger.js +0 -264
  66. package/utils/i18n.js +0 -139
  67. package/utils/image-progress.js +0 -159
  68. package/utils/logger.js +0 -154
  69. package/utils/plugin-loader.js +0 -124
  70. package/utils/plugin-manager.js +0 -348
  71. package/utils/ray_cli_wrapper.js +0 -746
  72. package/utils/sandbox-client.js +0 -419
  73. package/utils/terminal.js +0 -32
  74. package/utils/tips.js +0 -106
@@ -1,124 +0,0 @@
1
- 'use strict';
2
-
3
- const { ReplayDataSource } = require('./data-source');
4
- const { LoghouseDataSource } = require('./loghouse-data-source');
5
- const logger = require('../../../../utils/logger');
6
-
7
- // Default data source for internal environment
8
- const defaultDataSource = new LoghouseDataSource();
9
-
10
- /**
11
- * 历史获取器
12
- * 封装数据源调用逻辑,支持批量并发获取
13
- */
14
- class HistoryFetcher {
15
- /**
16
- * @param {ReplayDataSource} [dataSource] - 数据源实例(可选,默认使用 LoghouseDataSource)
17
- */
18
- constructor(dataSource = null) {
19
- this.dataSource = dataSource || defaultDataSource;
20
- }
21
-
22
- /**
23
- * 获取单个沙箱的历史
24
- * @param {string} sandboxId - 沙箱 ID
25
- * @param {Object} options - 选项
26
- * @param {string} options.cluster - 集群名称
27
- * @param {Array<string>} options.uris - URI 过滤器
28
- * @param {boolean} options.debug - 是否开启调试
29
- * @returns {Promise<Object>} - 历史数据
30
- */
31
- async fetch(sandboxId, options = {}) {
32
- const result = await this.dataSource.fetch(sandboxId, options);
33
- return result;
34
- }
35
-
36
- /**
37
- * 批量获取历史(并发控制)
38
- * @param {SandboxTask[]} tasks - 任务列表
39
- * @param {number} concurrency - 并发数
40
- * @param {Object} options - 选项
41
- * @param {boolean} options.quiet - 静默模式
42
- * @param {Function} options.onProgress - 进度回调
43
- * @returns {Promise<void>}
44
- */
45
- async fetchBatch(tasks, concurrency, options = {}) {
46
- const { quiet, onProgress } = options;
47
-
48
- // 过滤出需要获取历史的任务(没有预加载 requests 的)
49
- const tasksToFetch = tasks.filter(task => !task.hasRequests());
50
-
51
- if (tasksToFetch.length === 0) {
52
- if (!quiet) {
53
- logger.info('All sandboxes have pre-loaded requests, skipping history fetch.');
54
- }
55
- // 标记所有任务为 ready
56
- tasks.forEach(task => {
57
- if (task.hasRequests()) {
58
- task.status = 'ready';
59
- }
60
- });
61
- return;
62
- }
63
-
64
- if (!quiet) {
65
- logger.info(`Fetching history for ${tasksToFetch.length} sandboxes (concurrency: ${concurrency})...`);
66
- }
67
-
68
- // 创建任务队列
69
- const queue = [...tasksToFetch];
70
- let completed = 0;
71
-
72
- // Worker 函数
73
- const worker = async () => {
74
- while (queue.length > 0) {
75
- const task = queue.shift();
76
- if (!task) break;
77
-
78
- task.startHistoryFetch();
79
-
80
- try {
81
- const historyData = await this.fetch(task.sandboxId, {
82
- cluster: task.cluster,
83
- uris: task.uris
84
- });
85
-
86
- task.completeHistoryFetch(historyData);
87
- } catch (error) {
88
- task.failHistoryFetch(error);
89
- }
90
-
91
- completed++;
92
- onProgress?.(completed, tasksToFetch.length, task);
93
- }
94
- };
95
-
96
- // 启动并发 workers
97
- const workers = [];
98
- const actualConcurrency = Math.min(concurrency, tasksToFetch.length);
99
-
100
- for (let i = 0; i < actualConcurrency; i++) {
101
- workers.push(worker());
102
- }
103
-
104
- // 等待所有 workers 完成
105
- await Promise.allSettled(workers);
106
-
107
- // 标记预加载的任务为 ready
108
- tasks.forEach(task => {
109
- if (task.hasRequests() && task.status === 'pending') {
110
- task.status = 'ready';
111
- }
112
- });
113
-
114
- // 汇总结果
115
- const succeeded = tasks.filter(t => t.status === 'ready').length;
116
- const failed = tasks.filter(t => t.status === 'failed').length;
117
-
118
- if (!quiet) {
119
- logger.info(`History fetch completed: ${succeeded} succeeded, ${failed} failed.`);
120
- }
121
- }
122
- }
123
-
124
- module.exports = { HistoryFetcher };
@@ -1,338 +0,0 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
- const logger = require('../../../../utils/logger');
4
- const { RequestAnalyzer } = require('./analyzer');
5
- const { ReplayExecutor } = require('./executor');
6
- const {
7
- displayAnalysisSummary,
8
- displayResultsSummary,
9
- displayDryRunSummary
10
- } = require('./display');
11
- const { ConcurrentReplayOrchestrator } = require('./concurrent-orchestrator');
12
- const { displayConcurrentResultsSummary } = require('./concurrent-display');
13
- const { BatchReplayOrchestrator } = require('./batch-orchestrator');
14
- const { gracefulExit } = require('../../../../utils/execution_logger');
15
-
16
- /**
17
- * 从 stdin 读取数据
18
- * @returns {Promise<string>}
19
- */
20
- function readStdin() {
21
- return new Promise((resolve, reject) => {
22
- let data = '';
23
- process.stdin.setEncoding('utf8');
24
-
25
- process.stdin.on('data', (chunk) => {
26
- data += chunk;
27
- });
28
-
29
- process.stdin.on('end', () => {
30
- resolve(data);
31
- });
32
-
33
- process.stdin.on('error', (error) => {
34
- reject(new Error(`Error reading from stdin: ${error.message}`));
35
- });
36
- });
37
- }
38
-
39
- /**
40
- * 解析请求数据
41
- * @param {string} inputData - JSON 字符串
42
- * @returns {Object[]} 请求列表
43
- */
44
- function parseRequests(inputData) {
45
- let data;
46
- try {
47
- data = JSON.parse(inputData);
48
- } catch (parseError) {
49
- throw new Error(`Failed to parse JSON from stdin: ${parseError.message}`);
50
- }
51
-
52
- if (!data.requests || !Array.isArray(data.requests)) {
53
- throw new Error('Invalid input format: "requests" array is required');
54
- }
55
-
56
- return data.requests;
57
- }
58
-
59
- /**
60
- * 处理 replay 命令
61
- * @param {Object} argv - 命令行参数
62
- * @param {Object} client - SandboxClient 实例
63
- */
64
- async function handleSmartReplay(argv, client) {
65
- // 检查是否为批量模式
66
- if (argv.fromFile) {
67
- return handleBatchReplay(argv, client);
68
- }
69
-
70
- // 检查是否为目录模式
71
- if (argv.fromDir) {
72
- return handleDirectoryReplay(argv, client);
73
- }
74
-
75
- // 1. 读取并解析输入
76
- const inputData = await readStdin();
77
- const requests = parseRequests(inputData);
78
-
79
- if (requests.length === 0) {
80
- logger.info('No requests to replay');
81
- return;
82
- }
83
-
84
- // 2. 分析请求
85
- const analyzer = new RequestAnalyzer({
86
- mode: argv.mode || 'smart',
87
- filters: argv.filter || [],
88
- executeStop: argv.stop || false
89
- });
90
-
91
- const plan = analyzer.analyze(requests);
92
-
93
- // 3. 显示分析摘要
94
- displayAnalysisSummary(plan, {
95
- mode: argv.mode || 'smart',
96
- quiet: argv.quiet || false
97
- });
98
-
99
- // 4. 预演模式
100
- if (argv.dryRun) {
101
- displayDryRunSummary(plan);
102
- logger.info('Dry run completed - no requests were executed');
103
- return;
104
- }
105
-
106
- // 5. 检查是否有请求需要执行
107
- if (plan.executeCount === 0) {
108
- logger.info('No requests to execute after filtering');
109
- return;
110
- }
111
-
112
- // 6. 检查并发模式
113
- const concurrency = argv.concurrency || 1;
114
-
115
- if (concurrency > 1) {
116
- // === 并发回放路径 ===
117
- const orchestrator = new ConcurrentReplayOrchestrator({
118
- concurrency: concurrency,
119
- config: client.config,
120
- quiet: argv.quiet || false,
121
- logFile: argv.logFile || 'replay.log',
122
- failureStrategy: argv.failureStrategy || 'continue'
123
- });
124
-
125
- const result = await orchestrator.execute(plan, {
126
- timing: argv.timing || 'none',
127
- interval: argv.interval || 5,
128
- quiet: argv.quiet || false,
129
- logFile: argv.logFile || 'replay.log'
130
- });
131
-
132
- // 显示并发结果摘要
133
- displayConcurrentResultsSummary(result, {
134
- quiet: argv.quiet || false
135
- });
136
-
137
- // 设置退出码
138
- if (!result.allSucceeded || result.aggregated.failed > 0) {
139
- process.exitCode = 1;
140
- }
141
-
142
- } else {
143
- // === 原有单沙箱回放路径 ===
144
- const executor = new ReplayExecutor(client, {
145
- timing: argv.timing || 'none',
146
- interval: argv.interval || 5,
147
- quiet: argv.quiet || false,
148
- logFile: argv.logFile || 'replay.log',
149
- verboseLog: argv.verboseLog || false,
150
- plan: plan
151
- });
152
-
153
- const results = await executor.execute(plan);
154
-
155
- // 显示结果摘要
156
- displayResultsSummary(results, [], {
157
- quiet: argv.quiet || false,
158
- logFile: argv.logFile || 'replay.log',
159
- sandboxId: executor.currentSandboxId
160
- });
161
-
162
- // 如果有失败,设置退出码
163
- if (results.failed > 0) {
164
- process.exitCode = 1;
165
- }
166
- }
167
- }
168
-
169
- /**
170
- * 处理批量回放命令
171
- * @param {Object} argv - 命令行参数
172
- * @param {Object} client - SandboxClient 实例
173
- */
174
- async function handleBatchReplay(argv, client) {
175
- const orchestrator = new BatchReplayOrchestrator({
176
- concurrency: argv.concurrency || 1,
177
- baseConfig: client.config,
178
- mode: argv.mode || 'smart',
179
- timing: argv.timing || 'none',
180
- interval: argv.interval || 5,
181
- filters: argv.filter || [],
182
- autoFetchHistory: argv.autoFetchHistory !== false,
183
- continueOnError: argv.continueOnSandboxError !== false,
184
- quiet: argv.quiet || false,
185
- dryRun: argv.dryRun || false,
186
- executeStop: argv.stop || false,
187
- reportFile: argv.reportFile || 'batch-replay-report.json',
188
- logFileBase: argv.logFile || 'replay.log',
189
- verboseLog: argv.verboseLog || false
190
- });
191
-
192
- const result = await orchestrator.execute(argv.fromFile);
193
-
194
- // 设置退出码
195
- if (result.summary.failed > 0) {
196
- process.exitCode = 1;
197
- }
198
-
199
- return result;
200
- }
201
-
202
- /**
203
- * 处理目录模式批量回放
204
- * @param {Object} argv - 命令行参数
205
- * @param {Object} client - SandboxClient 实例
206
- */
207
- async function handleDirectoryReplay(argv, client) {
208
- const sourceDir = argv.fromDir;
209
-
210
- // 1. 验证目录存在
211
- if (!fs.existsSync(sourceDir)) {
212
- logger.error(`Directory not found: ${sourceDir}`);
213
- gracefulExit(1);
214
- }
215
-
216
- // 2. 读取 manifest.json(如果存在)
217
- const manifestPath = path.join(sourceDir, 'manifest.json');
218
- let manifest = null;
219
- let historyFiles = [];
220
-
221
- if (fs.existsSync(manifestPath)) {
222
- try {
223
- manifest = fs.readJsonSync(manifestPath);
224
- } catch (error) {
225
- logger.warn(`Failed to read manifest.json: ${error.message}`);
226
- }
227
- }
228
-
229
- // 3. 扫描目录中的 JSON 文件
230
- const files = fs.readdirSync(sourceDir);
231
- historyFiles = files.filter(f =>
232
- f.endsWith('.json') &&
233
- f !== 'manifest.json' &&
234
- !f.startsWith('.')
235
- );
236
-
237
- if (historyFiles.length === 0) {
238
- logger.error(`No history files found in ${sourceDir}`);
239
- gracefulExit(1);
240
- }
241
-
242
- // 4. 构建输入数据(模拟 --from-file 格式)
243
- const sandboxes = [];
244
- const loadErrors = [];
245
-
246
- for (const file of historyFiles) {
247
- const filePath = path.join(sourceDir, file);
248
- try {
249
- const data = fs.readJsonSync(filePath);
250
-
251
- if (!data.sandboxId) {
252
- loadErrors.push({ file, error: 'Missing sandboxId' });
253
- continue;
254
- }
255
-
256
- if (!data.requests || !Array.isArray(data.requests)) {
257
- loadErrors.push({ file, error: 'Missing or invalid requests array' });
258
- continue;
259
- }
260
-
261
- sandboxes.push(data);
262
- } catch (error) {
263
- loadErrors.push({ file, error: error.message });
264
- }
265
- }
266
-
267
- if (!argv.quiet) {
268
- console.log('\n' + '═'.repeat(70));
269
- console.log('📂 Directory Replay Mode');
270
- console.log('═'.repeat(70));
271
- console.log(` Source Dir: ${sourceDir}`);
272
- console.log(` Files Found: ${historyFiles.length}`);
273
- console.log(` Valid: ${sandboxes.length}`);
274
- if (loadErrors.length > 0) {
275
- console.log(` Errors: ${loadErrors.length}`);
276
- loadErrors.slice(0, 5).forEach(e => {
277
- console.log(` - ${e.file}: ${e.error}`);
278
- });
279
- if (loadErrors.length > 5) {
280
- console.log(` ... and ${loadErrors.length - 5} more`);
281
- }
282
- }
283
- console.log('═'.repeat(70) + '\n');
284
- }
285
-
286
- if (sandboxes.length === 0) {
287
- logger.error('No valid sandbox histories found');
288
- gracefulExit(1);
289
- }
290
-
291
- // 5. 构建虚拟输入文件并调用批量回放
292
- const inputData = {
293
- metadata: {
294
- ...(manifest?.metadata || {}),
295
- sourceDir: sourceDir,
296
- loadedAt: new Date().toISOString()
297
- },
298
- defaults: manifest?.defaults || {},
299
- sandboxes: sandboxes
300
- };
301
-
302
- // 创建临时文件
303
- const tempFile = path.join(sourceDir, '.replay-input-temp.json');
304
- try {
305
- await fs.writeJson(tempFile, inputData, { spaces: 2 });
306
-
307
- // 使用批量回放处理(强制禁用自动获取历史)
308
- const modifiedArgv = {
309
- ...argv,
310
- fromFile: tempFile,
311
- autoFetchHistory: false // 已经有预加载的 requests
312
- };
313
-
314
- const result = await handleBatchReplay(modifiedArgv, client);
315
-
316
- // 清理临时文件
317
- await fs.remove(tempFile);
318
-
319
- return result;
320
- } catch (error) {
321
- // 确保清理临时文件
322
- if (fs.existsSync(tempFile)) {
323
- await fs.remove(tempFile);
324
- }
325
- throw error;
326
- }
327
- }
328
-
329
- module.exports = {
330
- handleSmartReplay,
331
- handleBatchReplay,
332
- handleDirectoryReplay,
333
- readStdin,
334
- parseRequests,
335
- RequestAnalyzer,
336
- ReplayExecutor,
337
- BatchReplayOrchestrator
338
- };
@@ -1,177 +0,0 @@
1
- 'use strict';
2
-
3
- const { ReplayDataSource } = require('./data-source');
4
- const { createClient } = require('../../../../lib/log_provider');
5
- const { clusterTableMapping } = require('../../../log/core/utils');
6
- const logger = require('../../../../utils/logger');
7
- const path = require('path');
8
- const fs = require('fs');
9
-
10
- // Load internal log config
11
- const internalLogConfigPath = path.join(__dirname, '../../../config/internal_log_config.json');
12
- let internalLogConfig = { internalDomains: [], logFiles: {} };
13
- if (fs.existsSync(internalLogConfigPath)) {
14
- try {
15
- internalLogConfig = JSON.parse(fs.readFileSync(internalLogConfigPath, 'utf8'));
16
- } catch (error) {
17
- logger.warn(`Failed to load internal log config: ${error.message}`);
18
- }
19
- }
20
-
21
- // Time ranges to search (in minutes)
22
- const TIME_RANGES = [30, 60, 120, 240, 480];
23
-
24
- /**
25
- * LoghouseDataSource - Internal implementation of ReplayDataSource
26
- * Fetches sandbox history data from Loghouse (internal log storage)
27
- */
28
- class LoghouseDataSource extends ReplayDataSource {
29
- /**
30
- * Fetch history data for a sandbox from Loghouse
31
- * @param {string} sandboxId - Sandbox ID
32
- * @param {Object} options - Fetch options
33
- * @param {string} [options.cluster] - Cluster name (optional, will search all clusters if not specified)
34
- * @param {Array<string>} [options.uris] - URI filters
35
- * @param {boolean} [options.debug] - Enable debug mode
36
- * @returns {Promise<HistoryData>} History data
37
- */
38
- async fetch(sandboxId, options = {}) {
39
- const { cluster, uris, debug } = options;
40
-
41
- // Determine clusters to query
42
- let clustersToQuery = cluster
43
- ? [cluster]
44
- : Object.keys(clusterTableMapping.clusters);
45
-
46
- const now = Date.now();
47
- const requests = [];
48
- let foundCluster = null;
49
-
50
- // Query logs helper function
51
- const queryLogs = async (queryOptions) => {
52
- const { tableName, startTime, endTime, filter, limit } = queryOptions;
53
- const mysqlClient = createClient();
54
-
55
- try {
56
- await mysqlClient.connect();
57
- const logs = await mysqlClient.query({
58
- table: tableName,
59
- startTime,
60
- endTime,
61
- filter: filter || null,
62
- limit: limit || 1000,
63
- offset: 0,
64
- count: false,
65
- orderBy: '@timestamp',
66
- orderDirection: 'ASC'
67
- });
68
- return logs || [];
69
- } catch (error) {
70
- if (debug) {
71
- logger.error(`Query error: ${error.message}`);
72
- }
73
- return [];
74
- } finally {
75
- await mysqlClient.close();
76
- }
77
- };
78
-
79
- // Search for sandbox execution logs across clusters and time ranges
80
- for (const minutes of TIME_RANGES) {
81
- const startTime = now - minutes * 60 * 1000;
82
- const endTime = now;
83
-
84
- for (const clusterName of clustersToQuery) {
85
- const clusterConfig = clusterTableMapping.clusters[clusterName];
86
- if (!clusterConfig || !clusterConfig.nginx) continue;
87
-
88
- const tableName = clusterConfig.nginx;
89
- const nginxLogPath = internalLogConfig.logFiles?.nginxLog || '/home/admin/logs/nginx.log';
90
-
91
- // Build filter for sandbox execution logs
92
- let filter = `@filename:${nginxLogPath} and ${sandboxId}`;
93
-
94
- // Add URI filters if provided
95
- if (uris && uris.length > 0) {
96
- const uriFilters = uris.map(uri => `request_uri:*${uri}*`).join(' or ');
97
- filter = `${filter} and (${uriFilters})`;
98
- }
99
-
100
- const logs = await queryLogs({
101
- tableName,
102
- startTime,
103
- endTime,
104
- filter,
105
- limit: 5000
106
- });
107
-
108
- if (logs && logs.length > 0) {
109
- foundCluster = clusterName;
110
-
111
- // Transform logs to request format
112
- for (const log of logs) {
113
- const request = this._transformLogToRequest(log);
114
- if (request) {
115
- requests.push(request);
116
- }
117
- }
118
- }
119
- }
120
-
121
- // If we found data, no need to search further back
122
- if (requests.length > 0) {
123
- break;
124
- }
125
- }
126
-
127
- return {
128
- sandboxId,
129
- requests,
130
- metadata: {
131
- cluster: foundCluster,
132
- count: requests.length,
133
- fetchedAt: new Date().toISOString()
134
- }
135
- };
136
- }
137
-
138
- /**
139
- * Transform a log entry to a request object
140
- * @param {Object} log - Log entry from Loghouse
141
- * @returns {Object|null} Request object or null if invalid
142
- */
143
- _transformLogToRequest(log) {
144
- if (!log) return null;
145
-
146
- try {
147
- const request = {
148
- method: log.request_method || 'GET',
149
- uri: log.request_uri || '',
150
- timestamp: log['@timestamp'] || new Date().toISOString()
151
- };
152
-
153
- // Parse request body if present
154
- if (log.request_body) {
155
- try {
156
- request.requestBody = JSON.parse(log.request_body);
157
- } catch {
158
- request.requestBody = log.request_body;
159
- }
160
- }
161
-
162
- // Include relevant headers
163
- if (log.request_headers) {
164
- request.headers = log.request_headers;
165
- }
166
-
167
- return request;
168
- } catch (error) {
169
- logger.debug(`Failed to transform log: ${error.message}`);
170
- return null;
171
- }
172
- }
173
- }
174
-
175
- module.exports = {
176
- LoghouseDataSource,
177
- };
@@ -1,26 +0,0 @@
1
- /**
2
- * 从 nohup 输出中提取 PID
3
- * SDK 使用 PIDSTART{pid}PIDEND 格式
4
- * @param {string} output - 命令输出
5
- * @returns {string|null} 提取的 PID,如果未找到则返回 null
6
- */
7
- function extractPidFromOutput(output) {
8
- if (!output) return null;
9
-
10
- const match = output.match(/PIDSTART(\d+)PIDEND/);
11
- if (match) {
12
- return match[1];
13
- }
14
-
15
- // 备用方案:尝试匹配 [1] 12345 格式
16
- const bgMatch = output.match(/\[\d+\]\s+(\d+)/);
17
- if (bgMatch) {
18
- return bgMatch[1];
19
- }
20
-
21
- return null;
22
- }
23
-
24
- module.exports = {
25
- extractPidFromOutput
26
- };