javacore-analyser 2.1rc5__py3-none-any.whl → 2.2__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/__main__.py +43 -0
- javacore_analyser/constants.py +3 -1
- javacore_analyser/data/html/error.html +22 -0
- javacore_analyser/data/jquery/theme.blue.css +9 -3
- javacore_analyser/data/jquery/wait2scripts.js +11 -4
- javacore_analyser/data/style.css +32 -0
- javacore_analyser/data/xml/report.xsl +181 -22
- javacore_analyser/data/xml/threads/thread.xsl +5 -1
- javacore_analyser/har_file.py +65 -0
- javacore_analyser/java_thread.py +13 -0
- javacore_analyser/javacore_analyser_batch.py +29 -11
- javacore_analyser/javacore_analyser_web.py +7 -3
- javacore_analyser/javacore_set.py +37 -2
- javacore_analyser/thread_snapshot.py +14 -12
- javacore_analyser/tips.py +3 -3
- javacore_analyser/verbose_gc.py +7 -20
- {javacore_analyser-2.1rc5.dist-info → javacore_analyser-2.2.dist-info}/METADATA +31 -12
- {javacore_analyser-2.1rc5.dist-info → javacore_analyser-2.2.dist-info}/RECORD +21 -18
- {javacore_analyser-2.1rc5.dist-info → javacore_analyser-2.2.dist-info}/WHEEL +0 -0
- {javacore_analyser-2.1rc5.dist-info → javacore_analyser-2.2.dist-info}/entry_points.txt +0 -0
- {javacore_analyser-2.1rc5.dist-info → javacore_analyser-2.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# Copyright IBM Corp. 2024 - 2024
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
4
|
+
#
|
5
|
+
import argparse
|
6
|
+
|
7
|
+
from javacore_analyser import javacore_analyser_batch, constants, javacore_analyser_web
|
8
|
+
|
9
|
+
|
10
|
+
def main():
|
11
|
+
parser = argparse.ArgumentParser(prog="python -m javacore_analyser")
|
12
|
+
subparsers = parser.add_subparsers(dest="type", help="Application type", required=True)
|
13
|
+
|
14
|
+
batch = subparsers.add_parser("batch", description="Run batch application")
|
15
|
+
batch.add_argument("input", help="Input file(s) or directory")
|
16
|
+
batch.add_argument("output", help="Destination report directory")
|
17
|
+
batch.add_argument("--separator", default=constants.DEFAULT_FILE_DELIMITER)
|
18
|
+
|
19
|
+
web = subparsers.add_parser("web", description="Run web application")
|
20
|
+
web.add_argument("--debug", help="Debug mode. Use True only for app development", default=False)
|
21
|
+
web.add_argument("--port", help="Application port", default=constants.DEFAULT_PORT)
|
22
|
+
web.add_argument("--reports-dir", help="Directory to store reports data",
|
23
|
+
default=constants.DEFAULT_REPORTS_DIR)
|
24
|
+
|
25
|
+
args = parser.parse_args()
|
26
|
+
|
27
|
+
app_type: str = args.type
|
28
|
+
|
29
|
+
if app_type.lower() == "web":
|
30
|
+
print("Running web application")
|
31
|
+
javacore_analyser_web.run_web(args.debug, args.port, args.reports_dir)
|
32
|
+
elif app_type.lower() == "batch":
|
33
|
+
print("Running batch application")
|
34
|
+
javacore_analyser_batch.batch_process(args.input, args.output, args.separator)
|
35
|
+
else:
|
36
|
+
print('Invalid application type. Available types: "batch" or "web"')
|
37
|
+
|
38
|
+
|
39
|
+
if __name__ == '__main__':
|
40
|
+
# This is the code to be able to run the app from command line.
|
41
|
+
# Try this:
|
42
|
+
# python -m javacore_analyser -h
|
43
|
+
main()
|
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 = ';'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
|
3
|
+
<!--
|
4
|
+
# Copyright IBM Corp. 2024 - 2025
|
5
|
+
# SPDX-License-Identifier: Apache-2.0
|
6
|
+
-->
|
7
|
+
|
8
|
+
<html lang="en">
|
9
|
+
<head>
|
10
|
+
<meta charset="UTF-8">
|
11
|
+
<title>Processing failed</title>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<p>
|
15
|
+
Processing failed with an error. Check the log file. If the issue is a product defect, rais it on
|
16
|
+
<a href="https://github.com/IBM/javacore-analyser/issues/new?template=bug_report.md">Bug report</a> page.
|
17
|
+
</p>
|
18
|
+
<p>Please attach the stack trace</p>
|
19
|
+
<p>Stack trace: </p>
|
20
|
+
<code> {stacktrace} </code>
|
21
|
+
</body>
|
22
|
+
</html>
|
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
/*
|
2
|
+
Copyright IBM Corp. 2024 - 2025
|
3
|
+
SPDX-License-Identifier: Apache-2.0
|
4
|
+
*/
|
5
|
+
|
4
6
|
/* overall */
|
5
7
|
.tablesorter-blue {
|
6
8
|
width: 100%;
|
@@ -109,6 +111,10 @@
|
|
109
111
|
background-color: red
|
110
112
|
}
|
111
113
|
|
114
|
+
.tablesorter-blue td.http_failure {
|
115
|
+
background-color: red
|
116
|
+
}
|
117
|
+
|
112
118
|
/* hovered row colors
|
113
119
|
you'll need to add additional lines for
|
114
120
|
rows with more than 2 child rows
|
@@ -99,7 +99,9 @@ const loadChartGC = function() {
|
|
99
99
|
}
|
100
100
|
|
101
101
|
const sysResourceE3Elem = document.getElementById('systemresources_myChartGC');
|
102
|
-
sysResourceE3Elem
|
102
|
+
if (sysResourceE3Elem) {
|
103
|
+
sysResourceE3Elem.classList.remove('hide');
|
104
|
+
}
|
103
105
|
|
104
106
|
const ctx = document.getElementById('myChartGC');
|
105
107
|
|
@@ -125,7 +127,7 @@ const loadChartGC = function() {
|
|
125
127
|
startingPoint = timestamp;
|
126
128
|
|
127
129
|
if(endingPoint < timestamp)
|
128
|
-
endingPoint
|
130
|
+
endingPoint = timestamp;
|
129
131
|
}
|
130
132
|
|
131
133
|
coresTimeRange['startTime'] = startingPoint;
|
@@ -258,8 +260,13 @@ const loadChart = function () {
|
|
258
260
|
|
259
261
|
for(let i=1; i<snapshotsNumber; i++){
|
260
262
|
let rowEl = document.getElementById('all_threads_table_thread_xsl').rows[i];
|
261
|
-
|
262
|
-
|
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
|
+
}
|
263
270
|
}
|
264
271
|
|
265
272
|
new Chart(ctx, {
|
javacore_analyser/data/style.css
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
/*
|
2
|
+
Copyright IBM Corp. 2024 - 2025
|
3
|
+
SPDX-License-Identifier: Apache-2.0
|
4
|
+
*/
|
5
|
+
|
1
6
|
table.heading {
|
2
7
|
border: none;
|
3
8
|
width: 100%;
|
@@ -100,6 +105,28 @@ td {
|
|
100
105
|
text-align: left;
|
101
106
|
}
|
102
107
|
|
108
|
+
.info {
|
109
|
+
position: relative;
|
110
|
+
display: inline-block;
|
111
|
+
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
|
112
|
+
color: orange
|
113
|
+
}
|
114
|
+
|
115
|
+
/* Tooltip text */
|
116
|
+
.info .infotooltip {
|
117
|
+
visibility: hidden;
|
118
|
+
width: 120px;
|
119
|
+
background-color: black;
|
120
|
+
color: #fff;
|
121
|
+
text-align: center;
|
122
|
+
padding: 5px 0;
|
123
|
+
border-radius: 6px;
|
124
|
+
|
125
|
+
/* Position the tooltip text - see examples below! */
|
126
|
+
position: absolute;
|
127
|
+
z-index: 1;
|
128
|
+
}
|
129
|
+
|
103
130
|
.warning {
|
104
131
|
position: relative;
|
105
132
|
display: inline-block;
|
@@ -142,6 +169,11 @@ mark.current {
|
|
142
169
|
background: orange;
|
143
170
|
}
|
144
171
|
|
172
|
+
/* Show the tooltip text when you mouse over the tooltip container */
|
173
|
+
.info:hover .infotooltip {
|
174
|
+
visibility: visible;
|
175
|
+
}
|
176
|
+
|
145
177
|
/* Show the tooltip text when you mouse over the tooltip container */
|
146
178
|
.warning:hover .warningtooltip {
|
147
179
|
visibility: visible;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
2
|
|
3
3
|
<!--
|
4
|
-
# Copyright IBM Corp. 2024 -
|
4
|
+
# Copyright IBM Corp. 2024 - 2025
|
5
5
|
# SPDX-License-Identifier: Apache-2.0
|
6
6
|
-->
|
7
7
|
|
@@ -59,6 +59,15 @@
|
|
59
59
|
},
|
60
60
|
});
|
61
61
|
|
62
|
+
$('#har_files_table').tablesorter({
|
63
|
+
theme : 'blue',
|
64
|
+
headers: {
|
65
|
+
0: { sorter: false },
|
66
|
+
1: { sorter: false },
|
67
|
+
2: { sorter: false }
|
68
|
+
},
|
69
|
+
});
|
70
|
+
|
62
71
|
$('#java_arguments_table').tablesorter({
|
63
72
|
theme : 'blue',
|
64
73
|
widgets : ['zebra', 'columns'],
|
@@ -122,6 +131,21 @@
|
|
122
131
|
sortReset : true,
|
123
132
|
sortRestart : true
|
124
133
|
});
|
134
|
+
|
135
|
+
$('#HttpCallTable').tablesorter({
|
136
|
+
theme : 'blue',
|
137
|
+
widgets : ['zebra', 'columns'],
|
138
|
+
sortList: [
|
139
|
+
[2, 1]
|
140
|
+
],
|
141
|
+
sortInitialOrder: 'asc',
|
142
|
+
headers : {
|
143
|
+
0 : { sortInitialOrder: 'asc' }
|
144
|
+
},
|
145
|
+
usNumberFormat : false,
|
146
|
+
sortReset : true,
|
147
|
+
sortRestart : true
|
148
|
+
});
|
125
149
|
});
|
126
150
|
</script>
|
127
151
|
</head>
|
@@ -135,7 +159,7 @@
|
|
135
159
|
<button data-search="clear">✖</button>
|
136
160
|
</div>
|
137
161
|
<div class="content">
|
138
|
-
<h1>
|
162
|
+
<h1>Javacore Analyser Report</h1>
|
139
163
|
<div class="margined">
|
140
164
|
from data between
|
141
165
|
<b><xsl:value-of select="doc/report_info/javacores_generation_time/starting_time"/></b> and
|
@@ -262,6 +286,49 @@
|
|
262
286
|
</xsl:when>
|
263
287
|
<xsl:otherwise> No verbose GC files </xsl:otherwise>
|
264
288
|
</xsl:choose>
|
289
|
+
<xsl:choose>
|
290
|
+
<xsl:when test="doc/har_files">
|
291
|
+
<h4>HAR files</h4>
|
292
|
+
<a id="togglehardoc" href="javascript:expand_it(hardoc,togglehardoc)" class="expandit">
|
293
|
+
What does this table tell me?</a>
|
294
|
+
<div id="hardoc" style="display:none;">
|
295
|
+
This table shows all the HAR files that are included in the data set.
|
296
|
+
<ul>
|
297
|
+
<li>
|
298
|
+
<strong>File Name</strong>
|
299
|
+
is the name of the HAR file.
|
300
|
+
</li>
|
301
|
+
<li>
|
302
|
+
<strong>Hostname</strong>
|
303
|
+
is the name of the server machine for which the HAR file was collected.
|
304
|
+
</li>
|
305
|
+
<li>
|
306
|
+
<strong>Browser</strong>
|
307
|
+
contains information about the browser that was used to collect the HAR file.
|
308
|
+
</li>
|
309
|
+
</ul>
|
310
|
+
</div>
|
311
|
+
<table id="har_files_table">
|
312
|
+
<thead>
|
313
|
+
<tr>
|
314
|
+
<th class="sixty">File Name</th>
|
315
|
+
<th class="ten">Hostname</th>
|
316
|
+
<th class="ten">Browser</th>
|
317
|
+
</tr>
|
318
|
+
</thead>
|
319
|
+
<tbody>
|
320
|
+
<xsl:for-each select="doc/har_files/har_file">
|
321
|
+
<tr>
|
322
|
+
<td class="left"><xsl:value-of select="@filename"/></td>
|
323
|
+
<td class="left"><xsl:value-of select="@hostname"/></td>
|
324
|
+
<td class="left"><xsl:value-of select="@browser"/></td>
|
325
|
+
</tr>
|
326
|
+
</xsl:for-each>
|
327
|
+
</tbody>
|
328
|
+
</table>
|
329
|
+
</xsl:when>
|
330
|
+
<!-- xsl:otherwise> No HAR files </xsl:otherwise -->
|
331
|
+
</xsl:choose>
|
265
332
|
</div>
|
266
333
|
<h3><a id="toggle_system_properties"
|
267
334
|
href="javascript:expand_it(system_properties, toggle_system_properties)"
|
@@ -316,6 +383,14 @@
|
|
316
383
|
<td>Os level</td>
|
317
384
|
<td class="left"><xsl:value-of select="doc/system_info/os_level"/></td>
|
318
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>
|
319
394
|
</tbody>
|
320
395
|
</table>
|
321
396
|
<h4>Java Arguments</h4>
|
@@ -355,25 +430,41 @@
|
|
355
430
|
<h4>Garbage Collection Activity</h4>
|
356
431
|
<a id="togglememusagedoc" href="javascript:expand_it(memusagedoc,togglememusagedoc)" class="expandit">
|
357
432
|
What does this chart tell me?</a>
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
433
|
+
<xsl:choose>
|
434
|
+
<xsl:when test="doc/report_info/verbose_gc_list/verbose_gc">
|
435
|
+
<xsl:choose>
|
436
|
+
<xsl:when test="//verbose_gc_list/@total_collects_in_time_limits = 0">
|
437
|
+
<br/>
|
438
|
+
There were no garbage collections withing the javacore time limits
|
439
|
+
</xsl:when>
|
440
|
+
<xsl:otherwise>
|
441
|
+
<div id="memusagedoc" style="display:none;">
|
442
|
+
This chart shows all the garbage collections that happened between the time
|
443
|
+
of the first and the last javacore in the data set.
|
444
|
+
Garbage collections that happened before the first
|
445
|
+
or after the last javacore generation time are not included.
|
446
|
+
<ul>
|
447
|
+
<li><strong>Heap Usage</strong>
|
448
|
+
is the available Java heap memory over time,
|
449
|
+
based on the garbage collection data from the verbose GC log files.
|
450
|
+
</li>
|
451
|
+
<li><strong>Total Heap</strong>
|
452
|
+
is the maximum size of the Java heap, configured by using the Xmx Java argument,
|
453
|
+
expressed in megabytes.
|
454
|
+
</li>
|
455
|
+
</ul>
|
456
|
+
</div>
|
457
|
+
<div id="systemresources_myChartGC" class="chart-container hide">
|
458
|
+
<canvas id="myChartGC" height="200"></canvas>
|
459
|
+
</div>
|
460
|
+
</xsl:otherwise>
|
461
|
+
</xsl:choose>
|
462
|
+
</xsl:when>
|
463
|
+
<xsl:otherwise>
|
464
|
+
<br/>
|
465
|
+
No verbosegc logs were provided
|
466
|
+
</xsl:otherwise>
|
467
|
+
</xsl:choose>
|
377
468
|
<h4>CPU Load</h4>
|
378
469
|
<a id="togglecpuloaddoc" href="javascript:expand_it(cpuloaddoc,togglecpuloaddoc)" class="expandit">
|
379
470
|
What does this chart tell me?</a>
|
@@ -450,6 +541,7 @@
|
|
450
541
|
that may be reused for unrelated tasks. Two tasks with different thread names are therefore treated
|
451
542
|
as separate threads for the purpose of this report, even if they are executed in the scope of the same
|
452
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.
|
453
545
|
The table can be sorted by clicking on any column header.
|
454
546
|
The following information is displayed for each thread:
|
455
547
|
<ul>
|
@@ -503,7 +595,9 @@
|
|
503
595
|
<a>
|
504
596
|
<xsl:attribute name="id"><xsl:value-of select="concat('toggle_thread_name',$i)"/></xsl:attribute>
|
505
597
|
<xsl:attribute name="href"><xsl:value-of select="concat('javascript:expand_stack(stack',$i,',toggle_thread_name',$i,')')"/></xsl:attribute>
|
506
|
-
<xsl:attribute name="class">expandit</xsl:attribute
|
598
|
+
<xsl:attribute name="class">expandit</xsl:attribute>
|
599
|
+
<xsl:value-of select="thread_name"/>
|
600
|
+
</a>
|
507
601
|
<a class="right" target="_blank">
|
508
602
|
<xsl:attribute name="href">
|
509
603
|
<xsl:value-of select="concat('threads/thread_', thread_hash, '.html')"/>
|
@@ -513,6 +607,7 @@
|
|
513
607
|
<br/>
|
514
608
|
<div style="display:none;" >
|
515
609
|
<xsl:attribute name="id"><xsl:value-of select="concat('stack',$i)"/></xsl:attribute>
|
610
|
+
java/lang/Thread:<xsl:value-of select="thread_address"/>
|
516
611
|
<xsl:for-each select="*[starts-with(name(), 'stack')]">
|
517
612
|
<div>
|
518
613
|
<xsl:choose>
|
@@ -746,6 +841,70 @@
|
|
746
841
|
</table>
|
747
842
|
</div>
|
748
843
|
|
844
|
+
<xsl:choose>
|
845
|
+
<xsl:when test="doc/har_files">
|
846
|
+
<h3><a id="toggle_http_calls" href="javascript:expand_it(http_calls,toggle_http_calls)" class="expandit">HTTP calls</a></h3>
|
847
|
+
<div id="http_calls" style="display:none;" >
|
848
|
+
<a id="togglehttpcallsdoc" href="javascript:expand_it(httpcallsdoc,togglehttpcallsdoc)" class="expandit">
|
849
|
+
What does this table tell me?</a>
|
850
|
+
<div id="httpcallsdoc" style="display:none;">
|
851
|
+
The table shows the HTTP calls that are included in the HAR files from the data set.
|
852
|
+
The table can be sorted by clicking on a column header.
|
853
|
+
<ul>
|
854
|
+
<li><strong>URL</strong>
|
855
|
+
is the URL of the HTTP request.
|
856
|
+
</li>
|
857
|
+
<li><strong>Status</strong>
|
858
|
+
is the HTTP response code.
|
859
|
+
</li>
|
860
|
+
<li><strong>Start time</strong>
|
861
|
+
is the time when the HTTP request was made.
|
862
|
+
</li>
|
863
|
+
<li><strong>Duration</strong>
|
864
|
+
is the amount of time it took to complete the HTTP call, in milliseconds.
|
865
|
+
</li>
|
866
|
+
<li><strong>Size</strong>
|
867
|
+
is size of the response body, in bytes.
|
868
|
+
</li>
|
869
|
+
</ul>
|
870
|
+
</div>
|
871
|
+
<table id="HttpCallTable" class="tablesorter">
|
872
|
+
<thead>
|
873
|
+
<tr>
|
874
|
+
<th class="sixty">URL</th>
|
875
|
+
<th>Status</th>
|
876
|
+
<th>Start Time</th>
|
877
|
+
<th>Duration</th>
|
878
|
+
<th>Size</th>
|
879
|
+
</tr>
|
880
|
+
</thead>
|
881
|
+
<tbody>
|
882
|
+
<xsl:for-each select="//http_call">
|
883
|
+
<tr>
|
884
|
+
<td class="left"><xsl:value-of select="@url"/></td>
|
885
|
+
<td>
|
886
|
+
<xsl:choose>
|
887
|
+
<xsl:when test="@success='False'">
|
888
|
+
<xsl:attribute name="class">http_failure</xsl:attribute>
|
889
|
+
</xsl:when>
|
890
|
+
</xsl:choose>
|
891
|
+
<xsl:value-of select="@status"/>
|
892
|
+
</td>
|
893
|
+
<td><xsl:value-of select="@start_time"/></td>
|
894
|
+
<td>
|
895
|
+
<div class="info"><xsl:value-of select="@duration"/>
|
896
|
+
<span class="infotooltip"><xsl:value-of select="@timings"/></span>
|
897
|
+
</div>
|
898
|
+
</td>
|
899
|
+
<td><xsl:value-of select="@size"/></td>
|
900
|
+
</tr>
|
901
|
+
</xsl:for-each>
|
902
|
+
</tbody>
|
903
|
+
</table>
|
904
|
+
</div>
|
905
|
+
</xsl:when>
|
906
|
+
</xsl:choose>
|
907
|
+
|
749
908
|
<p></p>
|
750
909
|
<div class="margined">
|
751
910
|
<a href="https://github.com/IBM/javacore-analyser/wiki" target="_blank">Documentation</a>
|
@@ -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.
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#
|
2
|
+
# Copyright IBM Corp. 2024 - 2025
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
4
|
+
#
|
5
|
+
import os
|
6
|
+
|
7
|
+
from haralyzer import HarParser
|
8
|
+
import json
|
9
|
+
|
10
|
+
|
11
|
+
class HarFile:
|
12
|
+
|
13
|
+
def __init__(self, path):
|
14
|
+
self.path = path
|
15
|
+
with open(path, 'r') as f:
|
16
|
+
self.har = HarParser(json.loads(f.read()))
|
17
|
+
|
18
|
+
def get_xml(self, doc):
|
19
|
+
har_file_node = doc.createElement("har_file")
|
20
|
+
har_file_node.setAttribute("filename", os.path.basename(self.path))
|
21
|
+
har_file_node.setAttribute("hostname", str(self.har.hostname))
|
22
|
+
har_file_node.setAttribute("browser", str(self.har.browser))
|
23
|
+
for page in self.har.pages:
|
24
|
+
for entry in page.entries:
|
25
|
+
http_call = HttpCall(entry)
|
26
|
+
har_file_node.appendChild(http_call.get_xml(doc))
|
27
|
+
return har_file_node
|
28
|
+
|
29
|
+
|
30
|
+
class HttpCall:
|
31
|
+
|
32
|
+
def __init__(self, call):
|
33
|
+
self.call = call
|
34
|
+
self.url = call.url
|
35
|
+
self.status = str(call.status)
|
36
|
+
self.start_time = str(call.startTime)
|
37
|
+
self.duration = str(self.get_total_time())
|
38
|
+
self.timings = str(call.timings)
|
39
|
+
self.size = str(call.response.bodySize)
|
40
|
+
self.success = str(self.get_success())
|
41
|
+
|
42
|
+
def get_total_time(self):
|
43
|
+
total = 0
|
44
|
+
if len(self.call.timings) > 0:
|
45
|
+
for key in self.call.timings.keys():
|
46
|
+
time = int(self.call.timings[key])
|
47
|
+
if time > 0:
|
48
|
+
total += time
|
49
|
+
return total
|
50
|
+
|
51
|
+
def get_success(self):
|
52
|
+
if self.status.startswith('4') or self.status.startswith('5'):
|
53
|
+
return False
|
54
|
+
return True
|
55
|
+
|
56
|
+
def get_xml(self, doc):
|
57
|
+
http_call_node = doc.createElement("http_call")
|
58
|
+
http_call_node.setAttribute("url", self.url)
|
59
|
+
http_call_node.setAttribute("status", self.status)
|
60
|
+
http_call_node.setAttribute("start_time", self.start_time)
|
61
|
+
http_call_node.setAttribute("duration", self.duration)
|
62
|
+
http_call_node.setAttribute("timings", self.timings)
|
63
|
+
http_call_node.setAttribute("size", self.size)
|
64
|
+
http_call_node.setAttribute("success", self.success)
|
65
|
+
return http_call_node
|
javacore_analyser/java_thread.py
CHANGED
@@ -8,6 +8,14 @@ from javacore_analyser.abstract_snapshot_collection import AbstractSnapshotColle
|
|
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
|
+
|
11
19
|
def get_hash(self):
|
12
20
|
id_str = self.name + str(self.id)
|
13
21
|
hashcode = abs(hash(id_str))
|
@@ -26,6 +34,11 @@ class Thread(AbstractSnapshotCollection):
|
|
26
34
|
name_node.appendChild(doc.createTextNode(self.name + " (" + str(self.id) + ")"))
|
27
35
|
thread_node.appendChild(name_node)
|
28
36
|
|
37
|
+
# thread address
|
38
|
+
thread_address_node = doc.createElement("thread_address")
|
39
|
+
thread_address_node.appendChild(doc.createTextNode(self.thread_address))
|
40
|
+
thread_node.appendChild(thread_address_node)
|
41
|
+
|
29
42
|
# hash
|
30
43
|
hash_node = doc.createElement("thread_hash")
|
31
44
|
hash_node.appendChild(doc.createTextNode(self.get_hash()))
|
@@ -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
|
|
@@ -12,6 +12,7 @@ import shutil
|
|
12
12
|
import sys
|
13
13
|
import tarfile
|
14
14
|
import tempfile
|
15
|
+
import traceback
|
15
16
|
import zipfile
|
16
17
|
|
17
18
|
import importlib_resources
|
@@ -64,11 +65,6 @@ def extract_archive(input_archive_filename, output_path):
|
|
64
65
|
|
65
66
|
|
66
67
|
def main():
|
67
|
-
logging_utils.create_console_logging()
|
68
|
-
logging.info("IBM Javacore analyser")
|
69
|
-
logging.info("Python version: " + sys.version)
|
70
|
-
logging.info("Preferred encoding: " + locale.getpreferredencoding())
|
71
|
-
|
72
68
|
parser = argparse.ArgumentParser()
|
73
69
|
parser.add_argument("input", help="Input javacore file(s) or directory with javacores. "
|
74
70
|
"The javacores can be packed "
|
@@ -86,12 +82,19 @@ def main():
|
|
86
82
|
output_param = args.output
|
87
83
|
files_separator = args.separator
|
88
84
|
|
85
|
+
batch_process(input_param, output_param, files_separator)
|
86
|
+
|
87
|
+
|
88
|
+
def batch_process(input_param, output_param, files_separator=DEFAULT_FILE_DELIMITER):
|
89
|
+
logging_utils.create_console_logging()
|
90
|
+
logging.info("IBM Javacore analyser")
|
91
|
+
logging.info("Python version: " + sys.version)
|
92
|
+
logging.info("Preferred encoding: " + locale.getpreferredencoding())
|
89
93
|
logging.info("Input parameter: " + input_param)
|
90
94
|
logging.info("Report directory: " + output_param)
|
91
|
-
|
95
|
+
output_param = os.path.normpath(output_param)
|
92
96
|
# Needs to be created once output file structure is ready.
|
93
97
|
logging_utils.create_file_logging(output_param)
|
94
|
-
|
95
98
|
# Check whether as input we got list of files or single file
|
96
99
|
# Semicolon is separation mark for list of input files
|
97
100
|
if files_separator in input_param or fnmatch.fnmatch(input_param, '*javacore*.txt'):
|
@@ -100,6 +103,7 @@ def main():
|
|
100
103
|
else:
|
101
104
|
files = [input_param]
|
102
105
|
try:
|
106
|
+
files = [os.path.normpath(file) for file in files]
|
103
107
|
process_javacores_and_generate_report_data(files, output_param)
|
104
108
|
except Exception as ex:
|
105
109
|
logging.exception(ex)
|
@@ -156,6 +160,15 @@ def create_output_files_structure(output_dir):
|
|
156
160
|
os.path.join(output_dir, "index.html"))
|
157
161
|
|
158
162
|
|
163
|
+
def generate_error_page(output_dir, exception):
|
164
|
+
error_page_text = importlib_resources.read_text("javacore_analyser", "data/html/error.html")
|
165
|
+
tb = traceback.format_exc()
|
166
|
+
file = os.path.join(output_dir, "index.html")
|
167
|
+
f = open(file, "w")
|
168
|
+
f.write(error_page_text.format(stacktrace=tb))
|
169
|
+
f.close()
|
170
|
+
|
171
|
+
|
159
172
|
# Assisted by WCA@IBM
|
160
173
|
# Latest GenAI contribution: ibm/granite-8b-code-instruct
|
161
174
|
def process_javacores_and_generate_report_data(input_files, output_dir):
|
@@ -169,9 +182,14 @@ def process_javacores_and_generate_report_data(input_files, output_dir):
|
|
169
182
|
Returns:
|
170
183
|
None
|
171
184
|
"""
|
172
|
-
|
173
|
-
|
174
|
-
|
185
|
+
try:
|
186
|
+
create_output_files_structure(output_dir)
|
187
|
+
javacore_set = generate_javecore_set_data(input_files)
|
188
|
+
javacore_set.generate_report_files(output_dir)
|
189
|
+
except Exception as ex:
|
190
|
+
logging.exception(ex)
|
191
|
+
logging.error("Processing was not successful. Correct the problem and try again.")
|
192
|
+
generate_error_page(output_dir, ex)
|
175
193
|
|
176
194
|
|
177
195
|
if __name__ == "__main__":
|
@@ -132,9 +132,14 @@ def main():
|
|
132
132
|
args = parser.parse_args()
|
133
133
|
debug = args.debug
|
134
134
|
port = args.port
|
135
|
-
|
136
|
-
|
135
|
+
reports_directory = args.reports_dir
|
136
|
+
|
137
|
+
run_web(debug, port, reports_directory)
|
138
|
+
|
137
139
|
|
140
|
+
def run_web(debug=False, port=5000, reports_directory=DEFAULT_REPORTS_DIR):
|
141
|
+
global reports_dir
|
142
|
+
reports_dir = reports_directory
|
138
143
|
create_console_logging()
|
139
144
|
logging.info("Javacore analyser")
|
140
145
|
logging.info("Python version: " + sys.version)
|
@@ -142,7 +147,6 @@ def main():
|
|
142
147
|
logging.info("Reports directory: " + reports_dir)
|
143
148
|
create_file_logging(reports_dir)
|
144
149
|
create_temp_data_in_reports_dir(reports_dir)
|
145
|
-
|
146
150
|
if debug:
|
147
151
|
app.run(debug=True, port=port) # Run Flask for development
|
148
152
|
else:
|
@@ -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
|
|
@@ -22,6 +22,7 @@ from tqdm import tqdm
|
|
22
22
|
from javacore_analyser import tips
|
23
23
|
from javacore_analyser.code_snapshot_collection import CodeSnapshotCollection
|
24
24
|
from javacore_analyser.constants import *
|
25
|
+
from javacore_analyser.har_file import HarFile
|
25
26
|
from javacore_analyser.java_thread import Thread
|
26
27
|
from javacore_analyser.javacore import Javacore
|
27
28
|
from javacore_analyser.snapshot_collection import SnapshotCollection
|
@@ -67,6 +68,8 @@ class JavacoreSet:
|
|
67
68
|
self.os_level = ""
|
68
69
|
self.architecture = ""
|
69
70
|
self.java_version = ""
|
71
|
+
self.jvm_start_time = ""
|
72
|
+
self.cmd_line = ""
|
70
73
|
self.user_args = []
|
71
74
|
# end of static information
|
72
75
|
self.files = []
|
@@ -87,6 +90,7 @@ class JavacoreSet:
|
|
87
90
|
self.blocked_snapshots = []
|
88
91
|
self.tips = []
|
89
92
|
self.gc_parser = VerboseGcParser()
|
93
|
+
self.har_files = []
|
90
94
|
|
91
95
|
# Assisted by WCA@IBM
|
92
96
|
# Latest GenAI contribution: ibm/granite-8b-code-instruct
|
@@ -140,16 +144,18 @@ class JavacoreSet:
|
|
140
144
|
|
141
145
|
@staticmethod
|
142
146
|
def __generate_placeholder_htmls(placeholder_file, directory, collection, file_prefix):
|
147
|
+
logging.info(f"Generating placeholder htmls in {directory}")
|
143
148
|
if os.path.exists(directory):
|
144
149
|
shutil.rmtree(directory)
|
145
150
|
os.mkdir(directory)
|
146
151
|
|
147
|
-
for element in tqdm(collection, desc="Generating placeholder htmls", unit="
|
152
|
+
for element in tqdm(collection, desc="Generating placeholder htmls", unit=" files"):
|
148
153
|
filename = file_prefix + "_" + element.get_id() + ".html"
|
149
154
|
if filename.startswith("_"):
|
150
155
|
filename = filename[1:]
|
151
156
|
file_path = os.path.join(directory, filename)
|
152
157
|
shutil.copy2(placeholder_file, file_path)
|
158
|
+
logging.info("Finished generating placeholder htmls")
|
153
159
|
|
154
160
|
def __generate_htmls_for_threads(self, output_dir, temp_dir_name):
|
155
161
|
_create_xml_xsl_for_collection(os.path.join(temp_dir_name, "threads"),
|
@@ -187,6 +193,8 @@ class JavacoreSet:
|
|
187
193
|
logging.debug("Architecture: {}".format(self.architecture))
|
188
194
|
logging.debug("Java version: {}".format(self.java_version))
|
189
195
|
logging.debug("OS Level: {}".format(self.os_level))
|
196
|
+
logging.debug("JVM Startup time: {}".format(self.jvm_start_time))
|
197
|
+
logging.debug("Command line: {}".format(self.cmd_line))
|
190
198
|
|
191
199
|
@staticmethod
|
192
200
|
def create(path):
|
@@ -230,6 +238,9 @@ class JavacoreSet:
|
|
230
238
|
if fnmatch.fnmatch(file, '*verbosegc*.txt*'):
|
231
239
|
self.gc_parser.add_file(dirpath + os.sep + file)
|
232
240
|
logging.info("VerboseGC file found: " + file)
|
241
|
+
if fnmatch.fnmatch(file, "*.har"):
|
242
|
+
self.har_files.append(HarFile(dirpath + os.sep + file))
|
243
|
+
logging.info("HAR file found: " + file)
|
233
244
|
|
234
245
|
# sorting files by name.
|
235
246
|
# Unless the user changed the javacore file name format, this is equivalent to sorting by date
|
@@ -260,6 +271,12 @@ class JavacoreSet:
|
|
260
271
|
elif line.startswith(JAVA_VERSION):
|
261
272
|
self.java_version = line[len(JAVA_VERSION) + 1:].strip()
|
262
273
|
continue
|
274
|
+
elif line.startswith(STARTTIME):
|
275
|
+
self.jvm_start_time = line[line.find(":") + 1:].strip()
|
276
|
+
continue
|
277
|
+
elif line.startswith(CMD_LINE):
|
278
|
+
self.cmd_line = line[len(CMD_LINE) + 1:].strip()
|
279
|
+
continue
|
263
280
|
except Exception as ex:
|
264
281
|
logging.exception(ex)
|
265
282
|
logging.error(f'Error during processing file: {file.name} \n'
|
@@ -385,6 +402,8 @@ class JavacoreSet:
|
|
385
402
|
|
386
403
|
verbose_gc_list_node = self.doc.createElement("verbose_gc_list")
|
387
404
|
report_info_node.appendChild(verbose_gc_list_node)
|
405
|
+
|
406
|
+
total_collects_in_time_limits = 0
|
388
407
|
for vgc in self.gc_parser.get_files():
|
389
408
|
verbose_gc_node = self.doc.createElement("verbose_gc")
|
390
409
|
verbose_gc_list_node.appendChild(verbose_gc_node)
|
@@ -394,9 +413,17 @@ class JavacoreSet:
|
|
394
413
|
verbose_gc_collects_node = self.doc.createElement("verbose_gc_collects")
|
395
414
|
verbose_gc_node.appendChild(verbose_gc_collects_node)
|
396
415
|
verbose_gc_collects_node.appendChild(self.doc.createTextNode(str(vgc.get_number_of_collects())))
|
416
|
+
total_collects_in_time_limits += vgc.get_number_of_collects()
|
397
417
|
verbose_gc_total_collects_node = self.doc.createElement("verbose_gc_total_collects")
|
398
418
|
verbose_gc_node.appendChild(verbose_gc_total_collects_node)
|
399
419
|
verbose_gc_total_collects_node.appendChild(self.doc.createTextNode(str(vgc.get_total_number_of_collects())))
|
420
|
+
verbose_gc_list_node.setAttribute("total_collects_in_time_limits", str(total_collects_in_time_limits))
|
421
|
+
|
422
|
+
if len(self.har_files) > 0:
|
423
|
+
har_files_node = self.doc.createElement("har_files")
|
424
|
+
doc_node.appendChild(har_files_node)
|
425
|
+
for har in self.har_files:
|
426
|
+
har_files_node.appendChild(har.get_xml(self.doc))
|
400
427
|
|
401
428
|
system_info_node = self.doc.createElement("system_info")
|
402
429
|
doc_node.appendChild(system_info_node)
|
@@ -455,6 +482,14 @@ class JavacoreSet:
|
|
455
482
|
system_info_node.appendChild(os_level_node)
|
456
483
|
os_level_node.appendChild(self.doc.createTextNode(self.os_level))
|
457
484
|
|
485
|
+
jvm_startup_time = self.doc.createElement("jvm_start_time")
|
486
|
+
system_info_node.appendChild(jvm_startup_time)
|
487
|
+
jvm_startup_time.appendChild(self.doc.createTextNode(self.jvm_start_time))
|
488
|
+
|
489
|
+
cmd_line = self.doc.createElement("cmd_line")
|
490
|
+
system_info_node.appendChild(cmd_line)
|
491
|
+
cmd_line.appendChild(self.doc.createTextNode(self.cmd_line))
|
492
|
+
|
458
493
|
doc_node.appendChild(self.get_blockers_xml())
|
459
494
|
doc_node.appendChild(self.threads.get_xml(self.doc))
|
460
495
|
doc_node.appendChild(self.stacks.get_xml(self.doc))
|
@@ -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)
|
@@ -155,7 +143,6 @@ class VerboseGcFile:
|
|
155
143
|
gets the total number of gc collections in this VerboseGcFile
|
156
144
|
regardless of the time when tey occurred with regards to the javacores
|
157
145
|
'''
|
158
|
-
|
159
146
|
def get_total_number_of_collects(self):
|
160
147
|
if self.__total_number_of_collects < 0:
|
161
148
|
self.get_collects()
|
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: javacore_analyser
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.2
|
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
|
7
|
-
Project-URL: Changelog, https://github.com/IBM/javacore-analyser/CHANGELOG.md
|
7
|
+
Project-URL: Changelog, https://github.com/IBM/javacore-analyser/blob/main/CHANGELOG.md
|
8
8
|
Project-URL: Source, https://github.com/IBM/javacore-analyser
|
9
9
|
Author-email: Krzysztof Kazmierczyk <kazm@ibm.com>, Piotr Aniola <Piotr.Aniola@ibm.com>, Tadeusz Janasiewicz <t.janasiewicz@ibm.com>
|
10
10
|
License: Apache License
|
@@ -228,6 +228,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
228
228
|
Classifier: Programming Language :: Python :: 3.13
|
229
229
|
Requires-Python: >=3.9
|
230
230
|
Requires-Dist: flask
|
231
|
+
Requires-Dist: haralyzer
|
231
232
|
Requires-Dist: importlib-resources
|
232
233
|
Requires-Dist: lxml
|
233
234
|
Requires-Dist: py7zr
|
@@ -239,8 +240,18 @@ Description-Content-Type: text/markdown
|
|
239
240
|
<!-- This should be the location of the title of the repository, normally the short name -->
|
240
241
|
# Javacore Analyser
|
241
242
|
|
243
|
+

|
244
|
+

|
245
|
+

|
242
246
|
<!-- Build Status, is a great thing to have at the top of your repository, it shows that you take your CI/CD as first class citizens -->
|
243
247
|
[](https://app.travis-ci.com/IBM/javacore-analyser)
|
248
|
+

|
249
|
+

|
250
|
+

|
251
|
+

|
252
|
+

|
253
|
+

|
254
|
+
|
244
255
|
|
245
256
|
<!-- Not always needed, but a scope helps the user understand in a short sentance like below, why this repo exists -->
|
246
257
|
## Scope
|
@@ -267,7 +278,8 @@ Steps:
|
|
267
278
|
3. Run the following command:
|
268
279
|
`pip install javacore-analyser`
|
269
280
|
OR
|
270
|
-
`pip install --
|
281
|
+
`pip install --pre javacore-analyser` - if you want an experimental version
|
282
|
+
|
271
283
|
|
272
284
|
#### Installing from sources
|
273
285
|
This is recommended for geeks only:
|
@@ -281,32 +293,39 @@ This is recommended for geeks only:
|
|
281
293
|
#### Running cmd application:
|
282
294
|
1. Install application if not done yet
|
283
295
|
2. Activate your created virtual environment according to activate Virtual Environment according to [Creating virtual environments](https://docs.python.org/3/tutorial/venv.html#creating-virtual-environments)
|
284
|
-
3. Run the following command from cmd:
|
296
|
+
3. Run the following command from cmd:
|
297
|
+
`javacore-analyser-batch <input-data> <generated-reports-dir>`
|
298
|
+
or
|
299
|
+
`python -m javacore_analyser batch <input-data> <generated-reports-dir>`
|
300
|
+
|
285
301
|
Where `<input-data>` is one of the following:
|
286
302
|
* The directory containing javacores and optionally verbose gc
|
287
303
|
* Archive (7z, zip, tar.gz, tar.bz2) containing the same
|
288
304
|
* List of the javacores separated by `;` character. Optionally you can add `--separator` option to define your own separator.
|
289
305
|
You can type the following command to obtain the help:
|
290
|
-
`javacore-analyser-batch --help`
|
306
|
+
`javacore-analyser-batch --help` or `python -m javacore_analyser batch --help`
|
291
307
|
|
292
308
|
#### Running web application:
|
293
309
|
1. Repeat steps 1-3 from cmd application
|
294
310
|
2. Execute the following command from cmd:
|
295
|
-
`javacore_analyser_web --port=
|
311
|
+
`javacore_analyser_web --port=5000 --reports-dir=/data/reports_dir`
|
312
|
+
or
|
313
|
+
`python -m javacore_analyser web --port=5000 --reports-dir=/data/reports_dir`
|
314
|
+
|
296
315
|
|
297
|
-
|
298
|
-
|
316
|
+
The first parameter set the port to use by application. If not specified, 5000 will be used.
|
317
|
+
The second parameter sets where the reports need to be stored. If not set, then the `reports` dir will be created in current location.
|
299
318
|
|
300
|
-
|
319
|
+
Now you can type (http://localhost:5000/).
|
301
320
|
|
302
321
|
### Running container image
|
303
|
-
There is
|
322
|
+
There is a Docker/Podman container managed by one of projects developers. Use the following command
|
304
323
|
to start it:
|
305
324
|
|
306
|
-
`podman run -it --rm --name javacore-analyser --mount type=bind,src="/local-reports-dir",target=/reports -p 5001:5000 ghcr.io/
|
325
|
+
`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`
|
307
326
|
|
308
327
|
or
|
309
|
-
`docker run -it --rm --name javacore-analyser --mount type=bind,src="/local-reports-dir",target=/reports -p 5001:5000 ghcr.io/
|
328
|
+
`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`
|
310
329
|
|
311
330
|
The `mount` option specifies where you want locally to store the reports. The reports in the container are stored in
|
312
331
|
`/reports` directory. If you remove mount option, the application will work but the reports will not persist after
|
@@ -1,23 +1,26 @@
|
|
1
1
|
javacore_analyser/__init__.py,sha256=Sw2ZeqcI2Kx1cDDv083n1SiSY_FDRCmidTuzaN1uRSw,76
|
2
|
+
javacore_analyser/__main__.py,sha256=wQCPgu8Gp7XczyNckNGmY30c5YMUMRByW7jrdFO0OBY,1694
|
2
3
|
javacore_analyser/abstract_snapshot_collection.py,sha256=jGfd2XgujurRlKgEtlJjqNJK9sUvTdFsdgFnX9oLzt4,5589
|
3
4
|
javacore_analyser/code_snapshot_collection.py,sha256=6_C5myag5ocjOTwXVDbBamN6Lf1szgS3ylSHEEjUdVg,2655
|
4
|
-
javacore_analyser/constants.py,sha256=
|
5
|
-
javacore_analyser/
|
5
|
+
javacore_analyser/constants.py,sha256=7-gbGLzUMIMe2UvmLT17ymmy_r_izadpAyhrEKFonP8,1054
|
6
|
+
javacore_analyser/har_file.py,sha256=grXpfIyPek9xQ5jp3_AYOB5JDELd17o4O4rYELxWO7w,2131
|
7
|
+
javacore_analyser/java_thread.py,sha256=0Qh857o0M05sO_WRkNM5DFtBK03HytUwdMp7Ha1WXGI,4916
|
6
8
|
javacore_analyser/javacore.py,sha256=_2abTyvXEaZ6Tx8r9d3NEzRCIBcf4Is8lSjpKyPu-R8,6884
|
7
|
-
javacore_analyser/javacore_analyser_batch.py,sha256=
|
8
|
-
javacore_analyser/javacore_analyser_web.py,sha256=
|
9
|
-
javacore_analyser/javacore_set.py,sha256=
|
9
|
+
javacore_analyser/javacore_analyser_batch.py,sha256=D9H6ct_PBAXR_PvTqGtKw_FIx9Q9KuJSFBeEZ2FIkbo,7607
|
10
|
+
javacore_analyser/javacore_analyser_web.py,sha256=o-Spq119Wi7w4pvBa7M7ZrxiZnzKmWqDhCdGtEReQAU,5951
|
11
|
+
javacore_analyser/javacore_set.py,sha256=g-1NtOJ6r6HB6JqzIWVPjFJrXGNweBJx7WoavkF0ggE,32995
|
10
12
|
javacore_analyser/logging_utils.py,sha256=vLob0ikezysjGv9XGqv9GbLekxu4eO_csq22M-gtLiQ,966
|
11
13
|
javacore_analyser/snapshot_collection.py,sha256=fLEnwg9-cOjVVUUludtzI7R2yO9BBVgJgxkhvqG5QDg,443
|
12
14
|
javacore_analyser/snapshot_collection_collection.py,sha256=1PV1TX4QQk01dAbX-k-kTpgKr6Il867Bw6X7HHBuv-Q,1346
|
13
15
|
javacore_analyser/stack_trace.py,sha256=8sb8z4ac_L0yyxqJX1ukrTZRyngkHcA3zkXyqxG5ygA,1664
|
14
16
|
javacore_analyser/stack_trace_element.py,sha256=pZPrK1ACBUDE7YsVOFhTfewXequ1m5P-B0N-9RuhkWo,1143
|
15
17
|
javacore_analyser/stack_trace_kind.py,sha256=lOdfb_F3XrwDLciPk_ZgM_fmMn5JoXsIUjr7pjvmU4M,157
|
16
|
-
javacore_analyser/thread_snapshot.py,sha256=
|
17
|
-
javacore_analyser/tips.py,sha256=
|
18
|
-
javacore_analyser/verbose_gc.py,sha256=
|
18
|
+
javacore_analyser/thread_snapshot.py,sha256=yp7uJwF5adMN2UAhOn-lLtSP2X3j8utUfafjyKu8r4E,13252
|
19
|
+
javacore_analyser/tips.py,sha256=JggNTmCkH2x2jqFChdnWlex8hU9q3Gy5IqJaxDQtPwI,8625
|
20
|
+
javacore_analyser/verbose_gc.py,sha256=FdSzj9bB9GrJVM8qzkvjNm0LsJZRvKWpd2oMQ8G8eEE,6373
|
19
21
|
javacore_analyser/data/expand.js,sha256=KwqvNUoO7yMDeQKcnLDywfMdR3Zsjan5L8QoPsQQLGo,956
|
20
|
-
javacore_analyser/data/style.css,sha256=
|
22
|
+
javacore_analyser/data/style.css,sha256=HSKPajW3EItHjye6mSGNMRPEzfE2r7o1Gq-BEAI54Ts,2879
|
23
|
+
javacore_analyser/data/html/error.html,sha256=dJI5RdeNL1E4Y-zaU7NTBqrsxCuAovVc1Cebrk5GcYA,520
|
21
24
|
javacore_analyser/data/html/processing_data.html,sha256=S1S2GMXQ8oQdqdYTcPzVMxUib-NLtM4ffT3OJaIIO7w,421
|
22
25
|
javacore_analyser/data/jquery/chart.js,sha256=tgiW1vJqfIKxE0F2uVvsXbgUlTyrhPMY_sm30hh_Sxc,203464
|
23
26
|
javacore_analyser/data/jquery/chartjs-adapter-date-fns.bundle.min.js,sha256=6nqzDSbDjc8fLSa7Q-c6lFN7WPGQb1XhpUbdCTIbVhU,50650
|
@@ -28,18 +31,18 @@ javacore_analyser/data/jquery/jquery.tablesorter.min.js,sha256=dtGH1XcAyKopMui5x
|
|
28
31
|
javacore_analyser/data/jquery/jquery.tablesorter.widgets.min.js,sha256=GxbszpUzg-iYIcyDGyNVLz9Y0dQvzmQgXXVk5cHJbw0,53100
|
29
32
|
javacore_analyser/data/jquery/search.js,sha256=Jwi-cBJ9YKDHJwqIlcKXqrpcM1BX-wx93uKAR44JLww,4200
|
30
33
|
javacore_analyser/data/jquery/sorting.js,sha256=HsuVLa7F70IM4ZMXZpjj7wtVI1TXL1SPbZGWenv0Jp8,369
|
31
|
-
javacore_analyser/data/jquery/theme.blue.css,sha256=
|
34
|
+
javacore_analyser/data/jquery/theme.blue.css,sha256=cPcj8KaUj_zNy_xtDfrodSLue94nnYgyVNIZRusggCw,7624
|
32
35
|
javacore_analyser/data/jquery/theme.default.min.css,sha256=5sgExNTnkN8NcApKIU73_aqgZmqq_zJp9-9zXf9aSEw,4502
|
33
|
-
javacore_analyser/data/jquery/wait2scripts.js,sha256=
|
36
|
+
javacore_analyser/data/jquery/wait2scripts.js,sha256=jORUs9xgz_o-VnRm0RxjKlraZOleQrPp5DmTyrMBwrM,8577
|
34
37
|
javacore_analyser/data/xml/index.xml,sha256=9VH2rmri3FQpXcW39kbyi2dON94C5XTiaQn0ioExCe8,282
|
35
|
-
javacore_analyser/data/xml/report.xsl,sha256=
|
38
|
+
javacore_analyser/data/xml/report.xsl,sha256=uum_nBGzSyCa8LL51xjWQXUxYxo-1VR9wkhJrS_dbnI,59605
|
36
39
|
javacore_analyser/data/xml/javacores/javacore.xml,sha256=6dG89Whx1_kpEYVS_F6Upa2XuXnXorlQATFc8kD5Mfc,280
|
37
40
|
javacore_analyser/data/xml/javacores/javacore.xsl,sha256=5cnIp08Q9FccljHH8duoJQYofyW8lwUCGtpdzz5Y0Y8,11644
|
38
41
|
javacore_analyser/data/xml/threads/thread.xml,sha256=6dG89Whx1_kpEYVS_F6Upa2XuXnXorlQATFc8kD5Mfc,280
|
39
|
-
javacore_analyser/data/xml/threads/thread.xsl,sha256=
|
42
|
+
javacore_analyser/data/xml/threads/thread.xsl,sha256=1tg5tImtr1gyZ8Q61tqIukNtm1fQ6R8YoKC3EgIjLRA,14084
|
40
43
|
javacore_analyser/templates/index.html,sha256=aEuyry-HZ9HlQNwfbugugvqbSxwlo7LrQnrDmqO34YE,1682
|
41
|
-
javacore_analyser-2.
|
42
|
-
javacore_analyser-2.
|
43
|
-
javacore_analyser-2.
|
44
|
-
javacore_analyser-2.
|
45
|
-
javacore_analyser-2.
|
44
|
+
javacore_analyser-2.2.dist-info/METADATA,sha256=6VrRhosJvtsfgvoRi60G5ZZ5EvylO0PwcKvLEK5RXbY,22206
|
45
|
+
javacore_analyser-2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
46
|
+
javacore_analyser-2.2.dist-info/entry_points.txt,sha256=W3S799zI58g5-jWMsC3wY9xksz21LPEMYOILv8sayfM,160
|
47
|
+
javacore_analyser-2.2.dist-info/licenses/LICENSE,sha256=xllut76FgcGL5zbIRvuRc7aezPbvlMUTWJPsVr2Sugg,11358
|
48
|
+
javacore_analyser-2.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|