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. The collect bundle will show after the system info and results section. The layout for collect bundle will be the same as the results section. 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 PASS: Verify all collect bundle folders are shown PASS: Verify empty folders are showing grey with disabled click PASS: Verify empty files are showing grey with disabled click PASS: Verify handling of '.log', '.conf', '.info', '.json', '.alarm', '.pid', '.list', '.lock', '.txt' files PASS: Verify handling of files that are not in the above extension PASS: Verify a new window is opened if the file is viewable PASS: Verify a download popup is opened if the file is not viewable PASS: Verify index.html is in a reasonable size PASS: Verify index.html loading time is reasonable PASS: Verify the generated html with css content will bring no error in console Story: 2010533 Task: 49191 Change-Id: I71c4c6b39ca68464baf09c7d1708348e30989fda Signed-off-by: Lance Xu <lance.xu@windriver.com>
This commit is contained in:
parent
944f847b43
commit
b60bee00b9
|
@ -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