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.
@@ -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()
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright IBM Corp. 2024 - 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
- Blue Theme
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.classList.remove('hide');
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 > timestamp;
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
- inputData.push(Number(rowEl.cells[3].innerHTML));
262
- labels.push(String(rowEl.cells[0].innerHTML));
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, {
@@ -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 - 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>Wait Report</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
- <div id="memusagedoc" style="display:none;">
359
- This chart shows all the garbage collections that happened between the time
360
- of the first and the last javacore in the data set.
361
- Garbage collections that happened before the first
362
- or after the last javacore generation time are not included.
363
- <ul>
364
- <li><strong>Heap Usage</strong>
365
- is the available Java heap memory over time,
366
- based on the garbage collection data from the verbose GC log files.
367
- </li>
368
- <li><strong>Total Heap</strong>
369
- is the maximum size of the Java heap, configured by using the Xmx Java argument,
370
- expressed in megabytes.
371
- </li>
372
- </ul>
373
- </div>
374
- <div id="systemresources_myChartGC" class="chart-container hide">
375
- <canvas id="myChartGC" height="200"></canvas>
376
- </div>
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><xsl:value-of select="thread_name"/></a>
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>Wait Report for thread: <b><xsl:value-of select="thread_name"/></b></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
@@ -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 - 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
- create_output_files_structure(output_dir)
173
- javacore_set = generate_javecore_set_data(input_files)
174
- javacore_set.generate_report_files(output_dir)
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
- global reports_dir
136
- reports_dir = args.reports_dir
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 - 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=" file"):
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 received
77
- from the customer and run WAIT2 only against the ones that are applicable for the issue you are investigating. """
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 WAIT2 report with only one javacore.
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
@@ -1,11 +1,12 @@
1
1
  #
2
- # Copyright IBM Corp. 2024 - 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
- xml_text = ""
117
- root_closing_tag_available = False
118
- file = open(self.__path, 'r+')
119
- lines = file.readlines()
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("&#x1;", "?")
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("&#x1;", "?")
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.1rc5
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
+ ![GitHub License](https://img.shields.io/github/license/IBM/javacore-analyser)
244
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/javacore-analyser)
245
+ ![GitHub contributors](https://img.shields.io/github/contributors/IBM/javacore-analyser)
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
  [![Build Status](https://app.travis-ci.com/IBM/javacore-analyser.svg?token=w3i4X11XppEi2tJQsxDb&branch=main)](https://app.travis-ci.com/IBM/javacore-analyser)
248
+ ![GitHub last commit](https://img.shields.io/github/last-commit/IBM/javacore-analyser)
249
+ ![GitHub Release Date](https://img.shields.io/github/release-date/IBM/javacore-analyser)
250
+ ![GitHub commit activity](https://img.shields.io/github/commit-activity/t/IBM/javacore-analyser)
251
+ ![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr/IBM/javacore-analyser)
252
+ ![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr-closed/IBM/javacore-analyser)
253
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/javacore-analyser)
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 --extra-index-url https://test.pypi.org/simple/ javacore-analyser` - if you want an experimental version
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: `javacore-analyser-batch <input-data> <generated-reports-dir>`
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=500 --reports-dir=/data/reports_dir`
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
- The first parameter set the port to use by application. If not specified, 5000 will be used.
298
- 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
+ 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
- Now you can type (http://localhost:5000/).
319
+ Now you can type (http://localhost:5000/).
301
320
 
302
321
  ### Running container image
303
- There is an unofficial Docker/Podman container managed by one of projects developers. Use the following command
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/kkazmierczyk/javacore-analyser:latest`
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/kkazmierczyk/javacore-analyser:latest`
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=iGYAznPK8AySq6uqk-cpCU8Dbjbq6PrCh6q2mF8oeu8,1003
5
- javacore_analyser/java_thread.py,sha256=4zUfmmlH47SrIxgfPmrJHl_YUziVJXVNVedD5X25vXY,4464
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=g6xVPYFDHTaXDbaruyMRUrD3g2IlJK3Ht-XUzHv3LoQ,6802
8
- javacore_analyser/javacore_analyser_web.py,sha256=Ef91ZTI5TBaJPJhl0FtzrFHvzJNPLe07fmvbvik3OJQ,5788
9
- javacore_analyser/javacore_set.py,sha256=YM6ZKUhbfqzjuKE5y7Jy19Hbl-BSLA1i5gIsP7NbX38,31241
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=2Do8NPBXdpUezQrUI_9nyGbtU4b2s5euPnHqcuuKq7U,13255
17
- javacore_analyser/tips.py,sha256=EhwLUAha0FvFJtO5kmvba9a1nKXGdqNHFa2jFbHZr4U,8655
18
- javacore_analyser/verbose_gc.py,sha256=LLJ-PS2maOkP6zfW-RBGoEoHQBI99Reejb1tqpZispY,6872
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=YzHl0NSnfRik4ar6AInp7pZ_re1rirQy6L5jqdbKoKg,2246
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=mI0RCGd6G5GOKSG7BPagp0N58xipSjPXUKvrcHJ4h1Q,7528
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=CMbSqte7Ln0hP9ZScESGdIDfWEmxJwvfLZjDfYNc1Sg,8427
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=XEwgf0qfXL1fXjj-X5iYYwt-D0cPjI9mLjhTmRvyNnk,49697
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=rkqr5GQ2aZ_xrdhUjl2QZDCZ-09zxqUmtV8DFZVjTAA,13927
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.1rc5.dist-info/METADATA,sha256=CMlVgoGP1Fnpof2ycHYf2Auj6XOLRdrO5Q7Jcgr5oVo,21226
42
- javacore_analyser-2.1rc5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- javacore_analyser-2.1rc5.dist-info/entry_points.txt,sha256=W3S799zI58g5-jWMsC3wY9xksz21LPEMYOILv8sayfM,160
44
- javacore_analyser-2.1rc5.dist-info/licenses/LICENSE,sha256=xllut76FgcGL5zbIRvuRc7aezPbvlMUTWJPsVr2Sugg,11358
45
- javacore_analyser-2.1rc5.dist-info/RECORD,,
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,,