YARN-7641. Allow searchable filter for Application page log viewer in new YARN UI. Contributed by Vasudevan Skm. This closes #312.

This commit is contained in:
Sunil G 2017-12-13 15:51:49 +05:30
parent 7efc4f7688
commit fa4ecd8b98
3 changed files with 144 additions and 98 deletions

View File

@ -22,90 +22,120 @@ export default Ember.Controller.extend({
queryParams: ["service"], queryParams: ["service"],
service: undefined, service: undefined,
selectedAttemptId: '', selectedAttemptId: "",
attemptContainerList: null, attemptContainerList: null,
selectedContainerId: '', selectedContainerId: "",
selectedLogFileName: '', selectedLogFileName: "",
containerLogFiles: null, containerLogFiles: null,
selectedLogFileContent: '', selectedLogFileContent: "",
_isLoadingTopPanel: false, _isLoadingTopPanel: false,
_isLoadingBottomPanel: false, _isLoadingBottomPanel: false,
initializeSelect: function(selector = ".js-fetch-attempt-containers") {
Ember.run.schedule("afterRender", this, function() {
$(selector).select2({ width: "350px", multiple: false });
});
},
actions: { actions: {
showContainersForAttemptId(attemptId) { showContainersForAttemptId(attemptId) {
this.set('selectedAttemptId', ''); this.set("selectedAttemptId", "");
if (attemptId) { if (attemptId) {
this.set('_isLoadingTopPanel', true); this.set("_isLoadingTopPanel", true);
this.set('selectedAttemptId', attemptId); this.set("selectedAttemptId", attemptId);
this.fetchContainersForAttemptId(attemptId).then((hash) => { this.fetchContainersForAttemptId(attemptId)
let containers = null; .then(hash => {
if (hash.rmContainers.get('length') > 0 && hash.rmContainers.get('content')) { let containers = null;
containers = (containers || []).concat(hash.rmContainers.get('content')); if (
} hash.rmContainers.get("length") > 0 &&
if (hash.tsContainers.get('length') > 0 && hash.tsContainers.get('content')) { hash.rmContainers.get("content")
containers = (containers || []).concat(hash.tsContainers.get('content')); ) {
} containers = (containers || []).concat(
this.set('attemptContainerList', containers); hash.rmContainers.get("content")
}).finally(() => { );
this.set('_isLoadingTopPanel', false); }
}); if (
hash.tsContainers.get("length") > 0 &&
hash.tsContainers.get("content")
) {
containers = (containers || []).concat(
hash.tsContainers.get("content")
);
}
this.set("attemptContainerList", containers);
this.initializeSelect(".js-fetch-logs-containers");
})
.finally(() => {
this.set("_isLoadingTopPanel", false);
});
} else { } else {
this.set('attemptContainerList', null); this.set("attemptContainerList", null);
this.set('selectedContainerId', ''); this.set("selectedContainerId", "");
this.set('containerLogFiles', null); this.set("containerLogFiles", null);
this.set('selectedLogFileName', ''); this.set("selectedLogFileName", "");
this.set('selectedLogFileContent', ''); this.set("selectedLogFileContent", "");
} }
}, },
showLogFilesForContainerId(containerId) { showLogFilesForContainerId(containerId) {
this.set('selectedContainerId', ''); this.set("selectedContainerId", "");
this.set('containerLogFiles', null); this.set("containerLogFiles", null);
this.set('selectedLogFileName', ''); this.set("selectedLogFileName", "");
this.set('selectedLogFileContent', ''); this.set("selectedLogFileContent", "");
if (containerId) { if (containerId) {
this.set('_isLoadingBottomPanel', true); this.set("_isLoadingBottomPanel", true);
this.set('selectedContainerId', containerId); this.set("selectedContainerId", containerId);
this.fetchLogFilesForContainerId(containerId).then((hash) => { this.fetchLogFilesForContainerId(containerId)
if (hash.logs.get('length') > 0) { .then(hash => {
this.set('containerLogFiles', hash.logs); if (hash.logs.get("length") > 0) {
} else { this.set("containerLogFiles", hash.logs);
this.set('containerLogFiles', null); } else {
} this.set("containerLogFiles", null);
}).finally(() => { }
this.set('_isLoadingBottomPanel', false); this.initializeSelect(".js-fetch-log-for-container");
}); })
.finally(() => {
this.set("_isLoadingBottomPanel", false);
});
} }
}, },
showContentForLogFile(logFile) { showContentForLogFile(logFile) {
this.set('selectedLogFileName', ''); this.set("selectedLogFileName", "");
Ember.$("#logContentTextArea1234554321").val(''); Ember.$("#logContentTextArea1234554321").val("");
this.set('showFullLog', false); this.set("showFullLog", false);
if (logFile) { if (logFile) {
this.set('_isLoadingBottomPanel', true); this.set("_isLoadingBottomPanel", true);
this.set('selectedLogFileName', logFile); this.set("selectedLogFileName", logFile);
this.fetchContentForLogFile(this.get('selectedContainerId'), logFile).then((content) => { this.fetchContentForLogFile(this.get("selectedContainerId"), logFile)
this.set('selectedLogFileContent', content.trim()); .then(
}, () => { content => {
this.set('selectedLogFileContent', ''); this.set("selectedLogFileContent", content.trim());
}).always(() => { },
this.set('_isLoadingBottomPanel', false); () => {
}); this.set("selectedLogFileContent", "");
}
)
.always(() => {
this.set("_isLoadingBottomPanel", false);
});
} else { } else {
this.set('selectedLogFileContent', ''); this.set("selectedLogFileContent", "");
} }
}, },
findNextTextInLogContent() { findNextTextInLogContent() {
let searchInputElem = document.getElementById('logSeachInput98765'); let searchInputElem = document.getElementById("logSeachInput98765");
this.send('searchTextInLogContent', searchInputElem.value); this.send("searchTextInLogContent", searchInputElem.value);
}, },
searchTextInLogContent(searchText) { searchTextInLogContent(searchText) {
Ember.$('body').scrollTop(278); Ember.$("body").scrollTop(278);
let textAreaElem = document.getElementById('logContentTextArea1234554321'); let textAreaElem = document.getElementById(
"logContentTextArea1234554321"
);
let logContent = textAreaElem.innerText; let logContent = textAreaElem.innerText;
let startIndex = this.searchTextStartIndex || 0; let startIndex = this.searchTextStartIndex || 0;
if (startIndex === -1) { if (startIndex === -1) {
@ -130,75 +160,86 @@ export default Ember.Controller.extend({
selection.removeAllRanges(); selection.removeAllRanges();
selection.addRange(range); selection.addRange(range);
} }
this.searchTextStartIndex = logContent.indexOf(searchText, endIndex + 1); this.searchTextStartIndex = logContent.indexOf(
searchText,
endIndex + 1
);
} else { } else {
this.searchTextStartIndex = 0; this.searchTextStartIndex = 0;
} }
}, },
showFullLogFileContent() { showFullLogFileContent() {
this.set('showFullLog', true); this.set("showFullLog", true);
this.notifyPropertyChange('selectedLogFileContent'); this.notifyPropertyChange("selectedLogFileContent");
} }
}, },
attemptList: Ember.computed('model.attempts', function() { attemptList: Ember.computed("model.attempts", function() {
let attempts = this.get('model.attempts'); let attempts = this.get("model.attempts");
let list = null; let list = null;
if (attempts && attempts.get('length') && attempts.get('content')) { if (attempts && attempts.get("length") && attempts.get("content")) {
list = [].concat(attempts.get('content')); list = [].concat(attempts.get("content"));
} }
return list; return list;
}), }),
fetchContainersForAttemptId(attemptId) { fetchContainersForAttemptId(attemptId) {
return Ember.RSVP.hash({ return Ember.RSVP.hash({
rmContainers: this.store.query('yarn-container', { rmContainers: this.store
app_attempt_id: attemptId .query("yarn-container", {
}).catch(function() { app_attempt_id: attemptId
return Ember.A(); })
}), .catch(function() {
tsContainers: this.store.query('yarn-timeline-container', { return Ember.A();
app_attempt_id: attemptId }),
}).catch(function() { tsContainers: this.store
return Ember.A(); .query("yarn-timeline-container", {
}) app_attempt_id: attemptId
})
.catch(function() {
return Ember.A();
})
}); });
}, },
fetchLogFilesForContainerId(containerId) { fetchLogFilesForContainerId(containerId) {
return Ember.RSVP.hash({ return Ember.RSVP.hash({
logs: this.store.query('yarn-log', { logs: this.store
containerId: containerId .query("yarn-log", {
}).catch(function() { containerId: containerId
return Ember.A(); })
}) .catch(function() {
return Ember.A();
})
}); });
}, },
fetchContentForLogFile(containerId, logFile) { fetchContentForLogFile(containerId, logFile) {
let logAdapter = this.store.adapterFor('yarn-log'); let logAdapter = this.store.adapterFor("yarn-log");
return logAdapter.fetchLogFileContent(containerId, logFile); return logAdapter.fetchLogFileContent(containerId, logFile);
}, },
resetAfterRefresh() { resetAfterRefresh() {
this.set('selectedAttemptId', ''); this.set("selectedAttemptId", "");
this.set('attemptContainerList', null); this.set("attemptContainerList", null);
this.set('selectedContainerId', ''); this.set("selectedContainerId", "");
this.set('selectedLogFileName', ''); this.set("selectedLogFileName", "");
this.set('containerLogFiles', null); this.set("containerLogFiles", null);
this.set('selectedLogFileContent', ''); this.set("selectedLogFileContent", "");
}, },
showFullLog: false, showFullLog: false,
showLastFewLinesOfLogContent: Ember.computed('selectedLogFileContent', function() { showLastFewLinesOfLogContent: Ember.computed(
let content = this.get('selectedLogFileContent'); "selectedLogFileContent",
let lines = content.split('\n'); function() {
if (this.get('showFullLog') || lines.length < 10) { let content = this.get("selectedLogFileContent");
return content; let lines = content.split("\n");
if (this.get("showFullLog") || lines.length < 10) {
return content;
}
return lines.slice(lines.length - 10).join("\n");
} }
return lines.slice(lines.length - 10).join('\n'); )
})
}); });

View File

@ -34,6 +34,11 @@ export default AbstractRoute.extend(AppAttemptMixin, {
}); });
}, },
activate() {
const controller = this.controllerFor("yarn-app.logs");
controller.initializeSelect();
},
unloadAll() { unloadAll() {
this.store.unloadAll('yarn-app-attempt'); this.store.unloadAll('yarn-app-attempt');
this.store.unloadAll('yarn-timeline-appattempt'); this.store.unloadAll('yarn-timeline-appattempt');

View File

@ -32,7 +32,7 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<label>Choose attempt to fetch containers</label> <label>Choose attempt to fetch containers</label>
<select class="form-control" onchange={{action "showContainersForAttemptId" value="target.value"}} style="max-width:350px;"> <select class="js-fetch-attempt-containers" onchange={{action "showContainersForAttemptId" value="target.value"}} style="max-width:350px;">
<option value="" selected={{eq selectedAttemptId ''}}>None</option> <option value="" selected={{eq selectedAttemptId ''}}>None</option>
{{#each attemptList as |attempt|}} {{#each attemptList as |attempt|}}
<option value="{{attempt.id}}" selected={{eq selectedAttemptId attempt.id}}>{{attempt.id}}</option> <option value="{{attempt.id}}" selected={{eq selectedAttemptId attempt.id}}>{{attempt.id}}</option>
@ -42,7 +42,7 @@
{{#if attemptContainerList}} {{#if attemptContainerList}}
<div class="col-md-6"> <div class="col-md-6">
<label>Choose container to fetch logs</label> <label>Choose container to fetch logs</label>
<select class="form-control" onchange={{action "showLogFilesForContainerId" value="target.value"}} style="max-width:350px"> <select class="js-fetch-logs-containers" onchange={{action "showLogFilesForContainerId" value="target.value"}} style="max-width:350px">
<option value="" selected={{eq selectedContainerId ''}}>None</option> <option value="" selected={{eq selectedContainerId ''}}>None</option>
{{#each attemptContainerList as |container|}} {{#each attemptContainerList as |container|}}
<option value="{{container.id}}" selected={{eq selectedContainerId container.id}}>{{container.id}}</option> <option value="{{container.id}}" selected={{eq selectedContainerId container.id}}>{{container.id}}</option>
@ -84,7 +84,7 @@
<div class="row"> <div class="row">
<div class="col-md-6" style="margin-bottom:20px;"> <div class="col-md-6" style="margin-bottom:20px;">
<label>Choose log for {{selectedContainerId}}</label> <label>Choose log for {{selectedContainerId}}</label>
<select class="form-control" onchange={{action "showContentForLogFile" value="target.value"}} style="max-width:350px"> <select class="js-fetch-log-for-container" onchange={{action "showContentForLogFile" value="target.value"}} style="max-width:350px">
<option value="" selected={{eq selectedLogFileName ''}}>None</option> <option value="" selected={{eq selectedLogFileName ''}}>None</option>
{{#each containerLogFiles as |file|}} {{#each containerLogFiles as |file|}}
<option value="{{file.fileName}}" selected={{eq selectedLogFileName file.fileName}}>{{file.fileName}} - {{file.fileSize}} bytes</option> <option value="{{file.fileName}}" selected={{eq selectedLogFileName file.fileName}}>{{file.fileName}} - {{file.fileSize}} bytes</option>
@ -108,10 +108,10 @@
</div> </div>
{{/if}} {{/if}}
</div> </div>
<div class="row"> <div>
{{#if selectedLogFileContent}} {{#if selectedLogFileContent}}
{{#unless showFullLog}} {{#unless showFullLog}}
<div class="col-md-12"> <div>
<strong>Showing last 10 lines of log. Click <a href="#" {{action "showFullLogFileContent"}}>here</a> for full log.</strong> <strong>Showing last 10 lines of log. Click <a href="#" {{action "showFullLogFileContent"}}>here</a> for full log.</strong>
</div> </div>
{{/unless}} {{/unless}}