javacore-analyser 2.0rc1__py3-none-any.whl → 2.1.0.dev66__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.
@@ -20,177 +20,186 @@
20
20
  <script type="text/javascript" src="../data/jquery/chart.js"> _ </script>
21
21
  <script type="text/javascript" src="../data/jquery/chartjs-adapter-date-fns.bundle.min.js"> _ </script>
22
22
  <script type="text/javascript" src="../data/jquery/wait2scripts.js"> _ </script>
23
-
23
+ <script src="../data/jquery/jquery.mark.min.js"> _ </script>
24
+ <script type="text/javascript" src="../data/jquery/search.js"> _ </script>
24
25
  </head>
25
-
26
26
  <body id="doc_body" height="100%">
27
- <p class="right"><a href="../index.html"> Back to Main page </a></p>
28
- <h2>Wait Report for thread: <b><xsl:value-of select="thread_name"/></b></h2>
29
- <xsl:choose>
30
- <xsl:when test="//javacore_count = 1">
31
- System resource utilization data cannot be calculated with only a single javacore.
32
- </xsl:when>
33
- <xsl:otherwise>
34
- <div class="chart-container" height="25%">
35
- <canvas id="myChart" height="100%"></canvas>
36
- </div>
37
- </xsl:otherwise>
38
- </xsl:choose>
39
- <div id="all_threads">
40
- <table id="all_threads_table_thread_xsl">
41
- <thead>
42
- <tr>
43
- <th>Timestamp</th>
44
- <th>Elapsed time (s)</th>
45
- <th>CPU usage (s)</th>
46
- <th>% CPU usage</th>
47
- <th class='sixty'>Stack trace</th>
48
- <th>State</th>
49
- <th>Blocking</th>
50
- </tr>
51
- </thead>
52
- <!-- Snapshot starts here -->
53
- <xsl:for-each select="*[starts-with(name(), 'stack')]">
54
- <tr>
55
- <td>
56
- <a>
57
- <xsl:attribute name="href">
58
- ../javacores/<xsl:value-of select="file_name"/>.html
59
- </xsl:attribute>
60
- <xsl:value-of select='timestamp'/>
61
- </a>
62
- </td>
63
- <xsl:choose>
64
- <xsl:when test="position()=1">
65
- <td>N/A</td>
66
- </xsl:when>
67
- <xsl:otherwise>
68
- <td>
69
- <xsl:value-of select='format-number(elapsed_time, "0.##")'/>
70
- </td>
71
- </xsl:otherwise>
72
- </xsl:choose>
73
- <xsl:choose>
74
- <xsl:when test="position()=1">
75
- <td>N/A</td>
76
- </xsl:when>
77
- <xsl:otherwise>
78
- <td><xsl:value-of select='format-number(cpu_usage, "0.##")'/></td>
79
- </xsl:otherwise>
80
- </xsl:choose>
81
- <xsl:choose>
27
+ <div class="searchbar">
28
+ <input id="search-input" type="search" />
29
+ <button data-search="search" id="search-button">Search</button>
30
+ <button data-search="next">Next</button>
31
+ <button data-search="prev">Prev</button>
32
+ <button data-search="clear">✖</button>
33
+ </div>
34
+ <div class="content">
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>
37
+ <xsl:choose>
38
+ <xsl:when test="//javacore_count = 1">
39
+ System resource utilization data cannot be calculated with only a single javacore.
40
+ </xsl:when>
41
+ <xsl:otherwise>
42
+ <div class="chart-container" height="25%">
43
+ <canvas id="myChart" height="100%"></canvas>
44
+ </div>
45
+ </xsl:otherwise>
46
+ </xsl:choose>
47
+ <div id="all_threads">
48
+ <table id="all_threads_table_thread_xsl">
49
+ <thead>
50
+ <tr>
51
+ <th>Timestamp</th>
52
+ <th>Elapsed time (s)</th>
53
+ <th>CPU usage (s)</th>
54
+ <th>% CPU usage</th>
55
+ <th class='sixty'>Stack trace</th>
56
+ <th>State</th>
57
+ <th>Blocking</th>
58
+ </tr>
59
+ </thead>
60
+ <!-- Snapshot starts here -->
61
+ <xsl:for-each select="*[starts-with(name(), 'stack')]">
62
+ <tr>
63
+ <td>
64
+ <a>
65
+ <xsl:attribute name="href">
66
+ ../javacores/<xsl:value-of select="file_name"/>.html
67
+ </xsl:attribute>
68
+ <xsl:value-of select='timestamp'/>
69
+ </a>
70
+ </td>
71
+ <xsl:choose>
82
72
  <xsl:when test="position()=1">
