@lark-apaas/devtool-kits 1.2.5-alpha.2 → 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,146 +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 === 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, 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 hasInstanceID = entry.message?.includes(`instanceID=${instanceID}`);
2227
- if (!hasInstanceID) continue;
2228
- 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
+ };
2229
2253
  }
2230
- rl.close();
2231
- 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);
2232
2266
  return {
2233
- instanceID,
2234
- 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
+ ]
2235
2281
  };
2236
2282
  }
2237
- __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");
2238
2321
 
2239
2322
  // src/middlewares/dev-logs/controller.ts
2240
2323
  function handleNotFound(res, filePath, message = "Log file not found") {
@@ -2328,57 +2411,32 @@ function createGetLogFileHandler(logDir) {
2328
2411
  };
2329
2412
  }
2330
2413
  __name(createGetLogFileHandler, "createGetLogFileHandler");
2331
- function createGetTriggerListHandler(logDir) {
2332
- const traceLogPath = join3(logDir, "trace.log");
2414
+ function createGetServerLogsHandler(logDir) {
2333
2415
  return async (req, res) => {
2334
- const trigger = typeof req.query.trigger === "string" ? req.query.trigger.trim() : void 0;
2335
- if (!trigger) {
2336
- return res.status(400).json({
2337
- message: "trigger is required"
2338
- });
2339
- }
2340
- const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2341
- 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;
2342
2420
  try {
2343
- const result = await readTriggerList(traceLogPath, trigger, path7, limit);
2344
- if (!result) {
2345
- return handleNotFound(res, traceLogPath);
2346
- }
2347
- res.json({
2348
- file: getRelativePath(traceLogPath),
2349
- path: path7,
2350
- ...result
2421
+ const result = await readServerLogs(logDir, {
2422
+ limit,
2423
+ offset,
2424
+ levels,
2425
+ sources
2351
2426
  });
2352
- } catch (error) {
2353
- handleError(res, error, "Failed to read trace log");
2354
- }
2355
- };
2356
- }
2357
- __name(createGetTriggerListHandler, "createGetTriggerListHandler");
2358
- function createGetTriggerDetailHandler(logDir) {
2359
- const traceLogPath = join3(logDir, "server.log");
2360
- return async (req, res) => {
2361
- const instanceID = (req.params.instanceID || "").trim();
2362
- if (!instanceID) {
2363
- return res.status(400).json({
2364
- message: "instanceID is required"
2365
- });
2366
- }
2367
- try {
2368
- const result = await readTriggerDetail(traceLogPath, instanceID);
2369
2427
  if (!result) {
2370
- 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
+ });
2371
2432
  }
2372
- res.json({
2373
- file: getRelativePath(traceLogPath),
2374
- ...result
2375
- });
2433
+ res.json(result);
2376
2434
  } catch (error) {
2377
- handleError(res, error, "Failed to read trace log");
2435
+ handleError(res, error, "Failed to read server logs");
2378
2436
  }
2379
2437
  };
2380
2438
  }
2381
- __name(createGetTriggerDetailHandler, "createGetTriggerDetailHandler");
2439
+ __name(createGetServerLogsHandler, "createGetServerLogsHandler");
2382
2440
 
2383
2441
  // src/middlewares/dev-logs/health.controller.ts
2384
2442
  import http2 from "http";
@@ -2454,8 +2512,7 @@ function createDevLogRouter(options = {}) {
2454
2512
  router.get("/app/trace/:traceId", createGetTraceEntriesHandler(logDir));
2455
2513
  router.get("/trace/recent", createGetRecentTracesHandler(logDir));
2456
2514
  router.get("/files/:fileName", createGetLogFileHandler(logDir));
2457
- router.get("/trace/trigger/list", createGetTriggerListHandler(logDir));
2458
- router.get("/trace/trigger/:instanceID", createGetTriggerDetailHandler(logDir));
2515
+ router.get("/server-logs", createGetServerLogsHandler(logDir));
2459
2516
  router.get("/health", createHealthCheckHandler());
2460
2517
  return router;
2461
2518
  }
@@ -2480,13 +2537,8 @@ var DEV_LOGS_ROUTES = [
2480
2537
  },
2481
2538
  {
2482
2539
  method: "GET",
2483
- path: "/trace/trigger/list",
2484
- description: "Get trigger list (automation trigger) in trace.log"
2485
- },
2486
- {
2487
- method: "GET",
2488
- path: "/trace/trigger/:instanceID",
2489
- 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)"
2490
2542
  }
2491
2543
  ];
2492
2544
  function createDevLogsMiddleware(options = {}) {