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