83
73
  <td>N/A</td>
84
74
  </xsl:when>
85
75
  <xsl:otherwise>
86
- <td><xsl:value-of select='format-number(cpu_percentage, "0.#")'/></td>
76
+ <td>
77
+ <xsl:value-of select='format-number(elapsed_time, "0.##")'/>
78
+ </td>
87
79
  </xsl:otherwise>
88
80
  </xsl:choose>
89
- <td class="left">
90
- <div>
91
- <xsl:choose>
92
- <xsl:when test="stack_depth &gt; 0">
93
- <div class="toggle_expand">
94
- <a href="javaScript:;" class="show">[+] Expand</a>
95
- </div>
96
- <p class="stacktrace">
97
- <xsl:for-each select="*[starts-with(name(), 'line')]">
98
- <span>
99
- <xsl:attribute name="class"><xsl:value-of select="@kind"/></xsl:attribute>
100
- <xsl:value-of select="current()"/>
101
- </span>
102
- <br/>
103
- </xsl:for-each>
104
- </p>
81
+ <xsl:choose>
82
+ <xsl:when test="position()=1">
83
+ <td>N/A</td>
84
+ </xsl:when>
85
+ <xsl:otherwise>
86
+ <td><xsl:value-of select='format-number(cpu_usage, "0.##")'/></td>
87
+ </xsl:otherwise>
88
+ </xsl:choose>
89
+ <xsl:choose>
90
+ <xsl:when test="position()=1">
91
+ <td>N/A</td>
105
92
  </xsl:when>
106
93
  <xsl:otherwise>
107
- No Stack
94
+ <td><xsl:value-of select='format-number(cpu_percentage, "0.#")'/></td>
108
95
  </xsl:otherwise>
109
96
  </xsl:choose>
110
- </div>
111
- </td>
112
- <xsl:choose>
113
- <xsl:when test="state='CW'">
114
- <td class="waiting">
115
- <xsl:choose>
116
- <xsl:when test="blocked_by=''">
117
- Waiting on condition
118
- </xsl:when>
119
- <xsl:otherwise>
120
- <a target="_blank">
121
- <xsl:attribute name="href">
122
- <xsl:value-of select="concat('thread_', blocked_by/@thread_hash, '.html')"/>
123
- </xsl:attribute>
124
- <xsl:attribute name="title">
125
- <xsl:value-of select="blocked_by/@name" />
126
- </xsl:attribute>
127
- Waiting for <xsl:value-of select="blocked_by/@thread_id"/>
128
- </a>
129
- </xsl:otherwise>
130
- </xsl:choose>
131
- </td>
132
- </xsl:when>
133
- <xsl:when test="state='R'">
134
- <td class="runnable">Runnable</td>
135
- </xsl:when>
136
- <xsl:when test="state='P'">
137
- <td class="parked">
97
+ <td class="left">
98
+ <div>
138
99
  <xsl:choose>
139
- <xsl:when test="blocked_by=''">
140
- Parked
100
+ <xsl:when test="stack_depth &gt; 0">
101
+ <div class="toggle_expand">
102
+ <a href="javaScript:;" class="show">[+] Expand</a>
103
+ </div>
104
+ <p class="stacktrace">
105
+ <xsl:for-each select="*[starts-with(name(), 'line')]">
106
+ <span>
107
+ <xsl:attribute name="class"><xsl:value-of select="@kind"/></xsl:attribute>
108
+ <xsl:value-of select="current()"/>
109
+ </span>
110
+ <br/>
111
+ </xsl:for-each>
112
+ </p>
141
113
  </xsl:when>
142
114
  <xsl:otherwise>
143
- <a target="_blank">
144
- <xsl:attribute name="href">
145
- <xsl:value-of select="concat('thread_', blocked_by/@thread_hash, '.html')"/>
146
- </xsl:attribute>
147
- <xsl:attribute name="title">
148
- <xsl:value-of select="blocked_by/@name" />
149
- </xsl:attribute>
150
- Parked on <xsl:value-of select="blocked_by/@thread_id"/>
151
- </a>
115
+ No Stack
152
116
  </xsl:otherwise>
153
117
  </xsl:choose>
154
- </td>
155
- </xsl:when>
156
- <xsl:when test="state='B'">
157
- <td class="blocked">
158
- <a target="_blank">
159
- <xsl:attribute name="href">
160
- <xsl:value-of select="concat('thread_', blocked_by/@thread_hash, '.html')"/>
161
- </xsl:attribute>
162
- <xsl:attribute name="title">
163
- <xsl:value-of select="blocked_by/@name" />
164
- </xsl:attribute>
165
- Blocked by <xsl:value-of select="blocked_by/@thread_id"/>
166
- </a>
167
- </td>
168
- </xsl:when>
169
- <xsl:otherwise>
170
- <td><xsl:value-of select="state"/></td>
171
- </xsl:otherwise>
172
- </xsl:choose>
173
- <td>
118
+ </div>
119
+ </td>
174
120
  <xsl:choose>
175
- <xsl:when test="blocking/thread">
176
- blocking:
177
- <xsl:for-each select="blocking/thread">
178
- <a target="_blank">
179
- <xsl:attribute name="href">
180
- <xsl:value-of select="concat('thread_', @thread_hash, '.html')"/>
181
- </xsl:attribute>
182
- <xsl:attribute name="title">
183
- <xsl:value-of select="@name" />
184
- </xsl:attribute>
185
- <xsl:value-of select="@thread_id" />
186
- </a>;
187
- </xsl:for-each>
188
- </xsl:when>
189
- </xsl:choose>
190
- </td>
191
- </tr>
192
- </xsl:for-each>
193
- </table>
121
+ <xsl:when test="state='CW'">
122
+ <td class="waiting">
123
+ <xsl:choose>
124
+ <xsl:when test="blocked_by=''">
125
+ Waiting on condition
126
+ </xsl:when>
127
+ <xsl:otherwise>
128
+ <a target="_blank">
129
+ <xsl:attribute name="href">
130
+ <xsl:value-of select="concat('thread_', blocked_by/@thread_hash, '.html')"/>
131
+ </xsl:attribute>
132
+ <xsl:attribute name="title">
133
+ <xsl:value-of select="blocked_by/@name" />
134
+ </xsl:attribute>
135
+ Waiting for <xsl:value-of select="blocked_by/@thread_id"/>
136
+ </a>
137
+ </xsl:otherwise>
138
+ </xsl:choose>
139
+ </td>
140
+ </xsl:when>
141
+ <xsl:when test="state='R'">
142
+ <td class="runnable">Runnable</td>
143
+ </xsl:when>
144
+ <xsl:when test="state='P'">
145
+ <td class="parked">
146
+ <xsl:choose>
147
+ <xsl:when test="blocked_by=''">
148
+ Parked
149
+ </xsl:when>
150
+ <xsl:otherwise>
151
+ <a target="_blank">
152
+ <xsl:attribute name="href">
153
+ <xsl:value-of select="concat('thread_', blocked_by/@thread_hash, '.html')"/>
154
+ </xsl:attribute>
155
+ <xsl:attribute name="title">
156
+ <xsl:value-of select="blocked_by/@name" />
157
+ </xsl:attribute>
158
+ Parked on <xsl:value-of select="blocked_by/@thread_id"/>
159
+ </a>
160
+ </xsl:otherwise>
161
+ </xsl:choose>
162
+ </td>
163
+ </xsl:when>
164
+ <xsl:when test="state='B'">
165
+ <td class="blocked">
166
+ <a target="_blank">
167
+ <xsl:attribute name="href">
168
+ <xsl:value-of select="concat('thread_', blocked_by/@thread_hash, '.html')"/>
169
+ </xsl:attribute>
170
+ <xsl:attribute name="title">
171
+ <xsl:value-of select="blocked_by/@name" />
172
+ </xsl:attribute>
173
+ Blocked by <xsl:value-of select="blocked_by/@thread_id"/>
174
+ </a>
175
+ </td>
176
+ </xsl:when>
177
+ <xsl:otherwise>
178
+ <td><xsl:value-of select="state"/></td>
179
+ </xsl:otherwise>
180
+ </xsl:choose>
181
+ <td>
182
+ <xsl:choose>
183
+ <xsl:when test="blocking/thread">
184
+ blocking:
185
+ <xsl:for-each select="blocking/thread">
186
+ <a target="_blank">
187
+ <xsl:attribute name="href">
188
+ <xsl:value-of select="concat('thread_', @thread_hash, '.html')"/>
189
+ </xsl:attribute>
190
+ <xsl:attribute name="title">
191
+ <xsl:value-of select="@name" />
192
+ </xsl:attribute>
193
+ <xsl:value-of select="@thread_id" />
194
+ </a>;
195
+ </xsl:for-each>
196
+ </xsl:when>
197
+ </xsl:choose>
198
+ </td>
199
+ </tr>
200
+ </xsl:for-each>
201
+ </table>
202
+ </div>
194
203
  </div>
