Use the stream decode util and never opt to use the plain query param

This commit is contained in:
Michael Lange 2019-06-26 14:52:41 -07:00
parent 862d6f6da6
commit c3b33b8420
5 changed files with 37 additions and 37 deletions

View file

@ -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');

View file

@ -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);
}
}

View file

@ -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);
}
}
});

View file

@ -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');

View file

@ -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(() => {