@lark-apaas/devtool-kits 1.2.4 → 1.2.5-alpha.1
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 +255 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +255 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2095,6 +2095,229 @@ async function readLogFilePage(filePath, page, pageSize) {
|
|
|
2095
2095
|
};
|
|
2096
2096
|
}
|
|
2097
2097
|
__name(readLogFilePage, "readLogFilePage");
|
|
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
|
+
}
|
|
2123
|
+
return void 0;
|
|
2124
|
+
}
|
|
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
|
|
2136
|
+
};
|
|
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) {
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
} catch (error) {
|
|
2185
|
+
console.error(`[readLogsBySource] Error reading ${filePath}:`, error);
|
|
2186
|
+
throw error;
|
|
2187
|
+
} finally {
|
|
2188
|
+
if (rl) {
|
|
2189
|
+
rl.close();
|
|
2190
|
+
}
|
|
2191
|
+
if (stream) {
|
|
2192
|
+
stream.close();
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
return logs;
|
|
2196
|
+
}
|
|
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;
|
|
2230
|
+
}
|
|
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
|
+
};
|
|
2253
|
+
}
|
|
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);
|
|
2266
|
+
return {
|
|
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
|
+
]
|
|
2281
|
+
};
|
|
2282
|
+
}
|
|
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");
|
|
2098
2321
|
|
|
2099
2322
|
// src/middlewares/dev-logs/controller.ts
|
|
2100
2323
|
function handleNotFound(res, filePath, message = "Log file not found") {
|
|
@@ -2188,6 +2411,32 @@ function createGetLogFileHandler(logDir) {
|
|
|
2188
2411
|
};
|
|
2189
2412
|
}
|
|
2190
2413
|
__name(createGetLogFileHandler, "createGetLogFileHandler");
|
|
2414
|
+
function createGetServerLogsHandler(logDir) {
|
|
2415
|
+
return async (req, res) => {
|
|
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;
|
|
2420
|
+
try {
|
|
2421
|
+
const result = await readServerLogs(logDir, {
|
|
2422
|
+
limit,
|
|
2423
|
+
offset,
|
|
2424
|
+
levels,
|
|
2425
|
+
sources
|
|
2426
|
+
});
|
|
2427
|
+
if (!result) {
|
|
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
|
+
});
|
|
2432
|
+
}
|
|
2433
|
+
res.json(result);
|
|
2434
|
+
} catch (error) {
|
|
2435
|
+
handleError(res, error, "Failed to read server logs");
|
|
2436
|
+
}
|
|
2437
|
+
};
|
|
2438
|
+
}
|
|
2439
|
+
__name(createGetServerLogsHandler, "createGetServerLogsHandler");
|
|
2191
2440
|
|
|
2192
2441
|
// src/middlewares/dev-logs/health.controller.ts
|
|
2193
2442
|
import http2 from "http";
|
|
@@ -2263,6 +2512,7 @@ function createDevLogRouter(options = {}) {
|
|
|
2263
2512
|
router.get("/app/trace/:traceId", createGetTraceEntriesHandler(logDir));
|
|
2264
2513
|
router.get("/trace/recent", createGetRecentTracesHandler(logDir));
|
|
2265
2514
|
router.get("/files/:fileName", createGetLogFileHandler(logDir));
|
|
2515
|
+
router.get("/server-logs", createGetServerLogsHandler(logDir));
|
|
2266
2516
|
router.get("/health", createHealthCheckHandler());
|
|
2267
2517
|
return router;
|
|
2268
2518
|
}
|
|
@@ -2284,6 +2534,11 @@ var DEV_LOGS_ROUTES = [
|
|
|
2284
2534
|
method: "GET",
|
|
2285
2535
|
path: "/files/:fileName",
|
|
2286
2536
|
description: "Get paginated log file content by file name"
|
|
2537
|
+
},
|
|
2538
|
+
{
|
|
2539
|
+
method: "GET",
|
|
2540
|
+
path: "/server-logs",
|
|
2541
|
+
description: "Get server logs in ServerLog format (compatible with frontend)"
|
|
2287
2542
|
}
|
|
2288
2543
|
];
|
|
2289
2544
|
function createDevLogsMiddleware(options = {}) {
|