195
204
  </body>
196
205
  <script>loadChart();</script>
@@ -127,7 +127,8 @@ class Javacore:
127
127
  def encode(self, string):
128
128
  bts = str.encode(string, self.get_encoding(), 'ignore')
129
129
  for i in range(0, len(bts)):
130
- if bts[i] < 32 and bts[i] != 9 and bts[i] != 10 and bts[i] != 13 and bts[i] != 1: # fix for 'XML Syntax error PCDATA invalid char#405'
130
+ # fix for 'XML Syntax error PCDATA invalid char#405'
131
+ if bts[i] < 32 and bts[i] != 9 and bts[i] != 10 and bts[i] != 13 and bts[i] != 1:
131
132
  raise CorruptedJavacoreException("Javacore " + self.filename + " is corrupted in line " + string)
132
133
  string = bts.decode('utf-8', 'ignore')
133
134
  return string
@@ -145,7 +146,7 @@ class Javacore:
145
146
  break
146
147
  line = self.encode(line)
147
148
  if line.startswith(THREAD_INFO):
148
- line = self.processThreadName(line, file)
149
+ line = Javacore.process_thread_name(line, file)
149
150
  snapshot = ThreadSnapshot.create(line, file, self)
150
151
  self.snapshots.append(snapshot)
151
152
  except Exception as e:
@@ -158,7 +159,8 @@ class Javacore:
158
159
  finally:
159
160
  file.close()
160
161
 
161
- def processThreadName(self, line, file):
162
+ @staticmethod
163
+ def process_thread_name(line, file):
162
164
  count = line.count('"')
163
165
  if count == 0: return line # anonymous native threads
164
166
  while True:
@@ -12,10 +12,11 @@ import shutil
12
12
  import sys
13
13
  import tarfile
14
14
  import tempfile
15
- import traceback
16
15
  import zipfile
17
16
 
17
+ import importlib_resources
18
18
  import py7zr
19
+ from importlib_resources.abc import Traversable
19
20
 
20
21
  from javacore_analyser import logging_utils
21
22
  from javacore_analyser.constants import DEFAULT_FILE_DELIMITER
@@ -69,15 +70,20 @@ def main():
69
70
  logging.info("Preferred encoding: " + locale.getpreferredencoding())
70
71
 
71
72
  parser = argparse.ArgumentParser()
