diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 39fe0122..6cdff8b5 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -819,6 +819,8 @@ logCommands.add(new libCommand.Command({ "slave": { describe: "Query log of given slave", nargs: 1, type: "string", default: null }, "instance": { describe: "Query log of given instance", nargs: 1, type: "string", default: null }, "max-level": { describe: "Maximum log level to return", nargs: 1, type: "string", default: null }, + "limit": { describe: "Max number of entries to return", nargs: 1, type: "number", default: 1000 }, + "start": { describe: "Limit from the start instead of the end", nargs: 0, type: "boolean", default: false }, }); }], handler: async function(args, control) { @@ -835,8 +837,14 @@ logCommands.add(new libCommand.Command({ slave_ids, instance_ids, max_level: args.maxLevel, + limit: args.limit, + order: args.start ? "asc" : "desc", }); + if (!args.start) { + result.log.reverse(); + } + let stdoutLogger = winston.createLogger({ level: "verbose", levels, diff --git a/packages/lib/link/messages.js b/packages/lib/link/messages.js index dbb84455..5cc260d2 100644 --- a/packages/lib/link/messages.js +++ b/packages/lib/link/messages.js @@ -859,6 +859,8 @@ messages.queryLog = new Request({ items: { type: "integer" }, }, "max_level": { type: ["string", "null"] }, + "limit": { type: "integer" }, + "order": { enum: ["asc", "desc"] }, }, responseProperties: { "log": { diff --git a/packages/master/src/ControlConnection.js b/packages/master/src/ControlConnection.js index bf9fecf3..1d2efd49 100644 --- a/packages/master/src/ControlConnection.js +++ b/packages/master/src/ControlConnection.js @@ -456,12 +456,15 @@ class ControlConnection extends BaseConnection { // - The log file is read starting from the beginning let setDuration = lastQueryLogTime.startTimer(); let log = await query({ - order: "asc", + order: message.data.order, limit: Infinity, from: new Date(0), }); log = log.filter(this.constructor.logFilter(message.data)); + if (message.data.limit) { + log = log.slice(0, message.data.limit); + } setDuration(); return { log }; } diff --git a/packages/web_ui/src/components/InstanceConsole.jsx b/packages/web_ui/src/components/InstanceConsole.jsx index fdc0c7f2..30e8f76f 100644 --- a/packages/web_ui/src/components/InstanceConsole.jsx +++ b/packages/web_ui/src/components/InstanceConsole.jsx @@ -65,8 +65,10 @@ export default function InstanceConsole(props) { slave_ids: [], instance_ids: [props.id], max_level: null, + limit: 400, + order: "desc", }).then(result => { - setPastLines(result.log.slice(-400).map((info, index) => formatLog(info, index))); + setPastLines(result.log.map((info, index) => formatLog(info, index)).reverse()); }).catch(err => { setPastLines([{`Error loading log: ${err.message}`}
]); }); diff --git a/test/integration/clusterio.js b/test/integration/clusterio.js index ea92fd4d..072f0180 100644 --- a/test/integration/clusterio.js +++ b/test/integration/clusterio.js @@ -62,6 +62,42 @@ describe("Integration of Clusterio", function() { await connectorB.close(1000, ""); }); }); + + describe("queryLogRequestHandler", function() { + it("should honnor the limit", async function() { + let result = await libLink.messages.queryLog.send(getControl(), { + all: true, + master: false, + slave_ids: [], + instance_ids: [], + max_level: null, + limit: 10, + order: "asc", + }); + assert.equal(result.log.length, 10); + }); + it("should return entries by order", async function() { + let first = await libLink.messages.queryLog.send(getControl(), { + all: true, + master: false, + slave_ids: [], + instance_ids: [], + max_level: null, + limit: 1, + order: "asc", + }); + let last = await libLink.messages.queryLog.send(getControl(), { + all: true, + master: false, + slave_ids: [], + instance_ids: [], + max_level: null, + limit: 1, + order: "desc", + }); + assert(first.log[0].timestamp < last.log[0].timestamp, "first log entry happened after last"); + }); + }); }); describe("clusterioslave", function() {