Add rendering collect bundle files to report tool
This update causes report to automatically generate an index.html file in the report_analysis folder. Point browser to index.html to render the report_analysis graphically. Both Correlated Results and Plugin Results have its sub-items. Clicking items will show corresponding content in the content area. Test Plan: PASS: Verify the current report tool functions is not affected PASS: Verify the index.html is generated in the collect bundle folder PASS: Verify System Info can be read correctly PASS: Verify users can add/remove items in left panel of System Info PASS: Verify Correlated Results and Plugin Results are shown PASS: Verify the subitems of the Results are clickable and shown PASS: Verify the menus are expandable/collapsible PASS: Verify vertical scrollbar is applied when overflow occurs PASS: Verify system info for a selectable list of hosts are displayed PASS: Verify handling of long hostnames PASS: Verify handling of long list of hosts PASS: Verify controller-0 is printed when loading PASS: Verify correlated summary is printed when loading PASS: Verify correlated summary is printed when 'Correlated Results' menu title is selected PASS: Verify correlated results file contents are displayed by clicking on the 'Correlated Results' groups PASS: Verify plugin results summary is printed when 'Plugin Results' menu title is selected PASS: Verify selecting additional hosts adds to that list while deselecting them removes PASS: Verify plugin results file contents can be displayed by clicking on the 'Plugin Results group. PASS: Verify page is refreshed when System Information is clicked PASS: Verify index.html is created for all report bundle pointer options ; -b , -d , -f PASS: Verify index.html is created and included in the report analysis when report is run as part of collect PASS: Verify the generated html and css content has no error in console Story: 2010533 Task: 49191 Change-Id: I3303a9f0f138777f16be0ea34b1f633bdd394ee0 Signed-off-by: Lance Xu <lance.xu@windriver.com>
This commit is contained in:
parent
944f847b43
commit
260d56ad9a
|
@ -6,17 +6,19 @@
|
|||
#
|
||||
########################################################################
|
||||
#
|
||||
# This file contains the Render function
|
||||
# The Rendering tool visualizes the collect bundle and generates index.html file
|
||||
# This file contains the Render function.
|
||||
# The Rendering tool visualizes the collect bundle and generates
|
||||
# an index.html file
|
||||
#
|
||||
########################################################################
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
|
||||
def extract_section(log_contents, start_phrase):
|
||||
"""extract the correlated or plugin content of the summary
|
||||
"""Extract the correlated or plugin content of the summary
|
||||
|
||||
Parameters:
|
||||
log_contents (string): content of the log
|
||||
|
@ -32,7 +34,7 @@ def extract_section(log_contents, start_phrase):
|
|||
|
||||
|
||||
def remove_timestamp(text):
|
||||
"""remove timestamp of summary message
|
||||
"""Remove timestamp of summary message
|
||||
|
||||
Parameters:
|
||||
text (string): the summary message
|
||||
|
@ -51,7 +53,7 @@ def remove_timestamp(text):
|
|||
|
||||
|
||||
def remove_emptyinfo(text):
|
||||
""" remove 'INFO' text of summary message
|
||||
"""Remove 'INFO' text of summary message
|
||||
|
||||
Parameters:
|
||||
text (string): the summary message
|
||||
|
@ -66,7 +68,7 @@ def remove_emptyinfo(text):
|
|||
|
||||
|
||||
def process_section(section, title):
|
||||
"""return text with timestamp and INFO: removed
|
||||
"""Return text with timestamp and INFO: removed
|
||||
|
||||
Parameters:
|
||||
section (string): the message of the correlated/plugins section
|
||||
|
@ -79,7 +81,7 @@ def process_section(section, title):
|
|||
|
||||
|
||||
def classify_node(data):
|
||||
"""classify node type in system_info summary
|
||||
"""Classify node type in system_info summary
|
||||
|
||||
Parameters:
|
||||
data (string): the summary of system_info
|
||||
|
@ -92,7 +94,7 @@ def classify_node(data):
|
|||
|
||||
|
||||
def controller_sort(x):
|
||||
"""sort the controller, place the controller-0 first
|
||||
"""Sort the controller, place the controller-0 first
|
||||
|
||||
Parameters:
|
||||
x (list): list of controller info
|
||||
|
@ -101,7 +103,7 @@ def controller_sort(x):
|
|||
|
||||
|
||||
def html_css():
|
||||
"""static css code of the rendering tool
|
||||
"""Static css code of the rendering tool
|
||||
|
||||
iframe, textarea: the content panel showing information
|
||||
#show-worker: the show more worker button
|
||||
|
@ -193,7 +195,7 @@ def html_css():
|
|||
margin-top: 10px;
|
||||
}}
|
||||
|
||||
.content-item, .content-itemtwo {{
|
||||
.content-item, .content-itemtwo, .content-itemthree {{
|
||||
display: none;
|
||||
}}
|
||||
|
||||
|
@ -218,6 +220,31 @@ def html_css():
|
|||
color: #2F4F4F;
|
||||
}}
|
||||
|
||||
.caret {{
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
color: #00857e;
|
||||
font-weight: bold;
|
||||
}}
|
||||
|
||||
.caret::before {{
|
||||
content: '+';
|
||||
color: #2F4F4F;
|
||||
margin-right: 6px;
|
||||
}}
|
||||
|
||||
.caret-down::before {{
|
||||
color: #2F4F4F;
|
||||
content: '-';
|
||||
}}
|
||||
|
||||
.text-color {{
|
||||
color: #00ada4;
|
||||
}}
|
||||
|
||||
.nested {{ display: none; }}
|
||||
.active {{ display: block; }}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
"""
|
||||
|
@ -225,7 +252,7 @@ def html_css():
|
|||
|
||||
|
||||
def html_script():
|
||||
"""static script code
|
||||
"""Static script code
|
||||
|
||||
Functions:
|
||||
toggleContent: show content in System Info section
|
||||
|
@ -234,6 +261,7 @@ def html_script():
|
|||
showContentStorage: display content of selected storage item
|
||||
showContentWorker: display content of selected worker item
|
||||
showContentTwo: display content of result section
|
||||
toggleTree: show the collect bundle
|
||||
"""
|
||||
html_content_script = """
|
||||
<script>
|
||||
|
@ -323,6 +351,20 @@ def html_script():
|
|||
}}
|
||||
}}
|
||||
|
||||
function showContentThree(event, contentId) {{
|
||||
event.preventDefault();
|
||||
|
||||
const contentItems = document.querySelectorAll('.content-itemthree');
|
||||
contentItems.forEach(item => {{
|
||||
item.style.display = 'none';
|
||||
}});
|
||||
|
||||
const selectedContent = document.getElementById(contentId);
|
||||
if (selectedContent) {{
|
||||
selectedContent.style.display = 'block';
|
||||
}}
|
||||
}}
|
||||
|
||||
function toggleContent(option, menuItem) {{
|
||||
const contentDiv = document.getElementById(option);
|
||||
const icon = menuItem.querySelector('.icon');
|
||||
|
@ -395,6 +437,28 @@ def html_script():
|
|||
}}
|
||||
}}
|
||||
|
||||
function toggleTree() {{
|
||||
var toggler = document.getElementsByClassName('caret');
|
||||
for (var i = 0; i < toggler.length; i++) {{
|
||||
var nested = toggler[i].parentElement.querySelector('.nested');
|
||||
var isEmpty = nested.querySelectorAll('li').length === 0;
|
||||
|
||||
|
||||
if (!isEmpty) {{
|
||||
toggler[i].addEventListener('click', function() {{
|
||||
this.parentElement.querySelector('.nested').classList.toggle('active');
|
||||
this.classList.toggle('caret-down');
|
||||
this.parentElement.classList.toggle('text-color');
|
||||
}});
|
||||
}} else {{
|
||||
toggler[i].style.color = '#808080';
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
|
||||
// Call the function when the page loads to initialize the tree behavior
|
||||
toggleTree();
|
||||
|
||||
</script>
|
||||
</html>
|
||||
"""
|
||||
|
@ -402,7 +466,7 @@ def html_script():
|
|||
|
||||
|
||||
def html_info(sys_section):
|
||||
"""system info part generation
|
||||
"""System info part generation
|
||||
reads from plugin/system_info and show by different types
|
||||
order: controller, storage(if there exists), worker(if there exists)
|
||||
|
||||
|
@ -505,7 +569,7 @@ def html_info(sys_section):
|
|||
|
||||
|
||||
def html_result(log_contents, output_dir):
|
||||
"""result part generation in the menu-content style
|
||||
"""Result part generation in the menu-content style
|
||||
generates correlated results, plugin results, and the items under them
|
||||
subitems for plugins and correlated results under separate menus
|
||||
|
||||
|
@ -575,13 +639,58 @@ def html_result(log_contents, output_dir):
|
|||
html_content_two += f'<div class="content-itemtwo" id="content-item-plugin_results"><h2>Plugin Results</h2><textarea>{plugin_section}</textarea></div>'
|
||||
html_content_two += """
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</div><br>
|
||||
"""
|
||||
|
||||
return html_content_two
|
||||
|
||||
|
||||
def html_collect(output_dir):
|
||||
os.chdir('../../')
|
||||
current_directory = Path('.')
|
||||
tree_html = ""
|
||||
content_html = "<div class='content'>"
|
||||
target_dir = current_directory.resolve()
|
||||
newtree_html, newcontent_html = generate_directory_tree(current_directory, target_dir, True)
|
||||
tree_html += newtree_html
|
||||
content_html += newcontent_html
|
||||
content_html += "</div>"
|
||||
html_content_three = """<div class="container-menu"><div class="menu">
|
||||
""" + tree_html + "</div>" + content_html + "</div></body>"
|
||||
return html_content_three
|
||||
|
||||
|
||||
def generate_directory_tree(directory_path, target_dir, is_top_level=False):
|
||||
directory_name = directory_path.name
|
||||
tree_html = ""
|
||||
content_html = ""
|
||||
approved_list = ['.log', '.conf', '.info', '.json', '.alarm', '.pid', '.list', '.lock', '.txt']
|
||||
if not is_top_level:
|
||||
tree_html = f'<li><span class="caret">{directory_name}</span><ul class="nested">'
|
||||
for item in directory_path.iterdir():
|
||||
try:
|
||||
if item.is_dir() and item.name != "report_analysis":
|
||||
nested_tree_html, nested_content_html = generate_directory_tree(item, target_dir)
|
||||
tree_html += nested_tree_html
|
||||
content_html += nested_content_html
|
||||
elif item.is_file():
|
||||
if os.path.getsize(item) == 0:
|
||||
tree_html += f'<li><a style="color: #808080">{item}</a></li>'
|
||||
else:
|
||||
if item.name.endswith(tuple(approved_list)):
|
||||
tree_html += f'<li><a href="#" class="toggle-sign" onclick="showContentThree(event, \'{item.name}\')">{item.name}</a></li>'
|
||||
content_html += f'<div class="content-itemthree" id="{item.name}"><h2>{item.name}</h2><iframe src="{target_dir}/{item}"></iframe></div>'
|
||||
else:
|
||||
if not item.name.endswith(".tgz"):
|
||||
tree_html += f'<li><a href="../{item}" target="_blank">{item}</a></li>'
|
||||
except PermissionError as e:
|
||||
continue
|
||||
if not is_top_level:
|
||||
tree_html += '</ul></li>'
|
||||
|
||||
return tree_html, content_html
|
||||
|
||||
|
||||
# main
|
||||
def main(input_dir, output_dir):
|
||||
reportlog_path = os.path.join(output_dir, 'report.log')
|
||||
|
@ -596,8 +705,9 @@ def main(input_dir, output_dir):
|
|||
html_file = os.path.abspath(os.path.join(output_dir, 'index.html'))
|
||||
|
||||
sys_section = sysinfo_contents.strip().split("\n\n")
|
||||
html_content = html_css() + html_info(sys_section) + html_result(log_contents, output_dir) + html_script()
|
||||
html_content = html_css() + html_info(sys_section) + html_result(log_contents, output_dir)
|
||||
html_content = html_content.format()
|
||||
html_content += html_collect(output_dir) + html_script()
|
||||
|
||||
# write the HTML content to file
|
||||
with open(html_file, "w") as file:
|
||||
|
|
Loading…
Reference in New Issue