72
- parser.add_argument("input_param", help="Input file(s) or directory")
73
- parser.add_argument("output_param", help="Report output directory")
73
+ parser.add_argument("input", help="Input javacore file(s) or directory with javacores. "
74
+ "The javacores can be packed "
75
+ "into one of the supported archive formats: zip, gz, bz2, lzma, 7z. "
76
+ "Additional the verbose GC logs from the time "
77
+ "when the javacores were collected can be added. "
78
+ "See doc: https://github.com/IBM/javacore-analyser/wiki")
79
+ parser.add_argument("output", help="Name of directory where report will be generated")
74
80
  parser.add_argument("--separator",
75
81
  help='Input files separator (default "' + DEFAULT_FILE_DELIMITER + '")',
76
82
  default=DEFAULT_FILE_DELIMITER)
77
83
  args = parser.parse_args()
78
84
 
79
- input_param = args.input_param
80
- output_param = args.output_param
85
+ input_param = args.input
86
+ output_param = args.output
81
87
  files_separator = args.separator
82
88
 
83
89
  logging.info("Input parameter: " + input_param)
@@ -89,17 +95,15 @@ def main():
89
95
  # Check whether as input we got list of files or single file
90
96
  # Semicolon is separation mark for list of input files
91
97
  if files_separator in input_param or fnmatch.fnmatch(input_param, '*javacore*.txt'):
92
- # Process list of the files (copy all or them to output dir
98
+ # Process list of the files (copy all or them to output dir)
93
99
  files = input_param.split(files_separator)
94
100
  else:
95
101
  files = [input_param]
96
-
97
102
  try:
98
103
  process_javacores_and_generate_report_data(files, output_param)
99
104
  except Exception as ex:
100
- traceback.print_exc(file=sys.stdout)
101
- logging.error("Processing was not successful. Correct the problem and try again. Exiting with error 13",
102
- exc_info=True)
105
+ logging.exception(ex)
106
+ logging.error("Processing was not successful. Correct the problem and try again. Exiting with error 13")
103
107
  exit(13)
104
108
 
105
109
 
@@ -115,12 +119,9 @@ def generate_javecore_set_data(files):
115
119
  Returns:
116
120
  - JavacoreSet: Generated JavacoreSet object containing the processed data.
117
121
  """
118
-
119
-
122
+ javacores_temp_dir = tempfile.TemporaryDirectory()
120
123
  try:
121
124
  # Location when we store extracted archive or copied javacores files
122
- javacores_temp_dir = tempfile.TemporaryDirectory()
123
-
124
125
  javacores_temp_dir_name = javacores_temp_dir.name
125
126
  for file in files:
126
127
  if os.path.isdir(file):
@@ -137,6 +138,24 @@ def generate_javecore_set_data(files):
137
138
  javacores_temp_dir.cleanup()
138
139
 
139
140
 
141
+ def create_output_files_structure(output_dir):
142
+ if not os.path.isdir(output_dir):
143
+ os.mkdir(output_dir)
144
+ data_output_dir = os.path.normpath(os.path.join(output_dir, 'data'))
145
+ if not data_output_dir.startswith(output_dir):
146
+ raise Exception("Security exception: Uncontrolled data used in path expression")
147
+ if os.path.isdir(data_output_dir):
148
+ shutil.rmtree(data_output_dir, ignore_errors=True)
149
+ logging.info("Data dir: " + data_output_dir)
150
+
151
+ style_css_resource: Traversable = importlib_resources.files("javacore_analyser") / "data" / "style.css"
152
+ data_dir = os.path.dirname(str(style_css_resource))
153
+ os.mkdir(data_output_dir)
154
+ shutil.copytree(data_dir, data_output_dir, dirs_exist_ok=True)
155
+ shutil.copy2(os.path.join(data_output_dir, "html", "processing_data.html"),
156
+ os.path.join(output_dir, "index.html"))
157
+
158
+
140
159
  # Assisted by WCA@IBM
141
160
  # Latest GenAI contribution: ibm/granite-8b-code-instruct
142
161
  def process_javacores_and_generate_report_data(input_files, output_dir):
@@ -150,6 +169,7 @@ def process_javacores_and_generate_report_data(input_files, output_dir):
150
169
  Returns:
151
170
  None
152
171
  """
172
+ create_output_files_structure(output_dir)
153
173
  javacore_set = generate_javecore_set_data(input_files)
154
174
  javacore_set.generate_report_files(output_dir)
155
175
 
@@ -2,6 +2,7 @@
2
2
  # Copyright IBM Corp. 2024 - 2024
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
  #
5
+ import argparse
5
6
  import locale
6
7
  import logging
7
8
  import os
@@ -9,6 +10,7 @@ import re
9
10
  import shutil
10
11
  import sys
11
12
  import tempfile
13
+ import threading
12
14
  import time
13
15
  from pathlib import Path
14
16
 
@@ -16,29 +18,30 @@ from flask import Flask, render_template, request, send_from_directory, redirect
16
18
  from waitress import serve
17
19
 
18
20
  import javacore_analyser.javacore_analyser_batch
19
- from javacore_analyser.constants import DEFAULT_REPORTS_DIR, DEFAULT_PORT
21
+ from javacore_analyser.constants import DEFAULT_REPORTS_DIR, DEFAULT_PORT, TEMP_DIR
20
22
  from javacore_analyser.logging_utils import create_console_logging, create_file_logging
21
23
 
22
24
  """
23
25
  To run the application from cmd type:
24
- export REPORTS_DIR=/tmp/reports
26
+
25
27
  flask --app javacore_analyser_web run
26
28
  """
27
29
  app = Flask(__name__)
28
- with app.app_context():
29
- create_console_logging()
30
- logging.info("Javacore analyser")
31
- logging.info("Python version: " + sys.version)
32
- logging.info("Preferred encoding: " + locale.getpreferredencoding())
33
- reports_dir = os.getenv("REPORTS_DIR", DEFAULT_REPORTS_DIR)
34
- logging.info("Reports directory: " + reports_dir)
35
- create_file_logging(reports_dir)
30
+ reports_dir = DEFAULT_REPORTS_DIR
31
+
32
+
33
+ # Assisted by watsonx Code Assistant
34
+ def create_temp_data_in_reports_dir(directory):
35
+ tmp_reports_dir = os.path.join(directory, TEMP_DIR)
36
+ if os.path.isdir(tmp_reports_dir):
37
+ shutil.rmtree(tmp_reports_dir, ignore_errors=True)
38
+ os.mkdir(tmp_reports_dir)
36
39
 
37
40
 
38
41
  @app.route('/')
39
42
  def index():
40
43
  reports = [{"name": Path(f).name, "date": time.ctime(os.path.getctime(f)), "timestamp": os.path.getctime(f)}
41
- for f in os.scandir(reports_dir) if f.is_dir()]
44
+ for f in os.scandir(reports_dir) if f.is_dir() and Path(f).name is not TEMP_DIR]
42
45
  reports.sort(key=lambda item: item["timestamp"], reverse=True)
43
46
  return render_template('index.html', reports=reports)
44
47
 
@@ -50,8 +53,8 @@ def dir_listing(path):
50
53
 
51
54
  @app.route('/zip/<path:path>')
52
55
  def compress(path):
56
+ temp_zip_dir = tempfile.TemporaryDirectory()
53
57
  try:
54
- temp_zip_dir = tempfile.TemporaryDirectory()
55
58
  temp_zip_dir_name = temp_zip_dir.name
56
59
  zip_filename = path + ".zip"
57
60
  report_location = os.path.join(reports_dir, path)
@@ -68,7 +71,7 @@ def compress(path):
68
71
  def delete(path):
69
72
  # Checking if the report exists. This is to prevent attempt to delete any data by deleting any file outside
70
73
  # report dir if you prepare path variable.
71
- reports_list = os.listdir(reports_dir)
74
+ # reports_list = os.listdir(reports_dir)
72
75
  report_location = os.path.normpath(os.path.join(reports_dir, path))
