@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.js CHANGED
@@ -2095,147 +2095,229 @@ async function readLogFilePage(filePath, page, pageSize) {
2095
2095
  };
2096
2096
  }
2097
2097
  __name(readLogFilePage, "readLogFilePage");
2098
- async function readTriggerList(filePath, trigger, path7, limit) {
2099
- if (!await fileExists(filePath)) {
2098
+ async function readServerLogs(logDir, options = {}) {
2099
+ const limit = options.limit || 100;
2100
+ const offset = options.offset || 0;
2101
+ const sources = options.sources || [
2102
+ "server",
2103
+ "trace",
2104
+ "server-std",
2105
+ "client-std"
2106
+ ];
2107
+ const allLogs = [];
2108
+ const errors = [];
2109
+ for (const source of sources) {
2110
+ try {
2111
+ const logs = await readLogsBySource(logDir, source);
2112
+ allLogs.push(...logs);
2113
+ } catch (error) {
2114
+ const errorMsg = `Failed to read ${source}: ${error instanceof Error ? error.message : String(error)}`;
2115
+ errors.push(errorMsg);
2116
+ console.warn(`[readServerLogs] ${errorMsg}`);
2117
+ }
2118
+ }
2119
+ if (allLogs.length === 0) {
2120
+ if (errors.length > 0) {
2121
+ console.warn(`[readServerLogs] No logs found. Errors: ${errors.join(", ")}`);
2122
+ }
2100
2123
  return void 0;
2101
2124
  }
2102
- const config = {
2103
- maxEntriesPerTrace: 10,
2104
- chunkSize: 64 * 1024
2125
+ let filteredLogs = allLogs;
2126
+ if (options.levels && options.levels.length > 0) {
2127
+ filteredLogs = allLogs.filter((log) => options.levels.includes(log.level));
2128
+ }
2129
+ filteredLogs.sort((a, b) => b.timestamp - a.timestamp);
2130
+ const total = filteredLogs.length;
2131
+ const paginatedLogs = filteredLogs.slice(offset, offset + limit);
2132
+ return {
2133
+ logs: paginatedLogs,
2134
+ total,
2135
+ hasMore: offset + limit < total
2105
2136
  };
2106
- const builders = /* @__PURE__ */ new Map();
2107
- const completedCalls = [];
2108
- const createTraceBuilder = /* @__PURE__ */ __name((traceId) => ({
2109
- traceId,
2110
- entries: [],
2111
- method: void 0,
2112
- path: void 0,
2113
- startTime: void 0,
2114
- endTime: void 0,
2115
- statusCode: void 0,
2116
- durationMs: void 0,
2117
- hasCompleted: false
2118
- }), "createTraceBuilder");
2119
- const shouldIncludeInCompletedCalls = /* @__PURE__ */ __name((builder) => {
2120
- const alreadyAdded = completedCalls.some((call) => call.traceId === builder.traceId);
2121
- if (alreadyAdded) {
2122
- return false;
2123
- }
2124
- if (!builder.hasCompleted) {
2125
- return false;
2126
- }
2127
- const isAutomationTrigger = builder.path?.endsWith(path7);
2128
- if (!isAutomationTrigger) {
2129
- return false;
2130
- }
2131
- if (trigger && builder.entries.length > 0) {
2132
- const requestEntry = builder.entries.find((e) => e.request_body?.trigger);
2133
- if (requestEntry?.request_body?.trigger) {
2134
- return String(requestEntry.request_body.trigger) === trigger;
2135
- }
2136
- return false;
2137
- }
2138
- return true;
2139
- }, "shouldIncludeInCompletedCalls");
2140
- const updateBuilderMetadata = /* @__PURE__ */ __name((builder, entry) => {
2141
- if (entry.method && !builder.method) builder.method = String(entry.method);
2142
- if (entry.path && !builder.path) builder.path = String(entry.path);
2143
- builder.entries.push(entry);
2144
- if (builder.entries.length > config.maxEntriesPerTrace) {
2145
- builder.entries.shift();
2146
- }
2147
- if (shouldIncludeInCompletedCalls(builder)) {
2148
- completedCalls.push(builder);
2149
- if (limit && completedCalls.length > limit) {
2150
- completedCalls.shift();
2151
- }
2152
- }
2153
- }, "updateBuilderMetadata");
2154
- const handleRequestCompleted = /* @__PURE__ */ __name((builder, entry, message) => {
2155
- builder.hasCompleted = true;
2156
- builder.endTime = entry.time;
2157
- builder.statusCode = extractNumber(message, /status_code:\s*(\d+)/);
2158
- builder.durationMs = extractNumber(message, /duration_ms:\s*(\d+)/);
2159
- if (!builder.path && entry.path) {
2160
- builder.path = String(entry.path);
2161
- }
2162
- if (shouldIncludeInCompletedCalls(builder)) {
2163
- completedCalls.push(builder);
2164
- if (limit && completedCalls.length > limit) {
2165
- completedCalls.shift();
2137
+ }
2138
+ __name(readServerLogs, "readServerLogs");
2139
+ async function readLogsBySource(logDir, source) {
2140
+ const { join: join6 } = await import("path");
2141
+ let filePath;
2142
+ let parser;
2143
+ if (source === "server") {
2144
+ filePath = join6(logDir, "server.log");
2145
+ parser = /* @__PURE__ */ __name((line) => parsePinoLog(line, "server"), "parser");
2146
+ } else if (source === "trace") {
2147
+ filePath = join6(logDir, "trace.log");
2148
+ parser = /* @__PURE__ */ __name((line) => parsePinoLog(line, "trace"), "parser");
2149
+ } else if (source === "server-std") {
2150
+ filePath = join6(logDir, "server.std.log");
2151
+ parser = /* @__PURE__ */ __name((line) => parseStdLog(line, "server-std"), "parser");
2152
+ } else if (source === "client-std") {
2153
+ filePath = join6(logDir, "client.std.log");
2154
+ parser = /* @__PURE__ */ __name((line) => parseStdLog(line, "client-std"), "parser");
2155
+ } else {
2156
+ console.warn(`[readLogsBySource] Unknown source: ${source}`);
2157
+ return [];
2158
+ }
2159
+ if (!await fileExists(filePath)) {
2160
+ console.warn(`[readLogsBySource] File not found: ${filePath}`);
2161
+ return [];
2162
+ }
2163
+ const logs = [];
2164
+ let stream = null;
2165
+ let rl = null;
2166
+ try {
2167
+ stream = createReadStream(filePath, {
2168
+ encoding: "utf8"
2169
+ });
2170
+ rl = createInterface({
2171
+ input: stream,
2172
+ crlfDelay: Infinity
2173
+ });
2174
+ for await (const line of rl) {
2175
+ if (!line.trim()) continue;
2176
+ try {
2177
+ const log = parser(line);
2178
+ if (log) {
2179
+ logs.push(log);
2180
+ }
2181
+ } catch (parseError) {
2166
2182
  }
2167
2183
  }
2168
- }, "handleRequestCompleted");
2169
- const processLogEntry = /* @__PURE__ */ __name((entry) => {
2170
- const { trace_id: traceId, message = "" } = entry;
2171
- if (!traceId) return;
2172
- let builder = builders.get(traceId);
2173
- if (!builder) {
2174
- builder = createTraceBuilder(traceId);
2175
- builders.set(traceId, builder);
2176
- }
2177
- updateBuilderMetadata(builder, entry);
2178
- if (!builder.hasCompleted && (message.includes("HTTP request completed") || message.includes("HTTP request failed"))) {
2179
- handleRequestCompleted(builder, entry, message);
2180
- }
2181
- if (message.includes("HTTP request started") && !builder.startTime) {
2182
- builder.startTime = entry.time;
2184
+ } catch (error) {
2185
+ console.error(`[readLogsBySource] Error reading ${filePath}:`, error);
2186
+ throw error;
2187
+ } finally {
2188
+ if (rl) {
2189
+ rl.close();
2183
2190
  }
2184
- }, "processLogEntry");
2185
- const processLine = /* @__PURE__ */ __name((line) => {
2186
- const entry = parseLogLine2(line);
2187
- if (entry?.trace_id) {
2188
- processLogEntry(entry);
2191
+ if (stream) {
2192
+ stream.close();
2189
2193
  }
2190
- }, "processLine");
2191
- await readFileReverse(filePath, config.chunkSize, processLine);
2192
- return {
2193
- page: 1,
2194
- pageSize: completedCalls.length,
2195
- totalCalls: completedCalls.length,
2196
- totalPages: 1,
2197
- calls: completedCalls.map((builder) => ({
2198
- traceId: builder.traceId,
2199
- method: builder.method,
2200
- path: builder.path,
2201
- startTime: builder.startTime,
2202
- endTime: builder.endTime,
2203
- statusCode: builder.statusCode,
2204
- durationMs: builder.durationMs,
2205
- entries: builder.entries.slice().reverse()
2206
- }))
2207
- };
2194
+ }
2195
+ return logs;
2208
2196
  }
2209
- __name(readTriggerList, "readTriggerList");
2210
- async function readTriggerDetail(filePath, path7, instanceID) {
2211
- const exists = await fileExists(filePath);
2212
- if (!exists) {
2213
- return void 0;
2197
+ __name(readLogsBySource, "readLogsBySource");
2198
+ function parsePinoLog(line, source) {
2199
+ try {
2200
+ const pinoLog = JSON.parse(line);
2201
+ const id = generateUUID();
2202
+ return {
2203
+ id,
2204
+ level: mapPinoLevelToServerLogLevel(pinoLog.level),
2205
+ timestamp: new Date(pinoLog.time).getTime(),
2206
+ message: pinoLog.message || pinoLog.msg || "",
2207
+ context: pinoLog.context || null,
2208
+ traceId: pinoLog.trace_id || null,
2209
+ userId: pinoLog.user_id || null,
2210
+ appId: pinoLog.app_id || null,
2211
+ tenantId: pinoLog.tenant_id || null,
2212
+ stack: pinoLog.stack || null,
2213
+ meta: {
2214
+ pid: pinoLog.pid,
2215
+ hostname: pinoLog.hostname,
2216
+ path: pinoLog.path,
2217
+ method: pinoLog.method,
2218
+ statusCode: pinoLog.status_code,
2219
+ durationMs: pinoLog.duration_ms,
2220
+ ip: pinoLog.ip,
2221
+ requestBody: pinoLog.request_body,
2222
+ responseBody: pinoLog.response_body
2223
+ },
2224
+ tags: [
2225
+ source
2226
+ ]
2227
+ };
2228
+ } catch (error) {
2229
+ return null;
2214
2230
  }
2215
- const matches = [];
2216
- const stream = createReadStream(filePath, {
2217
- encoding: "utf8"
2218
- });
2219
- const rl = createInterface({
2220
- input: stream,
2221
- crlfDelay: Infinity
2222
- });
2223
- for await (const line of rl) {
2224
- const entry = parseLogLine2(line);
2225
- if (!entry) continue;
2226
- const isAutomationTrigger = entry.path?.endsWith(path7);
2227
- const hasInstanceID = entry.message?.includes(`instanceID=${instanceID}`);
2228
- if (!isAutomationTrigger || !hasInstanceID) continue;
2229
- matches.push(entry);
2231
+ }
2232
+ __name(parsePinoLog, "parsePinoLog");
2233
+ function parseStdLog(line, source) {
2234
+ const id = generateUUID();
2235
+ const match = line.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(server|client)\] (.*)$/);
2236
+ if (!match) {
2237
+ return {
2238
+ id,
2239
+ level: "log",
2240
+ timestamp: Date.now(),
2241
+ message: line,
2242
+ context: null,
2243
+ traceId: null,
2244
+ userId: null,
2245
+ appId: null,
2246
+ tenantId: null,
2247
+ stack: null,
2248
+ meta: null,
2249
+ tags: [
2250
+ source
2251
+ ]
2252
+ };
2230
2253
  }
2231
- rl.close();
2232
- stream.close();
2254
+ const [, timeStr, , content] = match;
2255
+ let timestamp;
2256
+ try {
2257
+ const isoStr = timeStr.replace(" ", "T");
2258
+ timestamp = new Date(isoStr).getTime();
2259
+ if (isNaN(timestamp)) {
2260
+ timestamp = Date.now();
2261
+ }
2262
+ } catch (error) {
2263
+ timestamp = Date.now();
2264
+ }
2265
+ const level = extractLogLevel(content);
2233
2266
  return {
2234
- instanceID,
2235
- entries: matches
2267
+ id,
2268
+ level,
2269
+ timestamp,
2270
+ message: content,
2271
+ context: null,
2272
+ traceId: null,
2273
+ userId: null,
2274
+ appId: null,
2275
+ tenantId: null,
2276
+ stack: null,
2277
+ meta: null,
2278
+ tags: [
2279
+ source
2280
+ ]
2236
2281
  };
2237
2282
  }
2238
- __name(readTriggerDetail, "readTriggerDetail");
2283
+ __name(parseStdLog, "parseStdLog");
2284
+ function mapPinoLevelToServerLogLevel(pinoLevel) {
2285
+ if (typeof pinoLevel === "string") {
2286
+ const lower = pinoLevel.toLowerCase();
2287
+ if (lower === "fatal") return "fatal";
2288
+ if (lower === "error") return "error";
2289
+ if (lower === "warn" || lower === "warning") return "warn";
2290
+ if (lower === "info" || lower === "log") return "log";
2291
+ if (lower === "debug") return "debug";
2292
+ if (lower === "trace" || lower === "verbose") return "verbose";
2293
+ return "log";
2294
+ }
2295
+ if (pinoLevel >= 60) return "fatal";
2296
+ if (pinoLevel >= 50) return "error";
2297
+ if (pinoLevel >= 40) return "warn";
2298
+ if (pinoLevel >= 30) return "log";
2299
+ if (pinoLevel >= 20) return "debug";
2300
+ return "verbose";
2301
+ }
2302
+ __name(mapPinoLevelToServerLogLevel, "mapPinoLevelToServerLogLevel");
2303
+ function extractLogLevel(text) {
2304
+ const lower = text.toLowerCase();
2305
+ if (lower.includes("fatal") || lower.includes("critical")) return "fatal";
2306
+ if (lower.includes("error") || lower.includes("<e>") || lower.includes("\u2716")) return "error";
2307
+ if (lower.includes("warn") || lower.includes("warning") || lower.includes("<w>") || lower.includes("\u26A0")) return "warn";
2308
+ if (lower.includes("debug") || lower.includes("<d>")) return "debug";
2309
+ if (lower.includes("verbose") || lower.includes("trace")) return "verbose";
2310
+ return "log";
2311
+ }
2312
+ __name(extractLogLevel, "extractLogLevel");
2313
+ function generateUUID() {
2314
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
2315
+ const r = Math.random() * 16 | 0;
2316
+ const v = c === "x" ? r : r & 3 | 8;
2317
+ return v.toString(16);
2318
+ });
2319
+ }
2320
+ __name(generateUUID, "generateUUID");
2239
2321
 
2240
2322
  // src/middlewares/dev-logs/controller.ts
2241
2323
  function handleNotFound(res, filePath, message = "Log file not found") {
@@ -2329,58 +2411,32 @@ function createGetLogFileHandler(logDir) {
2329
2411
  };
2330
2412
  }
2331
2413
  __name(createGetLogFileHandler, "createGetLogFileHandler");
2332
- function createGetTriggerListHandler(logDir) {
2333
- const traceLogPath = join3(logDir, "trace.log");
2414
+ function createGetServerLogsHandler(logDir) {
2334
2415
  return async (req, res) => {
2335
- const trigger = typeof req.query.trigger === "string" ? req.query.trigger.trim() : void 0;
2336
- if (!trigger) {
2337
- return res.status(400).json({
2338
- message: "trigger is required"
2339
- });
2340
- }
2341
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2342
- const limit = parseLimit(req.query.limit, 10, 200);
2416
+ const limit = parseLimit(req.query.limit, 100, 1e3);
2417
+ const offset = parsePositiveInt(req.query.offset, 0);
2418
+ const levels = req.query.levels ? String(req.query.levels).split(",").map((l) => l.trim()).filter(Boolean) : void 0;
2419
+ const sources = req.query.sources ? String(req.query.sources).split(",").map((s) => s.trim()).filter(Boolean) : void 0;
2343
2420
  try {
2344
- const result = await readTriggerList(traceLogPath, trigger, path7, limit);
2345
- if (!result) {
2346
- return handleNotFound(res, traceLogPath);
2347
- }
2348
- res.json({
2349
- file: getRelativePath(traceLogPath),
2350
- path: path7,
2351
- ...result
2421
+ const result = await readServerLogs(logDir, {
2422
+ limit,
2423
+ offset,
2424
+ levels,
2425
+ sources
2352
2426
  });
2353
- } catch (error) {
2354
- handleError(res, error, "Failed to read trace log");
2355
- }
2356
- };
2357
- }
2358
- __name(createGetTriggerListHandler, "createGetTriggerListHandler");
2359
- function createGetTriggerDetailHandler(logDir) {
2360
- const traceLogPath = join3(logDir, "server.log");
2361
- return async (req, res) => {
2362
- const instanceID = (req.params.instanceID || "").trim();
2363
- if (!instanceID) {
2364
- return res.status(400).json({
2365
- message: "instanceID is required"
2366
- });
2367
- }
2368
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2369
- try {
2370
- const result = await readTriggerDetail(traceLogPath, path7, instanceID);
2371
2427
  if (!result) {
2372
- return handleNotFound(res, traceLogPath);
2428
+ return res.status(404).json({
2429
+ message: "No server log files found",
2430
+ hint: "Expected files: server.log, trace.log, server.std.log, client.std.log"
2431
+ });
2373
2432
  }
2374
- res.json({
2375
- file: getRelativePath(traceLogPath),
2376
- ...result
2377
- });
2433
+ res.json(result);
2378
2434
  } catch (error) {
2379
- handleError(res, error, "Failed to read trace log");
2435
+ handleError(res, error, "Failed to read server logs");
2380
2436
  }
2381
2437
  };
2382
2438
  }
2383
- __name(createGetTriggerDetailHandler, "createGetTriggerDetailHandler");
2439
+ __name(createGetServerLogsHandler, "createGetServerLogsHandler");
2384
2440
 
2385
2441
  // src/middlewares/dev-logs/health.controller.ts
2386
2442
  import http2 from "http";
@@ -2456,8 +2512,7 @@ function createDevLogRouter(options = {}) {
2456
2512
  router.get("/app/trace/:traceId", createGetTraceEntriesHandler(logDir));
2457
2513
  router.get("/trace/recent", createGetRecentTracesHandler(logDir));
2458
2514
  router.get("/files/:fileName", createGetLogFileHandler(logDir));
2459
- router.get("/trace/trigger/list", createGetTriggerListHandler(logDir));
2460
- router.get("/trace/trigger/:instanceID", createGetTriggerDetailHandler(logDir));
2515
+ router.get("/server-logs", createGetServerLogsHandler(logDir));
2461
2516
  router.get("/health", createHealthCheckHandler());
2462
2517
  return router;
2463
2518
  }
@@ -2482,13 +2537,8 @@ var DEV_LOGS_ROUTES = [
2482
2537
  },
2483
2538
  {
2484
2539
  method: "GET",
2485
- path: "/trace/trigger/list",
2486
- description: "Get trigger list (automation trigger) in trace.log"
2487
- },
2488
- {
2489
- method: "GET",
2490
- path: "/trace/trigger/:instanceID",
2491
- description: "Get trigger detail (automation trigger) in trace.log by instanceID"
2540
+ path: "/server-logs",
2541
+ description: "Get server logs in ServerLog format (compatible with frontend)"
2492
2542
  }
2493
2543
  ];
2494
2544
  function createDevLogsMiddleware(options = {}) {