Use the stream decode util and never opt to use the plain query param
This commit is contained in:
parent
862d6f6da6
commit
c3b33b8420
|
@ -8,6 +8,7 @@ import queryString from 'query-string';
|
|||
import { task } from 'ember-concurrency';
|
||||
import StreamLogger from 'nomad-ui/utils/classes/stream-logger';
|
||||
import PollLogger from 'nomad-ui/utils/classes/poll-logger';
|
||||
import { decode } from 'nomad-ui/utils/stream-frames';
|
||||
import Anser from 'anser';
|
||||
|
||||
const MAX_OUTPUT_LENGTH = 50000;
|
||||
|
@ -73,7 +74,6 @@ const Log = EmberObject.extend(Evented, {
|
|||
const logFetch = this.logFetch;
|
||||
const queryParams = queryString.stringify(
|
||||
assign(this.params, {
|
||||
plain: true,
|
||||
origin: 'start',
|
||||
offset: 0,
|
||||
})
|
||||
|
@ -81,7 +81,8 @@ const Log = EmberObject.extend(Evented, {
|
|||
const url = `${this.url}?${queryParams}`;
|
||||
|
||||
this.stop();
|
||||
let text = yield logFetch(url).then(res => res.text(), fetchFailure(url));
|
||||
const response = yield logFetch(url).then(res => res.text(), fetchFailure(url));
|
||||
let text = decode(response).message;
|
||||
|
||||
if (text && text.length > MAX_OUTPUT_LENGTH) {
|
||||
text = text.substr(0, MAX_OUTPUT_LENGTH);
|
||||
|
@ -95,7 +96,6 @@ const Log = EmberObject.extend(Evented, {
|
|||
const logFetch = this.logFetch;
|
||||
const queryParams = queryString.stringify(
|
||||
assign(this.params, {
|
||||
plain: true,
|
||||
origin: 'end',
|
||||
offset: MAX_OUTPUT_LENGTH,
|
||||
})
|
||||
|
@ -103,7 +103,8 @@ const Log = EmberObject.extend(Evented, {
|
|||
const url = `${this.url}?${queryParams}`;
|
||||
|
||||
this.stop();
|
||||
let text = yield logFetch(url).then(res => res.text(), fetchFailure(url));
|
||||
const response = yield logFetch(url).then(res => res.text(), fetchFailure(url));
|
||||
let text = decode(response).message;
|
||||
|
||||
this.set('tail', text);
|
||||
this.set('logPointer', 'tail');
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import EmberObject from '@ember/object';
|
||||
import { task, timeout } from 'ember-concurrency';
|
||||
import { decode } from 'nomad-ui/utils/stream-frames';
|
||||
import AbstractLogger from './abstract-logger';
|
||||
import { fetchFailure } from './log';
|
||||
|
||||
|
@ -7,9 +8,7 @@ export default EmberObject.extend(AbstractLogger, {
|
|||
interval: 1000,
|
||||
|
||||
start() {
|
||||
return this.poll
|
||||
.linked()
|
||||
.perform();
|
||||
return this.poll.linked().perform();
|
||||
},
|
||||
|
||||
stop() {
|
||||
|
@ -29,15 +28,10 @@ export default EmberObject.extend(AbstractLogger, {
|
|||
let text = yield response.text();
|
||||
|
||||
if (text) {
|
||||
const lines = text.replace(/\}\{/g, '}\n{').split('\n');
|
||||
const frames = lines
|
||||
.map(line => JSON.parse(line))
|
||||
.filter(frame => frame.Data != null && frame.Offset != null);
|
||||
|
||||
if (frames.length) {
|
||||
frames.forEach(frame => (frame.Data = window.atob(frame.Data)));
|
||||
this.set('endOffset', frames[frames.length - 1].Offset);
|
||||
this.write(frames.mapBy('Data').join(''));
|
||||
const { offset, message } = decode(text);
|
||||
if (message) {
|
||||
this.set('endOffset', offset);
|
||||
this.write(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import EmberObject, { computed } from '@ember/object';
|
||||
import { task } from 'ember-concurrency';
|
||||
import TextDecoder from 'nomad-ui/utils/classes/text-decoder';
|
||||
import { decode } from 'nomad-ui/utils/stream-frames';
|
||||
import AbstractLogger from './abstract-logger';
|
||||
import { fetchFailure } from './log';
|
||||
|
||||
|
@ -60,13 +61,10 @@ export default EmberObject.extend(AbstractLogger, {
|
|||
|
||||
// Assuming the logs endpoint never returns nested JSON (it shouldn't), at this
|
||||
// point chunk is a series of valid JSON objects with no delimiter.
|
||||
const lines = chunk.replace(/\}\{/g, '}\n{').split('\n');
|
||||
const frames = lines.map(line => JSON.parse(line)).filter(frame => frame.Data);
|
||||
|
||||
if (frames.length) {
|
||||
frames.forEach(frame => (frame.Data = window.atob(frame.Data)));
|
||||
this.set('endOffset', frames[frames.length - 1].Offset);
|
||||
this.write(frames.mapBy('Data').join(''));
|
||||
const { offset, message } = decode(chunk);
|
||||
if (message) {
|
||||
this.set('endOffset', offset);
|
||||
this.write(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -21,24 +21,23 @@ const commonProps = {
|
|||
serverTimeout: allowedConnectionTime,
|
||||
};
|
||||
|
||||
const logHead = ['HEAD'];
|
||||
const logTail = ['TAIL'];
|
||||
const logHead = [logEncode(['HEAD'], 0)];
|
||||
const logTail = [logEncode(['TAIL'], 0)];
|
||||
const streamFrames = ['one\n', 'two\n', 'three\n', 'four\n', 'five\n'];
|
||||
let streamPointer = 0;
|
||||
let logMode = null;
|
||||
|
||||
module('Integration | Component | task log', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function() {
|
||||
const handler = ({ queryParams }) => {
|
||||
const { origin, offset, plain, follow } = queryParams;
|
||||
|
||||
let frames;
|
||||
let data;
|
||||
|
||||
if (origin === 'start' && offset === '0' && plain && !follow) {
|
||||
if (logMode === 'head') {
|
||||
frames = logHead;
|
||||
} else if (origin === 'end' && plain && !follow) {
|
||||
} else if (logMode === 'tail') {
|
||||
frames = logTail;
|
||||
} else {
|
||||
frames = streamFrames;
|
||||
|
@ -64,6 +63,7 @@ module('Integration | Component | task log', function(hooks) {
|
|||
hooks.afterEach(function() {
|
||||
this.server.shutdown();
|
||||
streamPointer = 0;
|
||||
logMode = null;
|
||||
});
|
||||
|
||||
test('Basic appearance', async function(assert) {
|
||||
|
@ -107,6 +107,7 @@ module('Integration | Component | task log', function(hooks) {
|
|||
});
|
||||
|
||||
test('Clicking Head loads the log head', async function(assert) {
|
||||
logMode = 'head';
|
||||
run.later(run, run.cancelTimers, commonProps.interval);
|
||||
|
||||
this.setProperties(commonProps);
|
||||
|
@ -117,7 +118,7 @@ module('Integration | Component | task log', function(hooks) {
|
|||
await settled();
|
||||
assert.ok(
|
||||
this.server.handledRequests.find(
|
||||
({ queryParams: qp }) => qp.origin === 'start' && qp.plain === 'true' && qp.offset === '0'
|
||||
({ queryParams: qp }) => qp.origin === 'start' && qp.offset === '0'
|
||||
),
|
||||
'Log head request was made'
|
||||
);
|
||||
|
@ -125,6 +126,7 @@ module('Integration | Component | task log', function(hooks) {
|
|||
});
|
||||
|
||||
test('Clicking Tail loads the log tail', async function(assert) {
|
||||
logMode = 'tail';
|
||||
run.later(run, run.cancelTimers, commonProps.interval);
|
||||
|
||||
this.setProperties(commonProps);
|
||||
|
@ -134,9 +136,7 @@ module('Integration | Component | task log', function(hooks) {
|
|||
|
||||
await settled();
|
||||
assert.ok(
|
||||
this.server.handledRequests.find(
|
||||
({ queryParams: qp }) => qp.origin === 'end' && qp.plain === 'true'
|
||||
),
|
||||
this.server.handledRequests.find(({ queryParams: qp }) => qp.origin === 'end'),
|
||||
'Log tail request was made'
|
||||
);
|
||||
assert.equal(find('[data-test-log-cli]').textContent, logTail[0], 'Tail of the log is shown');
|
||||
|
|
|
@ -76,7 +76,7 @@ module('Unit | Util | Log', function(hooks) {
|
|||
|
||||
test('gotoHead builds the correct URL', async function(assert) {
|
||||
const mocks = makeMocks('');
|
||||
const expectedUrl = `${mocks.url}?a=param&another=one&offset=0&origin=start&plain=true`;
|
||||
const expectedUrl = `${mocks.url}?a=param&another=one&offset=0&origin=start`;
|
||||
const log = Log.create(mocks);
|
||||
|
||||
run(() => {
|
||||
|
@ -89,10 +89,11 @@ module('Unit | Util | Log', function(hooks) {
|
|||
const longLog = Array(50001)
|
||||
.fill('a')
|
||||
.join('');
|
||||
const encodedLongLog = `{"Offset":0,"Data":"${window.btoa(longLog)}"}`;
|
||||
const truncationMessage =
|
||||
'\n\n---------- TRUNCATED: Click "tail" to view the bottom of the log ----------';
|
||||
|
||||
const mocks = makeMocks(longLog);
|
||||
const mocks = makeMocks(encodedLongLog);
|
||||
const log = Log.create(mocks);
|
||||
|
||||
run(() => {
|
||||
|
@ -100,7 +101,13 @@ module('Unit | Util | Log', function(hooks) {
|
|||
});
|
||||
|
||||
await settled();
|
||||
assert.ok(log.get('output').toString().endsWith(truncationMessage), 'Truncation message is shown');
|
||||
assert.ok(
|
||||
log
|
||||
.get('output')
|
||||
.toString()
|
||||
.endsWith(truncationMessage),
|
||||
'Truncation message is shown'
|
||||
);
|
||||
assert.equal(
|
||||
log.get('output').toString().length,
|
||||
50000 + truncationMessage.length,
|
||||
|
@ -110,7 +117,7 @@ module('Unit | Util | Log', function(hooks) {
|
|||
|
||||
test('gotoTail builds the correct URL', async function(assert) {
|
||||
const mocks = makeMocks('');
|
||||
const expectedUrl = `${mocks.url}?a=param&another=one&offset=50000&origin=end&plain=true`;
|
||||
const expectedUrl = `${mocks.url}?a=param&another=one&offset=50000&origin=end`;
|
||||
const log = Log.create(mocks);
|
||||
|
||||
run(() => {
|
||||
|
|
Loading…
Reference in a new issue