javacore-analyser 2.0rc1__py3-none-any.whl → 2.1.0.dev66__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: