@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 +230 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +230 -180
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
2140
|
-
|
|
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
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
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
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
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
|
-
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
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
|
-
|
|
2226
|
-
|
|
2227
|
-
const entry = parseLogLine2(line);
|
|
2228
|
-
if (entry?.trace_id) {
|
|
2229
|
-
processLogEntry(entry);
|
|
2232
|
+
if (stream) {
|
|
2233
|
+
stream.close();
|
|
2230
2234
|
}
|
|
2231
|
-
}
|
|
2232
|
-
|
|
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(
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
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
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
const
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
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
|
-
|
|
2273
|
-
|
|
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
|
-
|
|
2276
|
-
|
|
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(
|
|
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
|
|
2374
|
-
const traceLogPath = (0, import_node_path7.join)(logDir, "trace.log");
|
|
2455
|
+
function createGetServerLogsHandler(logDir) {
|
|
2375
2456
|
return async (req, res) => {
|
|
2376
|
-
const
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
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
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
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
|
|
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
|
|
2476
|
+
handleError(res, error, "Failed to read server logs");
|
|
2421
2477
|
}
|
|
2422
2478
|
};
|
|
2423
2479
|
}
|
|
2424
|
-
__name(
|
|
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("/
|
|
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: "/
|
|
2527
|
-
description: "Get
|
|
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 = {}) {
|