@nocobase/plugin-logger 1.2.13-alpha → 1.3.0-alpha.20240710084543

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.
@@ -1,287 +0,0 @@
1
- const { Readable, Writable, getStreamError } = require('streamx')
2
- const b4a = require('b4a')
3
-
4
- const constants = require('./constants')
5
- const headers = require('./headers')
6
-
7
- const DMODE = 0o755
8
- const FMODE = 0o644
9
-
10
- const END_OF_TAR = b4a.alloc(1024)
11
-
12
- class Sink extends Writable {
13
- constructor (pack, header, callback) {
14
- super({ mapWritable, eagerOpen: true })
15
-
16
- this.written = 0
17
- this.header = header
18
-
19
- this._callback = callback
20
- this._linkname = null
21
- this._isLinkname = header.type === 'symlink' && !header.linkname
22
- this._isVoid = header.type !== 'file' && header.type !== 'contiguous-file'
23
- this._finished = false
24
- this._pack = pack
25
- this._openCallback = null
26
-
27
- if (this._pack._stream === null) this._pack._stream = this
28
- else this._pack._pending.push(this)
29
- }
30
-
31
- _open (cb) {
32
- this._openCallback = cb
33
- if (this._pack._stream === this) this._continueOpen()
34
- }
35
-
36
- _continuePack (err) {
37
- if (this._callback === null) return
38
-
39
- const callback = this._callback
40
- this._callback = null
41
-
42
- callback(err)
43
- }
44
-
45
- _continueOpen () {
46
- if (this._pack._stream === null) this._pack._stream = this
47
-
48
- const cb = this._openCallback
49
- this._openCallback = null
50
- if (cb === null) return
51
-
52
- if (this._pack.destroying) return cb(new Error('pack stream destroyed'))
53
- if (this._pack._finalized) return cb(new Error('pack stream is already finalized'))
54
-
55
- this._pack._stream = this
56
-
57
- if (!this._isLinkname) {
58
- this._pack._encode(this.header)
59
- }
60
-
61
- if (this._isVoid) {
62
- this._finish()
63
- this._continuePack(null)
64
- }
65
-
66
- cb(null)
67
- }
68
-
69
- _write (data, cb) {
70
- if (this._isLinkname) {
71
- this._linkname = this._linkname ? b4a.concat([this._linkname, data]) : data
72
- return cb(null)
73
- }
74
-
75
- if (this._isVoid) {
76
- if (data.byteLength > 0) {
77
- return cb(new Error('No body allowed for this entry'))
78
- }
79
- return cb()
80
- }
81
-
82
- this.written += data.byteLength
83
- if (this._pack.push(data)) return cb()
84
- this._pack._drain = cb
85
- }
86
-
87
- _finish () {
88
- if (this._finished) return
89
- this._finished = true
90
-
91
- if (this._isLinkname) {
92
- this.header.linkname = this._linkname ? b4a.toString(this._linkname, 'utf-8') : ''
93
- this._pack._encode(this.header)
94
- }
95
-
96
- overflow(this._pack, this.header.size)
97
-
98
- this._pack._done(this)
99
- }
100
-
101
- _final (cb) {
102
- if (this.written !== this.header.size) { // corrupting tar
103
- return cb(new Error('Size mismatch'))
104
- }
105
-
106
- this._finish()
107
- cb(null)
108
- }
109
-
110
- _getError () {
111
- return getStreamError(this) || new Error('tar entry destroyed')
112
- }
113
-
114
- _predestroy () {
115
- this._pack.destroy(this._getError())
116
- }
117
-
118
- _destroy (cb) {
119
- this._pack._done(this)
120
-
121
- this._continuePack(this._finished ? null : this._getError())
122
-
123
- cb()
124
- }
125
- }
126
-
127
- class Pack extends Readable {
128
- constructor (opts) {
129
- super(opts)
130
- this._drain = noop
131
- this._finalized = false
132
- this._finalizing = false
133
- this._pending = []
134
- this._stream = null
135
- }
136
-
137
- entry (header, buffer, callback) {
138
- if (this._finalized || this.destroying) throw new Error('already finalized or destroyed')
139
-
140
- if (typeof buffer === 'function') {
141
- callback = buffer
142
- buffer = null
143
- }
144
-
145
- if (!callback) callback = noop
146
-
147
- if (!header.size || header.type === 'symlink') header.size = 0
148
- if (!header.type) header.type = modeToType(header.mode)
149
- if (!header.mode) header.mode = header.type === 'directory' ? DMODE : FMODE
150
- if (!header.uid) header.uid = 0
151
- if (!header.gid) header.gid = 0
152
- if (!header.mtime) header.mtime = new Date()
153
-
154
- if (typeof buffer === 'string') buffer = b4a.from(buffer)
155
-
156
- const sink = new Sink(this, header, callback)
157
-
158
- if (b4a.isBuffer(buffer)) {
159
- header.size = buffer.byteLength
160
- sink.write(buffer)
161
- sink.end()
162
- return sink
163
- }
164
-
165
- if (sink._isVoid) {
166
- return sink
167
- }
168
-
169
- return sink
170
- }
171
-
172
- finalize () {
173
- if (this._stream || this._pending.length > 0) {
174
- this._finalizing = true
175
- return
176
- }
177
-
178
- if (this._finalized) return
179
- this._finalized = true
180
-
181
- this.push(END_OF_TAR)
182
- this.push(null)
183
- }
184
-
185
- _done (stream) {
186
- if (stream !== this._stream) return
187
-
188
- this._stream = null
189
-
190
- if (this._finalizing) this.finalize()
191
- if (this._pending.length) this._pending.shift()._continueOpen()
192
- }
193
-
194
- _encode (header) {
195
- if (!header.pax) {
196
- const buf = headers.encode(header)
197
- if (buf) {
198
- this.push(buf)
199
- return
200
- }
201
- }
202
- this._encodePax(header)
203
- }
204
-
205
- _encodePax (header) {
206
- const paxHeader = headers.encodePax({
207
- name: header.name,
208
- linkname: header.linkname,
209
- pax: header.pax
210
- })
211
-
212
- const newHeader = {
213
- name: 'PaxHeader',
214
- mode: header.mode,
215
- uid: header.uid,
216
- gid: header.gid,
217
- size: paxHeader.byteLength,
218
- mtime: header.mtime,
219
- type: 'pax-header',
220
- linkname: header.linkname && 'PaxHeader',
221
- uname: header.uname,
222
- gname: header.gname,
223
- devmajor: header.devmajor,
224
- devminor: header.devminor
225
- }
226
-
227
- this.push(headers.encode(newHeader))
228
- this.push(paxHeader)
229
- overflow(this, paxHeader.byteLength)
230
-
231
- newHeader.size = header.size
232
- newHeader.type = header.type
233
- this.push(headers.encode(newHeader))
234
- }
235
-
236
- _doDrain () {
237
- const drain = this._drain
238
- this._drain = noop
239
- drain()
240
- }
241
-
242
- _predestroy () {
243
- const err = getStreamError(this)
244
-
245
- if (this._stream) this._stream.destroy(err)
246
-
247
- while (this._pending.length) {
248
- const stream = this._pending.shift()
249
- stream.destroy(err)
250
- stream._continueOpen()
251
- }
252
-
253
- this._doDrain()
254
- }
255
-
256
- _read (cb) {
257
- this._doDrain()
258
- cb()
259
- }
260
- }
261
-
262
- module.exports = function pack (opts) {
263
- return new Pack(opts)
264
- }
265
-
266
- function modeToType (mode) {
267
- switch (mode & constants.S_IFMT) {
268
- case constants.S_IFBLK: return 'block-device'
269
- case constants.S_IFCHR: return 'character-device'
270
- case constants.S_IFDIR: return 'directory'
271
- case constants.S_IFIFO: return 'fifo'
272
- case constants.S_IFLNK: return 'symlink'
273
- }
274
-
275
- return 'file'
276
- }
277
-
278
- function noop () {}
279
-
280
- function overflow (self, size) {
281
- size &= 511
282
- if (size) self.push(END_OF_TAR.subarray(0, 512 - size))
283
- }
284
-
285
- function mapWritable (buf) {
286
- return b4a.isBuffer(buf) ? buf : b4a.from(buf)
287
- }
@@ -1,35 +0,0 @@
1
- {
2
- "name": "tar-stream",
3
- "version": "3.1.6",
4
- "description": "tar-stream is a streaming tar parser and generator and nothing else. It operates purely using streams which means you can easily extract/parse tarballs without ever hitting the file system.",
5
- "main": "index.js",
6
- "files": [
7
- "*.js"
8
- ],
9
- "browser": {
10
- "fs": false
11
- },
12
- "scripts": {
13
- "test": "standard && brittle test/*.js"
14
- },
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/mafintosh/tar-stream.git"
18
- },
19
- "author": "Mathias Buus <mathiasbuus@gmail.com>",
20
- "license": "MIT",
21
- "bugs": {
22
- "url": "https://github.com/mafintosh/tar-stream/issues"
23
- },
24
- "homepage": "https://github.com/mafintosh/tar-stream",
25
- "dependencies": {
26
- "b4a": "^1.6.4",
27
- "fast-fifo": "^1.2.0",
28
- "streamx": "^2.15.0"
29
- },
30
- "devDependencies": {
31
- "brittle": "^3.3.2",
32
- "concat-stream": "^2.0.0",
33
- "standard": "^17.0.1"
34
- }
35
- }
@@ -1 +0,0 @@
1
- {"name":"tar-fs","version":"3.0.4","description":"filesystem bindings for tar-stream","dependencies":{"mkdirp-classic":"^0.5.2","pump":"^3.0.0","tar-stream":"^3.1.5"},"files":["index.js"],"standard":{"ignore":["test/fixtures/**"]},"keywords":["tar","fs","file","tarball","directory","stream"],"devDependencies":{"brittle":"^3.1.3","rimraf":"^2.6.3","standard":"^17.0.1"},"scripts":{"test":"standard && brittle test/index.js"},"bugs":{"url":"https://github.com/mafintosh/tar-fs/issues"},"homepage":"https://github.com/mafintosh/tar-fs","main":"index.js","directories":{"test":"test"},"author":"Mathias Buus","license":"MIT","repository":{"type":"git","url":"https://github.com/mafintosh/tar-fs.git"},"_lastModified":"2024-07-10T04:54:55.770Z"}
@@ -1,9 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
- export { default } from './plugin';
@@ -1,42 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- var __create = Object.create;
11
- var __defProp = Object.defineProperty;
12
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
- var __getOwnPropNames = Object.getOwnPropertyNames;
14
- var __getProtoOf = Object.getPrototypeOf;
15
- var __hasOwnProp = Object.prototype.hasOwnProperty;
16
- var __export = (target, all) => {
17
- for (var name in all)
18
- __defProp(target, name, { get: all[name], enumerable: true });
19
- };
20
- var __copyProps = (to, from, except, desc) => {
21
- if (from && typeof from === "object" || typeof from === "function") {
22
- for (let key of __getOwnPropNames(from))
23
- if (!__hasOwnProp.call(to, key) && key !== except)
24
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
- }
26
- return to;
27
- };
28
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
- // If the importer is in node compatibility mode or this is not an ESM
30
- // file that has been converted to a CommonJS file using a Babel-
31
- // compatible transform (i.e. "__esModule" has not been set), then set
32
- // "default" to the CommonJS "module.exports" for node compatibility.
33
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
- mod
35
- ));
36
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
- var server_exports = {};
38
- __export(server_exports, {
39
- default: () => import_plugin.default
40
- });
41
- module.exports = __toCommonJS(server_exports);
42
- var import_plugin = __toESM(require("./plugin"));
@@ -1,19 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
- import { InstallOptions, Plugin } from '@nocobase/server';
10
- export declare class PluginLoggerServer extends Plugin {
11
- afterAdd(): void;
12
- beforeLoad(): void;
13
- load(): Promise<void>;
14
- install(options?: InstallOptions): Promise<void>;
15
- afterEnable(): Promise<void>;
16
- afterDisable(): Promise<void>;
17
- remove(): Promise<void>;
18
- }
19
- export default PluginLoggerServer;
@@ -1,70 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- var __create = Object.create;
11
- var __defProp = Object.defineProperty;
12
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
- var __getOwnPropNames = Object.getOwnPropertyNames;
14
- var __getProtoOf = Object.getPrototypeOf;
15
- var __hasOwnProp = Object.prototype.hasOwnProperty;
16
- var __export = (target, all) => {
17
- for (var name in all)
18
- __defProp(target, name, { get: all[name], enumerable: true });
19
- };
20
- var __copyProps = (to, from, except, desc) => {
21
- if (from && typeof from === "object" || typeof from === "function") {
22
- for (let key of __getOwnPropNames(from))
23
- if (!__hasOwnProp.call(to, key) && key !== except)
24
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
- }
26
- return to;
27
- };
28
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
- // If the importer is in node compatibility mode or this is not an ESM
30
- // file that has been converted to a CommonJS file using a Babel-
31
- // compatible transform (i.e. "__esModule" has not been set), then set
32
- // "default" to the CommonJS "module.exports" for node compatibility.
33
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
- mod
35
- ));
36
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
- var plugin_exports = {};
38
- __export(plugin_exports, {
39
- PluginLoggerServer: () => PluginLoggerServer,
40
- default: () => plugin_default
41
- });
42
- module.exports = __toCommonJS(plugin_exports);
43
- var import_server = require("@nocobase/server");
44
- var import_logger = __toESM(require("./resourcer/logger"));
45
- class PluginLoggerServer extends import_server.Plugin {
46
- afterAdd() {
47
- }
48
- beforeLoad() {
49
- }
50
- async load() {
51
- this.app.resource(import_logger.default);
52
- this.app.acl.registerSnippet({
53
- name: `pm.${this.name}.logger`,
54
- actions: ["logger:*"]
55
- });
56
- }
57
- async install(options) {
58
- }
59
- async afterEnable() {
60
- }
61
- async afterDisable() {
62
- }
63
- async remove() {
64
- }
65
- }
66
- var plugin_default = PluginLoggerServer;
67
- // Annotate the CommonJS export names for ESM import in node:
68
- 0 && (module.exports = {
69
- PluginLoggerServer
70
- });
@@ -1,18 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
- import { Context, Next } from '@nocobase/actions';
10
- declare const _default: {
11
- name: string;
12
- actions: {
13
- list: (ctx: Context, next: Next) => Promise<void>;
14
- download: (ctx: Context, next: Next) => Promise<void>;
15
- collect: (ctx: Context, next: Next) => Promise<void>;
16
- };
17
- };
18
- export default _default;
@@ -1,182 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
- var __create = Object.create;
11
- var __defProp = Object.defineProperty;
12
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
- var __getOwnPropNames = Object.getOwnPropertyNames;
14
- var __getProtoOf = Object.getPrototypeOf;
15
- var __hasOwnProp = Object.prototype.hasOwnProperty;
16
- var __export = (target, all) => {
17
- for (var name in all)
18
- __defProp(target, name, { get: all[name], enumerable: true });
19
- };
20
- var __copyProps = (to, from, except, desc) => {
21
- if (from && typeof from === "object" || typeof from === "function") {
22
- for (let key of __getOwnPropNames(from))
23
- if (!__hasOwnProp.call(to, key) && key !== except)
24
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
- }
26
- return to;
27
- };
28
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
- // If the importer is in node compatibility mode or this is not an ESM
30
- // file that has been converted to a CommonJS file using a Babel-
31
- // compatible transform (i.e. "__esModule" has not been set), then set
32
- // "default" to the CommonJS "module.exports" for node compatibility.
33
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
- mod
35
- ));
36
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
- var logger_exports = {};
38
- __export(logger_exports, {
39
- default: () => logger_default
40
- });
41
- module.exports = __toCommonJS(logger_exports);
42
- var import_logger = require("@nocobase/logger");
43
- var import_promises = require("fs/promises");
44
- var import_path = require("path");
45
- var import_stream = __toESM(require("stream"));
46
- var import_tar_fs = require("tar-fs");
47
- var import_zlib = __toESM(require("zlib"));
48
- var import_lodash = __toESM(require("lodash"));
49
- const envVars = [
50
- "APP_ENV",
51
- "APP_PORT",
52
- "API_BASE_PATH",
53
- "API_BASE_URL",
54
- "DB_DIALECT",
55
- "DB_TABLE_PREFIX",
56
- "DB_UNDERSCORED",
57
- "DB_TIMEZONE",
58
- "DB_LOGGING",
59
- "LOGGER_TRANSPORT",
60
- "LOGGER_LEVEL"
61
- ];
62
- const getLastestLogs = async (path) => {
63
- const files = await (0, import_promises.readdir)(path);
64
- const prefixes = ["request", "sql", "system", "system_error"];
65
- const logs = files.filter((file) => file.endsWith(".log") && prefixes.some((prefix) => file.startsWith(prefix)));
66
- if (!logs.length) {
67
- return [];
68
- }
69
- const mtime = async (file) => {
70
- const info = await (0, import_promises.stat)((0, import_path.join)(path, file));
71
- return [file, info.mtime];
72
- };
73
- const logsWithTime = await Promise.all(logs.map(mtime));
74
- const getLatestLog = (prefix) => {
75
- const logs2 = logsWithTime.filter((file) => file[0].startsWith(prefix));
76
- if (!logs2.length) {
77
- return null;
78
- }
79
- return logs2.reduce((a, b) => a[1] > b[1] ? a : b)[0];
80
- };
81
- return prefixes.map(getLatestLog).filter((file) => file);
82
- };
83
- const tarFiles = (path, files) => {
84
- return new Promise((resolve, reject) => {
85
- const passthrough = new import_stream.default.PassThrough();
86
- const gz = import_zlib.default.createGzip();
87
- (0, import_tar_fs.pack)(path, {
88
- entries: files
89
- }).on("data", (chunk) => {
90
- passthrough.write(chunk);
91
- }).on("end", () => {
92
- passthrough.end();
93
- }).on("error", (err) => reject(err));
94
- passthrough.on("data", (chunk) => {
95
- gz.write(chunk);
96
- }).on("end", () => {
97
- gz.end();
98
- resolve(gz);
99
- }).on("error", (err) => reject(err));
100
- gz.on("error", (err) => reject(err));
101
- });
102
- };
103
- var logger_default = {
104
- name: "logger",
105
- actions: {
106
- list: async (ctx, next) => {
107
- const path = (0, import_logger.getLoggerFilePath)(ctx.app.name || "main");
108
- const readDir = async (path2) => {
109
- const fileTree = [];
110
- try {
111
- const files2 = await (0, import_promises.readdir)(path2, { withFileTypes: true });
112
- for (const file of files2) {
113
- if (file.isDirectory()) {
114
- const subFiles = await readDir((0, import_path.join)(path2, file.name));
115
- if (!subFiles.length) {
116
- continue;
117
- }
118
- fileTree.push({
119
- name: file.name,
120
- files: subFiles
121
- });
122
- } else if (file.name.endsWith(".log")) {
123
- fileTree.push(file.name);
124
- }
125
- }
126
- return fileTree;
127
- } catch (err) {
128
- ctx.log.error("readDir error", { err, path: path2 });
129
- return [];
130
- }
131
- };
132
- const files = await readDir(path);
133
- ctx.body = files;
134
- await next();
135
- },
136
- download: async (ctx, next) => {
137
- const path = (0, import_logger.getLoggerFilePath)(ctx.app.name || "main");
138
- let { files = [] } = ctx.action.params.values || {};
139
- const invalid = files.some((file) => !file.endsWith(".log"));
140
- if (invalid) {
141
- ctx.throw(400, ctx.t("Invalid file type: ") + invalid);
142
- }
143
- files = files.map((file) => {
144
- if (file.startsWith("/")) {
145
- return file.slice(1);
146
- }
147
- return file;
148
- });
149
- try {
150
- ctx.attachment("logs.tar.gz");
151
- ctx.body = await tarFiles(path, files);
152
- } catch (err) {
153
- ctx.log.error(`download error: ${err.message}`, { files, err: err.stack });
154
- ctx.throw(500, ctx.t("Download logs failed."));
155
- }
156
- await next();
157
- },
158
- collect: async (ctx, next) => {
159
- const { error, ...info } = ctx.action.params.values || {};
160
- const { message, ...e } = error || {};
161
- ctx.log.error({ message: `Diagnosis, frontend error, ${message}`, ...e });
162
- ctx.log.error(`Diagnostic information`, info);
163
- ctx.log.error("Diagnosis, environment variables", import_lodash.default.pick(process.env, envVars));
164
- const path = (0, import_logger.getLoggerFilePath)(ctx.app.name || "main");
165
- const files = await getLastestLogs(path);
166
- if (!files.length) {
167
- ctx.throw(
168
- 404,
169
- ctx.t("No log files found. Please check the LOGGER_TRANSPORTS environment variable configuration.")
170
- );
171
- }
172
- try {
173
- ctx.attachment("logs.tar.gz");
174
- ctx.body = await tarFiles(path, files);
175
- } catch (err) {
176
- ctx.log.error(`download error: ${err.message}`, { files, err: err.stack });
177
- ctx.throw(500, ctx.t("Download logs failed."));
178
- }
179
- await next();
180
- }
181
- }
182
- };