diff --git a/data/web/log/script.js b/data/web/log/script.js new file mode 100644 index 0000000000..fea743117f --- /dev/null +++ b/data/web/log/script.js @@ -0,0 +1,128 @@ +var levels = ['debug', 'info', 'warning', 'error', 'fatal']; +var filterLevel = 0; + +function insertAfter(newNode, referenceNode) { + referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); +} + +function remove(node) { + node.parentNode.removeChild(node); +} + +function scrollTo(selector) { + var element = document.querySelector(selector); + if (element && element.scrollIntoView) { + element.scrollIntoView(); + } +} + +function getLevel(element) { + return levels.findIndex(function (levelString, level) { + var className = 'log-level-' + levelString; + if (element.classList.contains(className)) { + return true; + } + }); +} + +function pluralize(nItems, singular, plural) { + if (nItems === 1) { + return [1, singular].join(' '); + } + plural = plural || [singular, 's'].join(''); + return [nItems.toString(), plural].join(' '); +} + +function scrollLink(content, selector) { + var html = '' + content + ""; + return html; +} + +function getSummary() { + var nFatals = document.getElementsByClassName('log-level-fatal').length; + var nErrors = document.getElementsByClassName('log-level-error').length; + var nWarnings = document.getElementsByClassName('log-level-warning').length; + + if (nFatals > 0) { + return '' + scrollLink(pluralize(nFatals, 'fatal error'), '.log-level-fatal') + + ', ' + scrollLink(pluralize(nErrors, 'other error'), '.log-level-error') + ' and ' + scrollLink(pluralize(nWarnings, 'warning'), '.log-level-warning') + ''; + } else if (nErrors > 0) { + return '' + scrollLink(pluralize(nErrors, 'error'), '.log-level-error') + ' and ' + + scrollLink(pluralize(nWarnings, 'warning'), '.log-level-warning') + ''; + } else if (nWarnings > 0) { + return '' + scrollLink(pluralize(nWarnings, 'warning'), '.log-level-warning') + ''; + } else { + return 'No errors or warnings'; + } +} + +function updateFilter() { + var table = document.getElementsByTagName('table')[0]; + table.classList.remove('hidden'); + + var noMessages = document.getElementById('no-messages'); + if (noMessages) { + remove(noMessages); + } + + var rows = document.getElementsByTagName('tr'); + var nShown = 0; + [].forEach.call(rows, function (row) { + if (row.classList.length === 0) { + return; + } + var rowLevel = getLevel(row); + if (rowLevel >= filterLevel) { + row.classList.remove('hidden'); + nShown++; + } else { + row.classList.add('hidden'); + } + }); + if (nShown === 0) { + var select = document.getElementsByTagName('select')[0]; + var p = document.createElement("p"); + p.id = "no-messages"; + p.innerHTML = "There are no log messages with the level '" + levels[filterLevel] + "' or higher."; + insertAfter(p, select); + table.classList.add('hidden'); + } +} + +window.onload = function () { + var header = document.getElementsByTagName('h1')[0]; + header.innerHTML = "OpenSpace Log"; + + var summary = document.createElement('p'); + summary.innerHTML = getSummary(); + + var select = document.createElement('select'); + select.id = 'filter-level-selector'; + + var selectLabel = document.createElement('label'); + selectLabel.for = 'filter-level-selector'; + selectLabel.innerHTML = "Lowest log level to show: "; + + levels.forEach(function (level) { + var option = document.createElement('option'); + option.value = level; + option.innerHTML = level; + select.appendChild(option); + }); + + insertAfter(summary, header); + insertAfter(selectLabel, summary); + insertAfter(select, selectLabel); + + var preselectedIndex = levels.indexOf(window.location.hash.slice(1)); + if (preselectedIndex >= 0) { + filterLevel = select.selectedIndex = preselectedIndex; + updateFilter(); + } + + select.onchange = function (evt) { + filterLevel = select.selectedIndex; + updateFilter(); + window.location.hash = '#' + select.options[select.selectedIndex].value; + }; +} \ No newline at end of file diff --git a/data/web/log/style.css b/data/web/log/style.css new file mode 100644 index 0000000000..3aa140b30e --- /dev/null +++ b/data/web/log/style.css @@ -0,0 +1,93 @@ +table { + width: 100%; +} + +td, th { + padding: 4px 15px 3px; +} + +.log-date { + width: 8em; +} + +h1 { + padding-left: 15px; +} + +.hidden { + display: none; +} + +p, label { + margin-left: 15px; + margin-bottom: 15px; +} + +label { + margin-right: 0.5em; +} + +.log-level-debug { + background-color: #bbdda9; + border-bottom: 1px solid #7bc142; + color: #265127; +} +.log-level-debug td:first-child { + border-left: 10px solid #7bc142; +} + +thead, .log-level-info { + color: #333333; + background-color: #ffffff; + border-bottom: 1px solid #eaeaea; +} +.log-level-info td:first-child { + border-left: 10px solid #eaeaea; +} + +thead th:first-child { + border-left 10px solid #fff; +} + +.log-level-warning { + color: #3e3115; + background-color: #fef8c3; + border-bottom: 1px solid #efcd3f; +} +.log-level-warning td:first-child { + border-left: 10px solid #efcd3f; +} + +.log-level-error { + color: #4c1315; + background-color: #fcdcdc; + border-bottom: 1px solid #d66767; +} +.log-level-error td:first-child { + border-left: 10px solid #d66767; +} + +.log-level-fatal { + color: #220f21; + background-color: #ff7dc1; + border-bottom: 1px solid #b84398; +} +.log-level-fatal td:first-child { + border-left: 10px solid #b84398; +} + +.summary { + padding: 5px; +} +.summary-warning { + background-color: #fef8c3; +} +.summary-error { + background-color: #fcdcdc; +} +.summary-fatal { + background-color: #ff7dc1; +} +.summary-ok { + background-color: #bbdda9; +} \ No newline at end of file diff --git a/src/engine/logfactory.cpp b/src/engine/logfactory.cpp index ffc145d95e..c1ec813a07 100644 --- a/src/engine/logfactory.cpp +++ b/src/engine/logfactory.cpp @@ -41,6 +41,10 @@ namespace { const std::string valueHtmlLog = "html"; const std::string valueTextLog = "Text"; + + const std::string BootstrapPath = "${OPENSPACE_DATA}/web/common/bootstrap.min.css"; + const std::string CssPath = "${OPENSPACE_DATA}/web/log/style.css"; + const std::string JsPath = "${OPENSPACE_DATA}/web/log/script.js"; } namespace openspace { @@ -81,13 +85,18 @@ std::unique_ptr createLog(const ghoul::Dictionary& dictiona using LogLevelStamping = ghoul::logging::Log::LogLevelStamping; if (type == valueHtmlLog) { + + std::vector cssFiles{absPath(BootstrapPath), absPath(CssPath)}; + std::vector jsFiles{absPath(JsPath)}; + return std::make_unique( filename, append ? Append::Yes : Append::No, timeStamp ? TimeStamping::Yes : TimeStamping::No, dateStamp ? DateStamping::Yes : DateStamping::No, categoryStamp ? CategoryStamping::Yes : CategoryStamping::No, - logLevelStamp ? LogLevelStamping::Yes : LogLevelStamping::No + logLevelStamp ? LogLevelStamping::Yes : LogLevelStamping::No, + cssFiles, jsFiles ); } else if (type == valueTextLog) {