javacore-analyser 2.2rc1__py3-none-any.whl → 2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- javacore_analyser/code_snapshot_collection.py +4 -2
- javacore_analyser/constants.py +3 -1
- javacore_analyser/data/jquery/wait2scripts.js +7 -2
- javacore_analyser/data/xml/report.xsl +26 -8
- javacore_analyser/data/xml/threads/thread.xsl +5 -1
- javacore_analyser/java_thread.py +25 -2
- javacore_analyser/javacore.py +3 -0
- javacore_analyser/javacore_analyser_batch.py +4 -0
- javacore_analyser/javacore_set.py +37 -14
- javacore_analyser/properties.py +28 -0
- javacore_analyser/thread_snapshot.py +14 -12
- javacore_analyser/tips.py +3 -3
- javacore_analyser/verbose_gc.py +7 -19
- {javacore_analyser-2.2rc1.dist-info → javacore_analyser-2.3.dist-info}/METADATA +8 -5
- {javacore_analyser-2.2rc1.dist-info → javacore_analyser-2.3.dist-info}/RECORD +18 -17
- {javacore_analyser-2.2rc1.dist-info → javacore_analyser-2.3.dist-info}/WHEEL +0 -0
- {javacore_analyser-2.2rc1.dist-info → javacore_analyser-2.3.dist-info}/entry_points.txt +0 -0
- {javacore_analyser-2.2rc1.dist-info → javacore_analyser-2.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright IBM Corp. 2024 -
|
2
|
+
# Copyright IBM Corp. 2024 - 2025
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
#
|
5
5
|
|
@@ -21,7 +21,6 @@ class CodeSnapshotCollection(AbstractSnapshotCollection):
|
|
21
21
|
"""
|
22
22
|
Returns list of the threads for which given stack appears
|
23
23
|
"""
|
24
|
-
|
25
24
|
def get_threads(self):
|
26
25
|
result = set()
|
27
26
|
for snapshot in self.thread_snapshots:
|
@@ -29,6 +28,9 @@ class CodeSnapshotCollection(AbstractSnapshotCollection):
|
|
29
28
|
result.add(thread)
|
30
29
|
return result
|
31
30
|
|
31
|
+
def is_interesting(self): # method is to be overloaded in subclasses, ignore the static warning
|
32
|
+
return True
|
33
|
+
|
32
34
|
def get_xml(self, doc):
|
33
35
|
snapshot_collection_node = super().get_xml(doc)
|
34
36
|
stack_strace = self.get_stack_trace()
|
javacore_analyser/constants.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright IBM Corp. 2024 -
|
2
|
+
# Copyright IBM Corp. 2024 - 2025
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
#
|
5
5
|
|
@@ -24,8 +24,10 @@ UNKNOWN = 'Unknown'
|
|
24
24
|
STACK_TRACE = '4XESTACKTRACE'
|
25
25
|
NATIVE_STACK_TRACE = '4XENATIVESTACK'
|
26
26
|
DATETIME = '1TIDATETIME'
|
27
|
+
STARTTIME = '1CISTARTTIME'
|
27
28
|
SIGINFO = '1TISIGINFO'
|
28
29
|
ENCODING = '1TICHARSET'
|
30
|
+
CMD_LINE = '1CICMDLINE'
|
29
31
|
|
30
32
|
DATA_OUTPUT_SUBDIR = '/data/'
|
31
33
|
DEFAULT_FILE_DELIMITER = ';'
|
@@ -260,8 +260,13 @@ const loadChart = function () {
|
|
260
260
|
|
261
261
|
for(let i=1; i<snapshotsNumber; i++){
|
262
262
|
let rowEl = document.getElementById('all_threads_table_thread_xsl').rows[i];
|
263
|
-
|
264
|
-
|
263
|
+
let value = Number(rowEl.cells[3].innerText);
|
264
|
+
|
265
|
+
// verify the input data
|
266
|
+
if(!isNaN(value)){
|
267
|
+
inputData.push(Number(rowEl.cells[3].innerText));
|
268
|
+
labels.push(String(rowEl.cells[0].innerText));
|
269
|
+
}
|
265
270
|
}
|
266
271
|
|
267
272
|
new Chart(ctx, {
|
@@ -159,7 +159,7 @@
|
|
159
159
|
<button data-search="clear">✖</button>
|
160
160
|
</div>
|
161
161
|
<div class="content">
|
162
|
-
<h1>
|
162
|
+
<h1>Javacore Analyser Report</h1>
|
163
163
|
<div class="margined">
|
164
164
|
from data between
|
165
165
|
<b><xsl:value-of select="doc/report_info/javacores_generation_time/starting_time"/></b> and
|
@@ -383,6 +383,14 @@
|
|
383
383
|
<td>Os level</td>
|
384
384
|
<td class="left"><xsl:value-of select="doc/system_info/os_level"/></td>
|
385
385
|
</tr>
|
386
|
+
<tr>
|
387
|
+
<td>JVM startup time</td>
|
388
|
+
<td class="left"><xsl:value-of select="doc/system_info/jvm_start_time"/></td>
|
389
|
+
</tr>
|
390
|
+
<tr>
|
391
|
+
<td>Command line</td>
|
392
|
+
<td class="left"><xsl:value-of select="doc/system_info/cmd_line"/></td>
|
393
|
+
</tr>
|
386
394
|
</tbody>
|
387
395
|
</table>
|
388
396
|
<h4>Java Arguments</h4>
|
@@ -533,6 +541,7 @@
|
|
533
541
|
that may be reused for unrelated tasks. Two tasks with different thread names are therefore treated
|
534
542
|
as separate threads for the purpose of this report, even if they are executed in the scope of the same
|
535
543
|
Thread java object.
|
544
|
+
The address of the java Thread object is included for each thread. This corresponds to the address reported in Java heapdumps.
|
536
545
|
The table can be sorted by clicking on any column header.
|
537
546
|
The following information is displayed for each thread:
|
538
547
|
<ul>
|
@@ -541,6 +550,8 @@
|
|
541
550
|
of the code that the thread was executing in each of the javacores in which it appears.
|
542
551
|
Note that there may be multiple threads with the same name,
|
543
552
|
since the names of threads are not unique over time, and may be reused.
|
553
|
+
A 'More' link may appear next to the thread name to allow to drilldown into that thread's individual page
|
554
|
+
The drilldown may be supressed for threads that don't appear to be doing anything interesting.
|
544
555
|
</li>
|
545
556
|
<li><strong>Total CPU usage</strong>
|
546
557
|
is the total number of seconds the thread was using CPU time since the first javacore,
|
@@ -586,16 +597,23 @@
|
|
586
597
|
<a>
|
587
598
|
<xsl:attribute name="id"><xsl:value-of select="concat('toggle_thread_name',$i)"/></xsl:attribute>
|
588
599
|
<xsl:attribute name="href"><xsl:value-of select="concat('javascript:expand_stack(stack',$i,',toggle_thread_name',$i,')')"/></xsl:attribute>
|
589
|
-
<xsl:attribute name="class">expandit</xsl:attribute
|
590
|
-
|
591
|
-
<xsl:attribute name="href">
|
592
|
-
<xsl:value-of select="concat('threads/thread_', thread_hash, '.html')"/>
|
593
|
-
</xsl:attribute>
|
594
|
-
More...
|
600
|
+
<xsl:attribute name="class">expandit</xsl:attribute>
|
601
|
+
<xsl:value-of select="thread_name"/>
|
595
602
|
</a>
|
596
|
-
<
|
603
|
+
<xsl:choose>
|
604
|
+
<xsl:when test="@has_drill_down='True'">
|
605
|
+
<a class="right" target="_blank">
|
606
|
+
<xsl:attribute name="href">
|
607
|
+
<xsl:value-of select="concat('threads/thread_', thread_hash, '.html')"/>
|
608
|
+
</xsl:attribute>
|
609
|
+
More...
|
610
|
+
</a>
|
611
|
+
<br/>
|
612
|
+
</xsl:when>
|
613
|
+
</xsl:choose>
|
597
614
|
<div style="display:none;" >
|
598
615
|
<xsl:attribute name="id"><xsl:value-of select="concat('stack',$i)"/></xsl:attribute>
|
616
|
+
java/lang/Thread:<xsl:value-of select="thread_address"/>
|
599
617
|
<xsl:for-each select="*[starts-with(name(), 'stack')]">
|
600
618
|
<div>
|
601
619
|
<xsl:choose>
|
@@ -33,7 +33,11 @@
|
|
33
33
|
</div>
|
34
34
|
<div class="content">
|
35
35
|
<p class="right"><a href="../index.html"> Back to Main page </a></p>
|
36
|
-
<h2>
|
36
|
+
<h2>
|
37
|
+
Wait Report for thread: <b><xsl:value-of select="thread_name"/></b>
|
38
|
+
<br/>
|
39
|
+
java/lang/Thread:<xsl:value-of select="thread_address"/>
|
40
|
+
</h2>
|
37
41
|
<xsl:choose>
|
38
42
|
<xsl:when test="//javacore_count = 1">
|
39
43
|
System resource utilization data cannot be calculated with only a single javacore.
|
javacore_analyser/java_thread.py
CHANGED
@@ -1,13 +1,28 @@
|
|
1
1
|
#
|
2
|
-
# Copyright IBM Corp. 2024 -
|
2
|
+
# Copyright IBM Corp. 2024 - 2025
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
#
|
5
|
-
|
6
5
|
from javacore_analyser.abstract_snapshot_collection import AbstractSnapshotCollection
|
6
|
+
from javacore_analyser.properties import Properties
|
7
7
|
|
8
8
|
|
9
9
|
class Thread(AbstractSnapshotCollection):
|
10
10
|
|
11
|
+
def __init__(self):
|
12
|
+
super().__init__()
|
13
|
+
self.thread_address = ""
|
14
|
+
|
15
|
+
def create(self, thread_snapshot):
|
16
|
+
super().create(thread_snapshot)
|
17
|
+
self.thread_address = thread_snapshot.thread_address
|
18
|
+
|
19
|
+
def is_interesting(self):
|
20
|
+
if self.get_total_cpu() > 0: return True
|
21
|
+
if self.get_avg_mem() // (1024 * 1024) > 0: return True # memory in megabytes
|
22
|
+
if len(self.get_blocker_threads()) > 0: return True
|
23
|
+
if len(self.get_blocking_threads()) > 0: return True
|
24
|
+
return False
|
25
|
+
|
11
26
|
def get_hash(self):
|
12
27
|
id_str = self.name + str(self.id)
|
13
28
|
hashcode = abs(hash(id_str))
|
@@ -16,6 +31,9 @@ class Thread(AbstractSnapshotCollection):
|
|
16
31
|
def get_xml(self, doc):
|
17
32
|
thread_node = super().get_xml(doc)
|
18
33
|
|
34
|
+
thread_node.setAttribute("has_drill_down",
|
35
|
+
str(self.is_interesting() or not Properties.get_instance().skip_boring))
|
36
|
+
|
19
37
|
# thread ID
|
20
38
|
id_node = doc.createElement("thread_id")
|
21
39
|
id_node.appendChild(doc.createTextNode(str(self.id)))
|
@@ -26,6 +44,11 @@ class Thread(AbstractSnapshotCollection):
|
|
26
44
|
name_node.appendChild(doc.createTextNode(self.name + " (" + str(self.id) + ")"))
|
27
45
|
thread_node.appendChild(name_node)
|
28
46
|
|
47
|
+
# thread address
|
48
|
+
thread_address_node = doc.createElement("thread_address")
|
49
|
+
thread_address_node.appendChild(doc.createTextNode(self.thread_address))
|
50
|
+
thread_node.appendChild(thread_address_node)
|
51
|
+
|
29
52
|
# hash
|
30
53
|
hash_node = doc.createElement("thread_hash")
|
31
54
|
hash_node.appendChild(doc.createTextNode(self.get_hash()))
|
javacore_analyser/javacore.py
CHANGED
@@ -42,6 +42,9 @@ class Javacore:
|
|
42
42
|
self.javacore_set = javacore_set
|
43
43
|
self.extract_thread_snapshots()
|
44
44
|
|
45
|
+
def is_interesting(self): # method is to be overloaded in subclasses, ignore the static warning
|
46
|
+
return True
|
47
|
+
|
45
48
|
def get_cpu_percentage(self):
|
46
49
|
if self.__total_cpu == -1:
|
47
50
|
self.__calculate_total_cpu_and_load()
|
@@ -22,6 +22,7 @@ from importlib_resources.abc import Traversable
|
|
22
22
|
from javacore_analyser import logging_utils
|
23
23
|
from javacore_analyser.constants import DEFAULT_FILE_DELIMITER
|
24
24
|
from javacore_analyser.javacore_set import JavacoreSet
|
25
|
+
from javacore_analyser.properties import Properties
|
25
26
|
|
26
27
|
SUPPORTED_ARCHIVES_FORMATS = {"zip", "gz", "tgz", "bz2", "lzma", "7z"}
|
27
28
|
|
@@ -76,11 +77,14 @@ def main():
|
|
76
77
|
parser.add_argument("--separator",
|
77
78
|
help='Input files separator (default "' + DEFAULT_FILE_DELIMITER + '")',
|
78
79
|
default=DEFAULT_FILE_DELIMITER)
|
80
|
+
parser.add_argument("--skip_boring", help='Skips drilldown page generation for threads that do not do anything',
|
81
|
+
default='True')
|
79
82
|
args = parser.parse_args()
|
80
83
|
|
81
84
|
input_param = args.input
|
82
85
|
output_param = args.output
|
83
86
|
files_separator = args.separator
|
87
|
+
Properties.get_instance().skip_boring = args.skip_boring != 'False'
|
84
88
|
|
85
89
|
batch_process(input_param, output_param, files_separator)
|
86
90
|
|
@@ -25,6 +25,7 @@ from javacore_analyser.constants import *
|
|
25
25
|
from javacore_analyser.har_file import HarFile
|
26
26
|
from javacore_analyser.java_thread import Thread
|
27
27
|
from javacore_analyser.javacore import Javacore
|
28
|
+
from javacore_analyser.properties import Properties
|
28
29
|
from javacore_analyser.snapshot_collection import SnapshotCollection
|
29
30
|
from javacore_analyser.snapshot_collection_collection import SnapshotCollectionCollection
|
30
31
|
from javacore_analyser.verbose_gc import VerboseGcParser
|
@@ -44,11 +45,14 @@ def _create_xml_xsl_for_collection(tmp_dir, templates_dir, xml_xsl_filename, col
|
|
44
45
|
filename = output_file_prefix + "_" + str(element_id) + extension
|
45
46
|
if filename.startswith("_"):
|
46
47
|
filename = filename[1:]
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
if element.is_interesting() or not Properties.get_instance().skip_boring:
|
49
|
+
file = os.path.join(tmp_dir, filename)
|
50
|
+
logging.debug("Writing file " + file)
|
51
|
+
f = open(file, "w")
|
52
|
+
f.write(file_content.format(id=element_id))
|
53
|
+
f.close()
|
54
|
+
else:
|
55
|
+
logging.debug("Skipping boring file: " + filename)
|
52
56
|
|
53
57
|
|
54
58
|
class JavacoreSet:
|
@@ -68,6 +72,8 @@ class JavacoreSet:
|
|
68
72
|
self.os_level = ""
|
69
73
|
self.architecture = ""
|
70
74
|
self.java_version = ""
|
75
|
+
self.jvm_start_time = ""
|
76
|
+
self.cmd_line = ""
|
71
77
|
self.user_args = []
|
72
78
|
# end of static information
|
73
79
|
self.files = []
|
@@ -142,17 +148,18 @@ class JavacoreSet:
|
|
142
148
|
|
143
149
|
@staticmethod
|
144
150
|
def __generate_placeholder_htmls(placeholder_file, directory, collection, file_prefix):
|
145
|
-
logging.info("Generating placeholder htmls")
|
151
|
+
logging.info(f"Generating placeholder htmls in {directory}")
|
146
152
|
if os.path.exists(directory):
|
147
153
|
shutil.rmtree(directory)
|
148
154
|
os.mkdir(directory)
|
149
155
|
|
150
|
-
for element in tqdm(collection, desc="Generating placeholder htmls", unit="
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
+
for element in tqdm(collection, desc="Generating placeholder htmls", unit=" file"):
|
157
|
+
if element.is_interesting() or not Properties.get_instance().skip_boring:
|
158
|
+
filename = file_prefix + "_" + element.get_id() + ".html"
|
159
|
+
if filename.startswith("_"):
|
160
|
+
filename = filename[1:]
|
161
|
+
file_path = os.path.join(directory, filename)
|
162
|
+
shutil.copy2(placeholder_file, file_path)
|
156
163
|
logging.info("Finished generating placeholder htmls")
|
157
164
|
|
158
165
|
def __generate_htmls_for_threads(self, output_dir, temp_dir_name):
|
@@ -191,6 +198,8 @@ class JavacoreSet:
|
|
191
198
|
logging.debug("Architecture: {}".format(self.architecture))
|
192
199
|
logging.debug("Java version: {}".format(self.java_version))
|
193
200
|
logging.debug("OS Level: {}".format(self.os_level))
|
201
|
+
logging.debug("JVM Startup time: {}".format(self.jvm_start_time))
|
202
|
+
logging.debug("Command line: {}".format(self.cmd_line))
|
194
203
|
|
195
204
|
@staticmethod
|
196
205
|
def create(path):
|
@@ -267,6 +276,12 @@ class JavacoreSet:
|
|
267
276
|
elif line.startswith(JAVA_VERSION):
|
268
277
|
self.java_version = line[len(JAVA_VERSION) + 1:].strip()
|
269
278
|
continue
|
279
|
+
elif line.startswith(STARTTIME):
|
280
|
+
self.jvm_start_time = line[line.find(":") + 1:].strip()
|
281
|
+
continue
|
282
|
+
elif line.startswith(CMD_LINE):
|
283
|
+
self.cmd_line = line[len(CMD_LINE) + 1:].strip()
|
284
|
+
continue
|
270
285
|
except Exception as ex:
|
271
286
|
logging.exception(ex)
|
272
287
|
logging.error(f'Error during processing file: {file.name} \n'
|
@@ -472,6 +487,14 @@ class JavacoreSet:
|
|
472
487
|
system_info_node.appendChild(os_level_node)
|
473
488
|
os_level_node.appendChild(self.doc.createTextNode(self.os_level))
|
474
489
|
|
490
|
+
jvm_startup_time = self.doc.createElement("jvm_start_time")
|
491
|
+
system_info_node.appendChild(jvm_startup_time)
|
492
|
+
jvm_startup_time.appendChild(self.doc.createTextNode(self.jvm_start_time))
|
493
|
+
|
494
|
+
cmd_line = self.doc.createElement("cmd_line")
|
495
|
+
system_info_node.appendChild(cmd_line)
|
496
|
+
cmd_line.appendChild(self.doc.createTextNode(self.cmd_line))
|
497
|
+
|
475
498
|
doc_node.appendChild(self.get_blockers_xml())
|
476
499
|
doc_node.appendChild(self.threads.get_xml(self.doc))
|
477
500
|
doc_node.appendChild(self.stacks.get_xml(self.doc))
|
@@ -551,7 +574,7 @@ class JavacoreSet:
|
|
551
574
|
logging.info(f"Using {threads_no} threads to generate html files")
|
552
575
|
|
553
576
|
list_files = os.listdir(data_input_dir)
|
554
|
-
progress_bar = tqdm(desc="Generating html files", unit='
|
577
|
+
progress_bar = tqdm(desc="Generating html files", unit=' file')
|
555
578
|
|
556
579
|
# Generating list of tuples. This is required attribute for p.map function executed few lines below.
|
557
580
|
generate_html_from_xml_xsl_files_params = []
|
@@ -608,7 +631,7 @@ class JavacoreSet:
|
|
608
631
|
extensions = [".xsl", ".xml"]
|
609
632
|
for extension in extensions:
|
610
633
|
file_content = Path(xml_xsls_prefix_path + extension).read_text()
|
611
|
-
for element in tqdm(collection, desc="Creating xml/xsl files", unit="
|
634
|
+
for element in tqdm(collection, desc="Creating xml/xsl files", unit=" file"):
|
612
635
|
element_id = element.get_id()
|
613
636
|
filename = output_file_prefix + "_" + str(element_id) + extension
|
614
637
|
if filename.startswith("_"):
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Copyright IBM Corp. 2024 - 2025
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
4
|
+
#
|
5
|
+
|
6
|
+
class Properties:
|
7
|
+
|
8
|
+
__instance = None
|
9
|
+
|
10
|
+
# Python doesn't have private constructors
|
11
|
+
# The key prevents creation of an object of this class from outside the class
|
12
|
+
__create_key = object()
|
13
|
+
|
14
|
+
@classmethod
|
15
|
+
def create(cls):
|
16
|
+
return Properties(cls.__create_key)
|
17
|
+
|
18
|
+
def __init__(self, create_key):
|
19
|
+
# the assertion below effectively makes the constructor private
|
20
|
+
assert (create_key == Properties.__create_key), \
|
21
|
+
"Properties objects must be created using Properties.create"
|
22
|
+
self.skip_boring = True
|
23
|
+
|
24
|
+
@staticmethod
|
25
|
+
def get_instance():
|
26
|
+
if not Properties.__instance:
|
27
|
+
Properties.__instance = Properties.create()
|
28
|
+
return Properties.__instance
|
@@ -21,6 +21,7 @@ class ThreadSnapshot:
|
|
21
21
|
self.allocated_mem = 0
|
22
22
|
self.name = None
|
23
23
|
self.thread_id = None
|
24
|
+
self.thread_address = None
|
24
25
|
self.thread = None
|
25
26
|
self.javacore = None
|
26
27
|
self.blocker = None
|
@@ -38,6 +39,7 @@ class ThreadSnapshot:
|
|
38
39
|
snapshot.file = file
|
39
40
|
snapshot.javacore = javacore
|
40
41
|
snapshot.name = snapshot.get_thread_name(line)
|
42
|
+
snapshot.thread_address = snapshot.get_thread_address(line)
|
41
43
|
snapshot.parse_state(line)
|
42
44
|
snapshot.parse_snapshot_data()
|
43
45
|
return snapshot
|
@@ -76,6 +78,18 @@ class ThreadSnapshot:
|
|
76
78
|
name = name.translate(str.maketrans({"\01": "[SOH]"}))
|
77
79
|
return name
|
78
80
|
|
81
|
+
def get_thread_address(self, line):
|
82
|
+
""" assuming line format:
|
83
|
+
3XMTHREADINFO "Default Executor-thread-27781" J9VMThread:0x0000000009443300,
|
84
|
+
omrthread_t:0x000000A8B62C3758, java/lang/Thread:0x00000008432D4140, state:B, prio=5 """
|
85
|
+
match = re.search("(java/lang/Thread:)(0x[0-9a-fA-F]+)", line)
|
86
|
+
address = ""
|
87
|
+
if match: # native threads don't have an address
|
88
|
+
address = match.group(2)
|
89
|
+
if self.javacore:
|
90
|
+
address = self.javacore.encode(address)
|
91
|
+
return address
|
92
|
+
|
79
93
|
def get_thread_hash(self):
|
80
94
|
if self.thread:
|
81
95
|
return self.thread.get_hash()
|
@@ -198,18 +212,6 @@ class ThreadSnapshot:
|
|
198
212
|
file_name = ""
|
199
213
|
if self.file:
|
200
214
|
file_name = self.javacore.filename.split(os.sep)[-1].strip()
|
201
|
-
# thread name
|
202
|
-
thread_name_node = doc.createElement("thread_name")
|
203
|
-
thread_name_node.appendChild(doc.createTextNode(self.name))
|
204
|
-
thread_snapshot_node.appendChild(thread_name_node)
|
205
|
-
# thread id
|
206
|
-
thread_name_node = doc.createElement("thread_id")
|
207
|
-
thread_name_node.appendChild(doc.createTextNode(str(self.get_thread_id())))
|
208
|
-
thread_snapshot_node.appendChild(thread_name_node)
|
209
|
-
# thread hash
|
210
|
-
thread_hash_node = doc.createElement("thread_hash")
|
211
|
-
thread_hash_node.appendChild(doc.createTextNode(str(self.get_thread_hash())))
|
212
|
-
thread_snapshot_node.appendChild(thread_hash_node)
|
213
215
|
# CPU usage
|
214
216
|
cpu_usage_node = doc.createElement("cpu_usage")
|
215
217
|
cpu_usage_node.appendChild(doc.createTextNode(str(self.get_cpu_usage_inc())))
|
javacore_analyser/tips.py
CHANGED
@@ -73,8 +73,8 @@ class DifferentIssuesTip:
|
|
73
73
|
MAX_INTERVAL_FOR_JAVACORES = 330 # 330 seconds (5 minutes and a little more time)
|
74
74
|
DIFFERENT_ISSUES_MESSAGE = """[WARNING] The time interval between javacore {0} and {1} is {2:.0f} seconds, while
|
75
75
|
the recommended maximum interval between two javacores is 300 seconds (5 minutes). It is likely that these
|
76
|
-
two javacores do not correspond to one occurrence of a single issue. Please review the list of javacores
|
77
|
-
|
76
|
+
two javacores do not correspond to one occurrence of a single issue. Please review the list of javacores
|
77
|
+
and the tool only against the ones that are applicable for the issue you are investigating. """
|
78
78
|
|
79
79
|
@staticmethod
|
80
80
|
def generate(javacore_set):
|
@@ -103,7 +103,7 @@ class TooFewJavacoresTip:
|
|
103
103
|
|
104
104
|
MIN_NUMBER_OF_JAVACORES = 10
|
105
105
|
|
106
|
-
ONE_JAVACORE_WARNING = '''[WARNING] You generated this
|
106
|
+
ONE_JAVACORE_WARNING = '''[WARNING] You generated this the report with only one javacore.
|
107
107
|
CPU usage calculation is not possible.'''
|
108
108
|
|
109
109
|
NOT_ENOUGH_JAVACORES_MESSAGE = """[WARNING] You ran the tool against {0} Javacores. The analysis
|
javacore_analyser/verbose_gc.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
#
|
2
|
-
# Copyright IBM Corp. 2024 -
|
2
|
+
# Copyright IBM Corp. 2024 - 2025
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
#
|
5
5
|
|
6
6
|
import logging
|
7
7
|
import ntpath
|
8
8
|
from datetime import datetime
|
9
|
+
from pathlib import Path
|
9
10
|
from xml.dom.minidom import Element, parseString
|
10
11
|
|
11
12
|
from tqdm import tqdm
|
@@ -59,7 +60,7 @@ class VerboseGcParser:
|
|
59
60
|
file.set_number_of_collects(collects_from_time_range)
|
60
61
|
except GcVerboseProcessingException as ex:
|
61
62
|
logging.warning(file_path + " was omitted due to error", ex)
|
62
|
-
logging.info("Finished parsing GC files
|
63
|
+
logging.info("Finished parsing GC files")
|
63
64
|
|
64
65
|
def get_xml(self, doc):
|
65
66
|
element = doc.createElement(GC_COLLECTIONS)
|
@@ -110,22 +111,11 @@ class VerboseGcFile:
|
|
110
111
|
self.__parse()
|
111
112
|
|
112
113
|
def __parse(self):
|
113
|
-
# read in the file as collection of lines
|
114
|
-
file = None
|
115
114
|
try:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
# find the last non-empty line
|
121
|
-
for line in lines:
|
122
|
-
line = line.strip()
|
123
|
-
# workaround for https://github.com/eclipse-openj9/openj9/issues/17978
|
124
|
-
line = line.replace("", "?")
|
125
|
-
xml_text = xml_text + line
|
126
|
-
if line == ROOT_CLOSING_TAG: root_closing_tag_available = True
|
127
|
-
|
128
|
-
if not root_closing_tag_available:
|
115
|
+
file = Path(self.__path)
|
116
|
+
xml_text = file.read_text()
|
117
|
+
xml_text = xml_text.replace("", "?")
|
118
|
+
if ROOT_CLOSING_TAG not in xml_text:
|
129
119
|
xml_text = xml_text + ROOT_CLOSING_TAG
|
130
120
|
logging.debug("adding closing tag")
|
131
121
|
|
@@ -133,8 +123,6 @@ class VerboseGcFile:
|
|
133
123
|
self.__root = self.__doc.documentElement
|
134
124
|
except Exception as ex:
|
135
125
|
raise GcVerboseProcessingException() from ex
|
136
|
-
finally:
|
137
|
-
if not file.closed: file.close()
|
138
126
|
|
139
127
|
def get_file_name(self):
|
140
128
|
head, tail = ntpath.split(self.__path)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: javacore_analyser
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.3
|
4
4
|
Summary: The tool to review IBM Javacore files
|
5
5
|
Project-URL: Homepage, https://github.com/IBM/javacore-analyser
|
6
6
|
Project-URL: Issues, https://github.com/IBM/javacore-analyser/issues
|
@@ -278,7 +278,8 @@ Steps:
|
|
278
278
|
3. Run the following command:
|
279
279
|
`pip install javacore-analyser`
|
280
280
|
OR
|
281
|
-
`pip install --pre
|
281
|
+
`pip install --pre javacore-analyser` - if you want an experimental version
|
282
|
+
|
282
283
|
|
283
284
|
#### Installing from sources
|
284
285
|
This is recommended for geeks only:
|
@@ -301,6 +302,7 @@ Where `<input-data>` is one of the following:
|
|
301
302
|
* The directory containing javacores and optionally verbose gc
|
302
303
|
* Archive (7z, zip, tar.gz, tar.bz2) containing the same
|
303
304
|
* List of the javacores separated by `;` character. Optionally you can add `--separator` option to define your own separator.
|
305
|
+
* You can specify `--skip_boring=False` if you want drill-down pages generated for all the threads, including the ones that do not do anything interesting.
|
304
306
|
You can type the following command to obtain the help:
|
305
307
|
`javacore-analyser-batch --help` or `python -m javacore_analyser batch --help`
|
306
308
|
|
@@ -311,19 +313,20 @@ You can type the following command to obtain the help:
|
|
311
313
|
or
|
312
314
|
`python -m javacore_analyser web --port=5000 --reports-dir=/data/reports_dir`
|
313
315
|
|
316
|
+
|
314
317
|
The first parameter set the port to use by application. If not specified, 5000 will be used.
|
315
318
|
The second parameter sets where the reports need to be stored. If not set, then the `reports` dir will be created in current location.
|
316
319
|
|
317
320
|
Now you can type (http://localhost:5000/).
|
318
321
|
|
319
322
|
### Running container image
|
320
|
-
There is
|
323
|
+
There is a Docker/Podman container managed by one of projects developers. Use the following command
|
321
324
|
to start it:
|
322
325
|
|
323
|
-
`podman run -it --rm --name javacore-analyser --mount type=bind,src="/local-reports-dir",target=/reports -p 5001:5000 ghcr.io/
|
326
|
+
`podman run -it --rm --name javacore-analyser --mount type=bind,src="/local-reports-dir",target=/reports -p 5001:5000 ghcr.io/ibm/javacore-analyser:latest`
|
324
327
|
|
325
328
|
or
|
326
|
-
`docker run -it --rm --name javacore-analyser --mount type=bind,src="/local-reports-dir",target=/reports -p 5001:5000 ghcr.io/
|
329
|
+
`docker run -it --rm --name javacore-analyser --mount type=bind,src="/local-reports-dir",target=/reports -p 5001:5000 ghcr.io/ibm/javacore-analyser:latest`
|
327
330
|
|
328
331
|
The `mount` option specifies where you want locally to store the reports. The reports in the container are stored in
|
329
332
|
`/reports` directory. If you remove mount option, the application will work but the reports will not persist after
|
@@ -1,23 +1,24 @@
|
|
1
1
|
javacore_analyser/__init__.py,sha256=Sw2ZeqcI2Kx1cDDv083n1SiSY_FDRCmidTuzaN1uRSw,76
|
2
2
|
javacore_analyser/__main__.py,sha256=wQCPgu8Gp7XczyNckNGmY30c5YMUMRByW7jrdFO0OBY,1694
|
3
3
|
javacore_analyser/abstract_snapshot_collection.py,sha256=jGfd2XgujurRlKgEtlJjqNJK9sUvTdFsdgFnX9oLzt4,5589
|
4
|
-
javacore_analyser/code_snapshot_collection.py,sha256=
|
5
|
-
javacore_analyser/constants.py,sha256=
|
4
|
+
javacore_analyser/code_snapshot_collection.py,sha256=yag25_O1JOQjz2uIK2gQzaTvovINnJ4ClnNhmrbC0Fg,2776
|
5
|
+
javacore_analyser/constants.py,sha256=7-gbGLzUMIMe2UvmLT17ymmy_r_izadpAyhrEKFonP8,1054
|
6
6
|
javacore_analyser/har_file.py,sha256=grXpfIyPek9xQ5jp3_AYOB5JDELd17o4O4rYELxWO7w,2131
|
7
|
-
javacore_analyser/java_thread.py,sha256=
|
8
|
-
javacore_analyser/javacore.py,sha256=
|
9
|
-
javacore_analyser/javacore_analyser_batch.py,sha256=
|
7
|
+
javacore_analyser/java_thread.py,sha256=nDFJiFQSO78jP9YdMpBr2d_M2RMT0te_kJxn5KY_RNo,5437
|
8
|
+
javacore_analyser/javacore.py,sha256=oqJ-nKkZvq8xk_zlF9Z4dX61isqLRndSVLnQob_KUG4,7006
|
9
|
+
javacore_analyser/javacore_analyser_batch.py,sha256=2JnRruA0jazWHspT60cXX-Yuwf4vFSA5ywXYPQ4-ZiM,7888
|
10
10
|
javacore_analyser/javacore_analyser_web.py,sha256=o-Spq119Wi7w4pvBa7M7ZrxiZnzKmWqDhCdGtEReQAU,5951
|
11
|
-
javacore_analyser/javacore_set.py,sha256=
|
11
|
+
javacore_analyser/javacore_set.py,sha256=5x16j8KfA_DXD3FlvKlRHfRJ2B1rj5j2EkMfb2dV3dg,33341
|
12
12
|
javacore_analyser/logging_utils.py,sha256=vLob0ikezysjGv9XGqv9GbLekxu4eO_csq22M-gtLiQ,966
|
13
|
+
javacore_analyser/properties.py,sha256=SVxe86mL4DM_vkPEBT-V0_xDeIbXp2vjYE1aD-Z_UCQ,805
|
13
14
|
javacore_analyser/snapshot_collection.py,sha256=fLEnwg9-cOjVVUUludtzI7R2yO9BBVgJgxkhvqG5QDg,443
|
14
15
|
javacore_analyser/snapshot_collection_collection.py,sha256=1PV1TX4QQk01dAbX-k-kTpgKr6Il867Bw6X7HHBuv-Q,1346
|
15
16
|
javacore_analyser/stack_trace.py,sha256=8sb8z4ac_L0yyxqJX1ukrTZRyngkHcA3zkXyqxG5ygA,1664
|
16
17
|
javacore_analyser/stack_trace_element.py,sha256=pZPrK1ACBUDE7YsVOFhTfewXequ1m5P-B0N-9RuhkWo,1143
|
17
18
|
javacore_analyser/stack_trace_kind.py,sha256=lOdfb_F3XrwDLciPk_ZgM_fmMn5JoXsIUjr7pjvmU4M,157
|
18
|
-
javacore_analyser/thread_snapshot.py,sha256=
|
19
|
-
javacore_analyser/tips.py,sha256=
|
20
|
-
javacore_analyser/verbose_gc.py,sha256=
|
19
|
+
javacore_analyser/thread_snapshot.py,sha256=yp7uJwF5adMN2UAhOn-lLtSP2X3j8utUfafjyKu8r4E,13252
|
20
|
+
javacore_analyser/tips.py,sha256=JggNTmCkH2x2jqFChdnWlex8hU9q3Gy5IqJaxDQtPwI,8625
|
21
|
+
javacore_analyser/verbose_gc.py,sha256=FdSzj9bB9GrJVM8qzkvjNm0LsJZRvKWpd2oMQ8G8eEE,6373
|
21
22
|
javacore_analyser/data/expand.js,sha256=KwqvNUoO7yMDeQKcnLDywfMdR3Zsjan5L8QoPsQQLGo,956
|
22
23
|
javacore_analyser/data/style.css,sha256=HSKPajW3EItHjye6mSGNMRPEzfE2r7o1Gq-BEAI54Ts,2879
|
23
24
|
javacore_analyser/data/html/error.html,sha256=dJI5RdeNL1E4Y-zaU7NTBqrsxCuAovVc1Cebrk5GcYA,520
|
@@ -33,16 +34,16 @@ javacore_analyser/data/jquery/search.js,sha256=Jwi-cBJ9YKDHJwqIlcKXqrpcM1BX-wx93
|
|
33
34
|
javacore_analyser/data/jquery/sorting.js,sha256=HsuVLa7F70IM4ZMXZpjj7wtVI1TXL1SPbZGWenv0Jp8,369
|
34
35
|
javacore_analyser/data/jquery/theme.blue.css,sha256=cPcj8KaUj_zNy_xtDfrodSLue94nnYgyVNIZRusggCw,7624
|
35
36
|
javacore_analyser/data/jquery/theme.default.min.css,sha256=5sgExNTnkN8NcApKIU73_aqgZmqq_zJp9-9zXf9aSEw,4502
|
36
|
-
javacore_analyser/data/jquery/wait2scripts.js,sha256=
|
37
|
+
javacore_analyser/data/jquery/wait2scripts.js,sha256=jORUs9xgz_o-VnRm0RxjKlraZOleQrPp5DmTyrMBwrM,8577
|
37
38
|
javacore_analyser/data/xml/index.xml,sha256=9VH2rmri3FQpXcW39kbyi2dON94C5XTiaQn0ioExCe8,282
|
38
|
-
javacore_analyser/data/xml/report.xsl,sha256=
|
39
|
+
javacore_analyser/data/xml/report.xsl,sha256=LlrleGFx9MC0VOhP6CBgII1uhP-kzhbo4pwro-HwAGo,60178
|
39
40
|
javacore_analyser/data/xml/javacores/javacore.xml,sha256=6dG89Whx1_kpEYVS_F6Upa2XuXnXorlQATFc8kD5Mfc,280
|
40
41
|
javacore_analyser/data/xml/javacores/javacore.xsl,sha256=5cnIp08Q9FccljHH8duoJQYofyW8lwUCGtpdzz5Y0Y8,11644
|
41
42
|
javacore_analyser/data/xml/threads/thread.xml,sha256=6dG89Whx1_kpEYVS_F6Upa2XuXnXorlQATFc8kD5Mfc,280
|
42
|
-
javacore_analyser/data/xml/threads/thread.xsl,sha256=
|
43
|
+
javacore_analyser/data/xml/threads/thread.xsl,sha256=1tg5tImtr1gyZ8Q61tqIukNtm1fQ6R8YoKC3EgIjLRA,14084
|
43
44
|
javacore_analyser/templates/index.html,sha256=aEuyry-HZ9HlQNwfbugugvqbSxwlo7LrQnrDmqO34YE,1682
|
44
|
-
javacore_analyser-2.
|
45
|
-
javacore_analyser-2.
|
46
|
-
javacore_analyser-2.
|
47
|
-
javacore_analyser-2.
|
48
|
-
javacore_analyser-2.
|
45
|
+
javacore_analyser-2.3.dist-info/METADATA,sha256=OqkpuvfVdhTUU35rvB1_OI2b1dTjIaS6FHY0XrF3e4Q,22362
|
46
|
+
javacore_analyser-2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
47
|
+
javacore_analyser-2.3.dist-info/entry_points.txt,sha256=W3S799zI58g5-jWMsC3wY9xksz21LPEMYOILv8sayfM,160
|
48
|
+
javacore_analyser-2.3.dist-info/licenses/LICENSE,sha256=xllut76FgcGL5zbIRvuRc7aezPbvlMUTWJPsVr2Sugg,11358
|
49
|
+
javacore_analyser-2.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|