@lark-apaas/devtool-kits 1.2.5-alpha.3 → 1.2.5

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/dist/index.cjs CHANGED
@@ -2136,147 +2136,229 @@ async function readLogFilePage(filePath, page, pageSize) {
2136
2136
  };
2137
2137
  }
2138
2138
  __name(readLogFilePage, "readLogFilePage");
2139
- async function readTriggerList(filePath, trigger, path7, limit) {
2140
- if (!await fileExists(filePath)) {
2139
+ async function readServerLogs(logDir, options = {}) {
2140
+ const limit = options.limit || 100;
2141
+ const offset = options.offset || 0;
2142
+ const sources = options.sources || [
2143
+ "server",
2144
+ "trace",
2145
+ "server-std",
2146
+ "client-std"
2147
+ ];
2148
+ const allLogs = [];
2149
+ const errors = [];
2150
+ for (const source of sources) {
2151
+ try {
2152
+ const logs = await readLogsBySource(logDir, source);
2153
+ allLogs.push(...logs);
2154
+ } catch (error) {
2155
+ const errorMsg = `Failed to read ${source}: ${error instanceof Error ? error.message : String(error)}`;
2156
+ errors.push(errorMsg);
2157
+ console.warn(`[readServerLogs] ${errorMsg}`);
2158
+ }
2159
+ }
2160
+ if (allLogs.length === 0) {
2161
+ if (errors.length > 0) {
2162
+ console.warn(`[readServerLogs] No logs found. Errors: ${errors.join(", ")}`);
2163
+ }
2141
2164
  return void 0;
2142
2165
  }
2143
- const config = {
2144
- maxEntriesPerTrace: 10,
2145
- chunkSize: 64 * 1024
2166
+ let filteredLogs = allLogs;
2167
+ if (options.levels && options.levels.length > 0) {
2168
+ filteredLogs = allLogs.filter((log) => options.levels.includes(log.level));
2169
+ }
2170
+ filteredLogs.sort((a, b) => b.timestamp - a.timestamp);
2171
+ const total = filteredLogs.length;
2172
+ const paginatedLogs = filteredLogs.slice(offset, offset + limit);
2173
+ return {
2174
+ logs: paginatedLogs,
2175
+ total,
2176
+ hasMore: offset + limit < total
2146
2177
  };
2147
- const builders = /* @__PURE__ */ new Map();
2148
- const completedCalls = [];
2149
- const createTraceBuilder = /* @__PURE__ */ __name((traceId) => ({
2150
- traceId,
2151
- entries: [],
2152
- method: void 0,
2153
- path: void 0,
2154
- startTime: void 0,
2155
- endTime: void 0,
2156
- statusCode: void 0,
2157
- durationMs: void 0,
2158
- hasCompleted: false
2159
- }), "createTraceBuilder");
2160
- const shouldIncludeInCompletedCalls = /* @__PURE__ */ __name((builder) => {
2161
- const alreadyAdded = completedCalls.some((call) => call.traceId === builder.traceId);
2162
- if (alreadyAdded) {
2163
- return false;
2164
- }
2165
- if (!builder.hasCompleted) {
2166
- return false;
2167
- }
2168
- const isAutomationTrigger = builder.path?.endsWith(path7);
2169
- if (!isAutomationTrigger) {
2170
- return false;
2171
- }
2172
- if (trigger && builder.entries.length > 0) {
2173
- const requestEntry = builder.entries.find((e) => e.request_body?.trigger);
2174
- if (requestEntry?.request_body?.trigger) {
2175
- return String(requestEntry.request_body.trigger) === trigger;
2176
- }
2177
- return false;
2178
- }
2179
- return true;
2180
- }, "shouldIncludeInCompletedCalls");
2181
- const updateBuilderMetadata = /* @__PURE__ */ __name((builder, entry) => {
2182
- if (entry.method && !builder.method) builder.method = String(entry.method);
2183
- if (entry.path && !builder.path) builder.path = String(entry.path);
2184
- builder.entries.push(entry);
2185
- if (builder.entries.length > config.maxEntriesPerTrace) {
2186
- builder.entries.shift();
2187
- }
2188
- if (shouldIncludeInCompletedCalls(builder)) {
2189
- completedCalls.push(builder);
2190
- if (limit && completedCalls.length > limit) {
2191
- completedCalls.shift();
2192
- }
2193
- }
2194
- }, "updateBuilderMetadata");
2195
- const handleRequestCompleted = /* @__PURE__ */ __name((builder, entry, message) => {
2196
- builder.hasCompleted = true;
2197
- builder.endTime = entry.time;
2198
- builder.statusCode = extractNumber(message, /status_code:\s*(\d+)/);
2199
- builder.durationMs = extractNumber(message, /duration_ms:\s*(\d+)/);
2200
- if (!builder.path && entry.path) {
2201
- builder.path = String(entry.path);
2202
- }
2203
- if (shouldIncludeInCompletedCalls(builder)) {
2204
- completedCalls.push(builder);
2205
- if (limit && completedCalls.length > limit) {
2206
- completedCalls.shift();
2178
+ }
2179
+ __name(readServerLogs, "readServerLogs");
2180
+ async function readLogsBySource(logDir, source) {
2181
+ const { join: join6 } = await import("path");
2182
+ let filePath;
2183
+ let parser;
2184
+ if (source === "server") {
2185
+ filePath = join6(logDir, "server.log");
2186
+ parser = /* @__PURE__ */ __name((line) => parsePinoLog(line, "server"), "parser");
2187
+ } else if (source === "trace") {
2188
+ filePath = join6(logDir, "trace.log");
2189
+ parser = /* @__PURE__ */ __name((line) => parsePinoLog(line, "trace"), "parser");
2190
+ } else if (source === "server-std") {
2191
+ filePath = join6(logDir, "server.std.log");
2192
+ parser = /* @__PURE__ */ __name((line) => parseStdLog(line, "server-std"), "parser");
2193
+ } else if (source === "client-std") {
2194
+ filePath = join6(logDir, "client.std.log");
2195
+ parser = /* @__PURE__ */ __name((line) => parseStdLog(line, "client-std"), "parser");
2196
+ } else {
2197
+ console.warn(`[readLogsBySource] Unknown source: ${source}`);
2198
+ return [];
2199
+ }
2200
+ if (!await fileExists(filePath)) {
2201
+ console.warn(`[readLogsBySource] File not found: ${filePath}`);
2202
+ return [];
2203
+ }
2204
+ const logs = [];
2205
+ let stream = null;
2206
+ let rl = null;
2207
+ try {
2208
+ stream = (0, import_node_fs7.createReadStream)(filePath, {
2209
+ encoding: "utf8"
2210
+ });
2211
+ rl = (0, import_node_readline.createInterface)({
2212
+ input: stream,
2213
+ crlfDelay: Infinity
2214
+ });
2215
+ for await (const line of rl) {
2216
+ if (!line.trim()) continue;
2217
+ try {
2218
+ const log = parser(line);
2219
+ if (log) {
2220
+ logs.push(log);
2221
+ }
2222
+ } catch (parseError) {
2207
2223
  }
2208
2224
  }
2209
- }, "handleRequestCompleted");
2210
- const processLogEntry = /* @__PURE__ */ __name((entry) => {
2211
- const { trace_id: traceId, message = "" } = entry;
2212
- if (!traceId) return;
2213
- let builder = builders.get(traceId);
2214
- if (!builder) {
2215
- builder = createTraceBuilder(traceId);
2216
- builders.set(traceId, builder);
2217
- }
2218
- updateBuilderMetadata(builder, entry);
2219
- if (!builder.hasCompleted && (message.includes("HTTP request completed") || message.includes("HTTP request failed"))) {
2220
- handleRequestCompleted(builder, entry, message);
2221
- }
2222
- if (message.includes("HTTP request started") && !builder.startTime) {
2223
- builder.startTime = entry.time;
2225
+ } catch (error) {
2226
+ console.error(`[readLogsBySource] Error reading ${filePath}:`, error);
2227
+ throw error;
2228
+ } finally {
2229
+ if (rl) {
2230
+ rl.close();
2224
2231
  }
2225
- }, "processLogEntry");
2226
- const processLine = /* @__PURE__ */ __name((line) => {
2227
- const entry = parseLogLine2(line);
2228
- if (entry?.trace_id) {
2229
- processLogEntry(entry);
2232
+ if (stream) {
2233
+ stream.close();
2230
2234
  }
2231
- }, "processLine");
2232
- await readFileReverse(filePath, config.chunkSize, processLine);
2233
- return {
2234
- page: 1,
2235
- pageSize: completedCalls.length,
2236
- totalCalls: completedCalls.length,
2237
- totalPages: 1,
2238
- calls: completedCalls.map((builder) => ({
2239
- traceId: builder.traceId,
2240
- method: builder.method,
2241
- path: builder.path,
2242
- startTime: builder.startTime,
2243
- endTime: builder.endTime,
2244
- statusCode: builder.statusCode,
2245
- durationMs: builder.durationMs,
2246
- entries: builder.entries.slice().reverse()
2247
- }))
2248
- };
2235
+ }
2236
+ return logs;
2249
2237
  }
2250
- __name(readTriggerList, "readTriggerList");
2251
- async function readTriggerDetail(filePath, path7, instanceID) {
2252
- const exists = await fileExists(filePath);
2253
- if (!exists) {
2254
- return void 0;
2238
+ __name(readLogsBySource, "readLogsBySource");
2239
+ function parsePinoLog(line, source) {
2240
+ try {
2241
+ const pinoLog = JSON.parse(line);
2242
+ const id = generateUUID();
2243
+ return {
2244
+ id,
2245
+ level: mapPinoLevelToServerLogLevel(pinoLog.level),
2246
+ timestamp: new Date(pinoLog.time).getTime(),
2247
+ message: pinoLog.message || pinoLog.msg || "",
2248
+ context: pinoLog.context || null,
2249
+ traceId: pinoLog.trace_id || null,
2250
+ userId: pinoLog.user_id || null,
2251
+ appId: pinoLog.app_id || null,
2252
+ tenantId: pinoLog.tenant_id || null,
2253
+ stack: pinoLog.stack || null,
2254
+ meta: {
2255
+ pid: pinoLog.pid,
2256
+ hostname: pinoLog.hostname,
2257
+ path: pinoLog.path,
2258
+ method: pinoLog.method,
2259
+ statusCode: pinoLog.status_code,
2260
+ durationMs: pinoLog.duration_ms,
2261
+ ip: pinoLog.ip,
2262
+ requestBody: pinoLog.request_body,
2263
+ responseBody: pinoLog.response_body
2264
+ },
2265
+ tags: [
2266
+ source
2267
+ ]
2268
+ };
2269
+ } catch (error) {
2270
+ return null;
2255
2271
  }
2256
- const matches = [];
2257
- const stream = (0, import_node_fs7.createReadStream)(filePath, {
2258
- encoding: "utf8"
2259
- });
2260
- const rl = (0, import_node_readline.createInterface)({
2261
- input: stream,
2262
- crlfDelay: Infinity
2263
- });
2264
- for await (const line of rl) {
2265
- const entry = parseLogLine2(line);
2266
- if (!entry) continue;
2267
- const isAutomationTrigger = entry.path?.endsWith(path7);
2268
- const hasInstanceID = entry.message?.includes(`instanceID=${instanceID}`);
2269
- if (!isAutomationTrigger || !hasInstanceID) continue;
2270
- matches.push(entry);
2272
+ }
2273
+ __name(parsePinoLog, "parsePinoLog");
2274
+ function parseStdLog(line, source) {
2275
+ const id = generateUUID();
2276
+ const match = line.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(server|client)\] (.*)$/);
2277
+ if (!match) {
2278
+ return {
2279
+ id,
2280
+ level: "log",
2281
+ timestamp: Date.now(),
2282
+ message: line,
2283
+ context: null,
2284
+ traceId: null,
2285
+ userId: null,
2286
+ appId: null,
2287
+ tenantId: null,
2288
+ stack: null,
2289
+ meta: null,
2290
+ tags: [
2291
+ source
2292
+ ]
2293
+ };
2271
2294
  }
2272
- rl.close();
2273
- stream.close();
2295
+ const [, timeStr, , content] = match;
2296
+ let timestamp;
2297
+ try {
2298
+ const isoStr = timeStr.replace(" ", "T");
2299
+ timestamp = new Date(isoStr).getTime();
2300
+ if (isNaN(timestamp)) {
2301
+ timestamp = Date.now();
2302
+ }
2303
+ } catch (error) {
2304
+ timestamp = Date.now();
2305
+ }
2306
+ const level = extractLogLevel(content);
2274
2307
  return {
2275
- instanceID,
2276
- entries: matches
2308
+ id,
2309
+ level,
2310
+ timestamp,
2311
+ message: content,
2312
+ context: null,
2313
+ traceId: null,
2314
+ userId: null,
2315
+ appId: null,
2316
+ tenantId: null,
2317
+ stack: null,
2318
+ meta: null,
2319
+ tags: [
2320
+ source
2321
+ ]
2277
2322
  };
2278
2323
  }
2279
- __name(readTriggerDetail, "readTriggerDetail");
2324
+ __name(parseStdLog, "parseStdLog");
2325
+ function mapPinoLevelToServerLogLevel(pinoLevel) {
2326
+ if (typeof pinoLevel === "string") {
2327
+ const lower = pinoLevel.toLowerCase();
2328
+ if (lower === "fatal") return "fatal";
2329
+ if (lower === "error") return "error";
2330
+ if (lower === "warn" || lower === "warning") return "warn";
2331
+ if (lower === "info" || lower === "log") return "log";
2332
+ if (lower === "debug") return "debug";
2333
+ if (lower === "trace" || lower === "verbose") return "verbose";
2334
+ return "log";
2335
+ }
2336
+ if (pinoLevel >= 60) return "fatal";
2337
+ if (pinoLevel >= 50) return "error";
2338
+ if (pinoLevel >= 40) return "warn";
2339
+ if (pinoLevel >= 30) return "log";
2340
+ if (pinoLevel >= 20) return "debug";
2341
+ return "verbose";
2342
+ }
2343
+ __name(mapPinoLevelToServerLogLevel, "mapPinoLevelToServerLogLevel");
2344
+ function extractLogLevel(text) {
2345
+ const lower = text.toLowerCase();
2346
+ if (lower.includes("fatal") || lower.includes("critical")) return "fatal";
2347
+ if (lower.includes("error") || lower.includes("<e>") || lower.includes("\u2716")) return "error";
2348
+ if (lower.includes("warn") || lower.includes("warning") || lower.includes("<w>") || lower.includes("\u26A0")) return "warn";
2349
+ if (lower.includes("debug") || lower.includes("<d>")) return "debug";
2350
+ if (lower.includes("verbose") || lower.includes("trace")) return "verbose";
2351
+ return "log";
2352
+ }
2353
+ __name(extractLogLevel, "extractLogLevel");
2354
+ function generateUUID() {
2355
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
2356
+ const r = Math.random() * 16 | 0;
2357
+ const v = c === "x" ? r : r & 3 | 8;
2358
+ return v.toString(16);
2359
+ });
2360
+ }
2361
+ __name(generateUUID, "generateUUID");
2280
2362
 
2281
2363
  // src/middlewares/dev-logs/controller.ts
2282
2364
  function handleNotFound(res, filePath, message = "Log file not found") {
@@ -2370,58 +2452,32 @@ function createGetLogFileHandler(logDir) {
2370
2452
  };
2371
2453
  }
2372
2454
  __name(createGetLogFileHandler, "createGetLogFileHandler");
2373
- function createGetTriggerListHandler(logDir) {
2374
- const traceLogPath = (0, import_node_path7.join)(logDir, "trace.log");
2455
+ function createGetServerLogsHandler(logDir) {
2375
2456
  return async (req, res) => {
2376
- const trigger = typeof req.query.trigger === "string" ? req.query.trigger.trim() : void 0;
2377
- if (!trigger) {
2378
- return res.status(400).json({
2379
- message: "trigger is required"
2380
- });
2381
- }
2382
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2383
- const limit = parseLimit(req.query.limit, 10, 200);
2457
+ const limit = parseLimit(req.query.limit, 100, 1e3);
2458
+ const offset = parsePositiveInt(req.query.offset, 0);
2459
+ const levels = req.query.levels ? String(req.query.levels).split(",").map((l) => l.trim()).filter(Boolean) : void 0;
2460
+ const sources = req.query.sources ? String(req.query.sources).split(",").map((s) => s.trim()).filter(Boolean) : void 0;
2384
2461
  try {
2385
- const result = await readTriggerList(traceLogPath, trigger, path7, limit);
2386
- if (!result) {
2387
- return handleNotFound(res, traceLogPath);
2388
- }
2389
- res.json({
2390
- file: getRelativePath(traceLogPath),
2391
- path: path7,
2392
- ...result
2462
+ const result = await readServerLogs(logDir, {
2463
+ limit,
2464
+ offset,
2465
+ levels,
2466
+ sources
2393
2467
  });
2394
- } catch (error) {
2395
- handleError(res, error, "Failed to read trace log");
2396
- }
2397
- };
2398
- }
2399
- __name(createGetTriggerListHandler, "createGetTriggerListHandler");
2400
- function createGetTriggerDetailHandler(logDir) {
2401
- const traceLogPath = (0, import_node_path7.join)(logDir, "server.log");
2402
- return async (req, res) => {
2403
- const instanceID = (req.params.instanceID || "").trim();
2404
- if (!instanceID) {
2405
- return res.status(400).json({
2406
- message: "instanceID is required"
2407
- });
2408
- }
2409
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2410
- try {
2411
- const result = await readTriggerDetail(traceLogPath, path7, instanceID);
2412
2468
  if (!result) {
2413
- return handleNotFound(res, traceLogPath);
2469
+ return res.status(404).json({
2470
+ message: "No server log files found",
2471
+ hint: "Expected files: server.log, trace.log, server.std.log, client.std.log"
2472
+ });
2414
2473
  }
2415
- res.json({
2416
- file: getRelativePath(traceLogPath),
2417
- ...result
2418
- });
2474
+ res.json(result);
2419
2475
  } catch (error) {
2420
- handleError(res, error, "Failed to read trace log");
2476
+ handleError(res, error, "Failed to read server logs");
2421
2477
  }
2422
2478
  };
2423
2479
  }
2424
- __name(createGetTriggerDetailHandler, "createGetTriggerDetailHandler");
2480
+ __name(createGetServerLogsHandler, "createGetServerLogsHandler");
2425
2481
 
2426
2482
  // src/middlewares/dev-logs/health.controller.ts
2427
2483
  var import_node_http2 = __toESM(require("http"), 1);
@@ -2497,8 +2553,7 @@ function createDevLogRouter(options = {}) {
2497
2553
  router.get("/app/trace/:traceId", createGetTraceEntriesHandler(logDir));
2498
2554
  router.get("/trace/recent", createGetRecentTracesHandler(logDir));
2499
2555
  router.get("/files/:fileName", createGetLogFileHandler(logDir));
2500
- router.get("/trace/trigger/list", createGetTriggerListHandler(logDir));
2501
- router.get("/trace/trigger/:instanceID", createGetTriggerDetailHandler(logDir));
2556
+ router.get("/server-logs", createGetServerLogsHandler(logDir));
2502
2557
  router.get("/health", createHealthCheckHandler());
2503
2558
  return router;
2504
2559
  }
@@ -2523,13 +2578,8 @@ var DEV_LOGS_ROUTES = [
2523
2578
  },
2524
2579
  {
2525
2580
  method: "GET",
2526
- path: "/trace/trigger/list",
2527
- description: "Get trigger list (automation trigger) in trace.log"
2528
- },
2529
- {
2530
- method: "GET",
2531
- path: "/trace/trigger/:instanceID",
2532
- description: "Get trigger detail (automation trigger) in trace.log by instanceID"
2581
+ path: "/server-logs",
2582
+ description: "Get server logs in ServerLog format (compatible with frontend)"
2533
2583
  }
2534
2584
  ];
2535
2585
  function createDevLogsMiddleware(options = {}) {