73
76
  if not report_location.startswith(reports_dir):
74
77
  logging.error("Deleted report in report list. Not deleting")
@@ -82,10 +85,19 @@ def delete(path):
82
85
  # Latest GenAI contribution: ibm/granite-20b-code-instruct-v2
83
86
  @app.route('/upload', methods=['POST'])
84
87
  def upload_file():
88
+
89
+ report_name = request.values.get("report_name")
90
+ report_name = re.sub(r'[^a-zA-Z0-9]', '_', report_name)
91
+
92
+ # Create a temporary directory to store uploaded files
93
+ # Note We have to use permanent files and then delete them.
94
+ # tempfile.Temporary_directory function does not work when you want to access files from another threads.
95
+ javacores_temp_dir_name = os.path.normpath(os.path.join(reports_dir, TEMP_DIR, report_name))
96
+ if not javacores_temp_dir_name.startswith(reports_dir):
97
+ raise Exception("Security exception: Uncontrolled data used in path expression")
98
+
85
99
  try:
86
- # Create a temporary directory to store uploaded files
87
- javacores_temp_dir = tempfile.TemporaryDirectory()
88
- javacores_temp_dir_name = javacores_temp_dir.name
100
+ os.mkdir(javacores_temp_dir_name)
89
101
 
90
102
  # Get the list of files from webpage
91
103
  files = request.files.getlist("files")
@@ -97,26 +109,46 @@ def upload_file():
97
109
  file.save(file_name)
98
110
  input_files.append(file_name)
99
111
 
100
- report_name = request.values.get("report_name")
101
- report_name = re.sub(r'[^a-zA-Z0-9]', '_', report_name)
102
-
103
112
  # Process the uploaded file
104
- report_output_dir = reports_dir + '/' + report_name
105
- javacore_analyser.javacore_analyser_batch.process_javacores_and_generate_report_data(input_files,
106
- report_output_dir)
107
-
113
+ report_output_dir = os.path.join(reports_dir, report_name)
114
+ processing_thread = threading.Thread(
115
+ target=javacore_analyser.javacore_analyser_batch.process_javacores_and_generate_report_data,
116
+ name="Processing javacore data", args=(input_files, report_output_dir)
117
+ )
118
+ processing_thread.start()
119
+
120
+ time.sleep(1) # Give 1 second to generate index.html in processing_thread before redirecting
108
121
  return redirect("/reports/" + report_name + "/index.html")
109
122
  finally:
110
- javacores_temp_dir.cleanup()
123
+ shutil.rmtree(javacores_temp_dir_name, ignore_errors=True)
124
+
111
125
 
112
126
  def main():
113
- debug = os.getenv("DEBUG", False)
114
- port = os.getenv("PORT", DEFAULT_PORT)
127
+ parser = argparse.ArgumentParser()
128
+ parser.add_argument("--debug", help="Debug mode. Use only for development", default=False)
129
+ parser.add_argument("--port", help="Port to run application", default=DEFAULT_PORT)
130
+ parser.add_argument("--reports-dir", help="Directory where app reports are stored",
131
+ default=DEFAULT_REPORTS_DIR)
132
+ args = parser.parse_args()
133
+ debug = args.debug
134
+ port = args.port
135
+ global reports_dir
136
+ reports_dir = args.reports_dir
137
+
138
+ create_console_logging()
139
+ logging.info("Javacore analyser")
140
+ logging.info("Python version: " + sys.version)
141
+ logging.info("Preferred encoding: " + locale.getpreferredencoding())
142
+ logging.info("Reports directory: " + reports_dir)
143
+ create_file_logging(reports_dir)
144
+ create_temp_data_in_reports_dir(reports_dir)
145
+
115
146
  if debug:
116
147
  app.run(debug=True, port=port) # Run Flask for development
117
148
  else:
118
149
  serve(app, port=port) # Run Waitress in production
119
150
 
151
+
120
152
  if __name__ == '__main__':
121
153
  """
122
154
  The application passes the following environmental variables: