mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-25 00:12:08 +08:00
Merge pull request #2143 from erasche/nicer-emails
Nicer bug report emails
This commit is contained in:
+122
-25
@@ -3,6 +3,7 @@ Functionality for dealing with tool errors.
|
||||
"""
|
||||
import string
|
||||
from galaxy import model, util, web
|
||||
import cgi
|
||||
|
||||
error_report_template = """
|
||||
GALAXY TOOL ERROR REPORT
|
||||
@@ -51,6 +52,91 @@ ${job_traceback}
|
||||
(This is an automated message).
|
||||
"""
|
||||
|
||||
error_report_template_html = """
|
||||
<html><head></head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
tr:nth-child(even) {background-color: #f2f2f2}
|
||||
table{margin: 1em;}
|
||||
.mono{font-family: monospace;}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
background: #eee;
|
||||
border:1px solid black;
|
||||
padding:10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Galaxy Tool Error Report</h1>
|
||||
<span class="sub"><i>from</i> <span class="mono"><a href="${host}">${host}</a></span>
|
||||
|
||||
<h3>Error Localization</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>Dataset</td><td>${dataset_id} (${dataset_id_encoded})</td></tr>
|
||||
<tr><td>History</td><td><a href="${history_view_link}">${history_id} (${history_id_encoded})</a></td></tr>
|
||||
<tr><td>Failed Job</td><td>${hid}: ${history_item_name} (${hda_id_encoded})</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>User Provided Information</h3>
|
||||
|
||||
The user <a href="mailto:${email_str}"><span class="mono">${email_str}</span></a> provided the following information:
|
||||
|
||||
<pre>
|
||||
${message}
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Detailed Job Information</h3>
|
||||
|
||||
Job environment and execution information is available at the job <a href="${hda_show_params_link}">Info Page</a>.
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>Job ID</td><td>${job_id} (${job_id_encoded})</td></tr>
|
||||
<tr><td>Tool ID</td><td>${job_tool_id}</td></tr>
|
||||
<tr><td>Tool Version</td><td>${tool_version}</td></tr>
|
||||
<tr><td>Job PID or DRM id</td><td>${job_runner_external_id}</td></tr>
|
||||
<tr><td>Job Tool Version</td><td>${job_tool_version}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Job Execution and Failure Information</h3>
|
||||
|
||||
<h4>Command Line</h4>
|
||||
<pre>
|
||||
${job_command_line}
|
||||
</pre>
|
||||
|
||||
<h4>stderr</h4>
|
||||
<pre>
|
||||
${job_stderr}
|
||||
</pre>
|
||||
|
||||
<h4>stdout</h4>
|
||||
<pre>
|
||||
${job_stdout}
|
||||
</pre>
|
||||
|
||||
<h4>Job Information</h4>
|
||||
<pre>
|
||||
${job_info}
|
||||
</pre>
|
||||
|
||||
<h4>Job Traceback</h4>
|
||||
<pre>
|
||||
${job_traceback}
|
||||
</pre>
|
||||
|
||||
This is an automated message. Do not reply to this address.
|
||||
</body></html>
|
||||
"""
|
||||
|
||||
|
||||
class ErrorReporter( object ):
|
||||
def __init__( self, hda, app ):
|
||||
@@ -91,30 +177,40 @@ class ErrorReporter( object ):
|
||||
email_str = "'%s' (providing preferred contact email '%s')" % (user.email, email)
|
||||
else:
|
||||
email_str = "'%s'" % (email or 'anonymously')
|
||||
self.report = string.Template( error_report_template ) \
|
||||
.safe_substitute( host=host,
|
||||
dataset_id_encoded=self.app.security.encode_id( hda.dataset_id ),
|
||||
dataset_id=hda.dataset_id,
|
||||
history_id_encoded=history_id_encoded,
|
||||
history_id=hda.history_id,
|
||||
hda_id_encoded=hda_id_encoded,
|
||||
hid=hda.hid,
|
||||
history_item_name=hda.get_display_name(),
|
||||
history_view_link=history_view_link,
|
||||
hda_show_params_link=hda_show_params_link,
|
||||
job_id_encoded=self.app.security.encode_id( job.id ),
|
||||
job_id=job.id,
|
||||
tool_version=job.tool_version,
|
||||
job_tool_id=job.tool_id,
|
||||
job_tool_version=hda.tool_version,
|
||||
job_runner_external_id=job.job_runner_external_id,
|
||||
job_command_line=job.command_line,
|
||||
job_stderr=util.unicodify( job.stderr ),
|
||||
job_stdout=util.unicodify( job.stdout ),
|
||||
job_info=util.unicodify( job.info ),
|
||||
job_traceback=util.unicodify( job.traceback ),
|
||||
email_str=email_str,
|
||||
message=util.unicodify( message ) )
|
||||
|
||||
report_variables = dict(
|
||||
host=host,
|
||||
dataset_id_encoded=self.app.security.encode_id( hda.dataset_id ),
|
||||
dataset_id=hda.dataset_id,
|
||||
history_id_encoded=history_id_encoded,
|
||||
history_id=hda.history_id,
|
||||
hda_id_encoded=hda_id_encoded,
|
||||
hid=hda.hid,
|
||||
history_item_name=hda.get_display_name(),
|
||||
history_view_link=history_view_link,
|
||||
hda_show_params_link=hda_show_params_link,
|
||||
job_id_encoded=self.app.security.encode_id( job.id ),
|
||||
job_id=job.id,
|
||||
tool_version=job.tool_version,
|
||||
job_tool_id=job.tool_id,
|
||||
job_tool_version=hda.tool_version,
|
||||
job_runner_external_id=job.job_runner_external_id,
|
||||
job_command_line=job.command_line,
|
||||
job_stderr=util.unicodify( job.stderr ),
|
||||
job_stdout=util.unicodify( job.stdout ),
|
||||
job_info=util.unicodify( job.info ),
|
||||
job_traceback=util.unicodify( job.traceback ),
|
||||
email_str=email_str,
|
||||
message=util.unicodify( message )
|
||||
)
|
||||
|
||||
self.report = string.Template( error_report_template ).safe_substitute( report_variables )
|
||||
|
||||
# Escape all of the content for use in the HTML report
|
||||
for parameter in report_variables.keys():
|
||||
report_variables[parameter] = cgi.escape(report_variables[parameter])
|
||||
|
||||
self.html_report = string.Template( error_report_template_html ).safe_substitute( report_variables )
|
||||
|
||||
def _send_report( self, user, email=None, message=None, **kwd ):
|
||||
return self.report
|
||||
@@ -146,5 +242,6 @@ class EmailErrorReporter( ErrorReporter ):
|
||||
subject = "%s (%s)" % ( subject, self.app.toolbox.get_tool( self.job.tool_id, self.job.tool_version ).old_id )
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Send it
|
||||
return util.send_mail( frm, to, subject, self.report, self.app.config )
|
||||
return util.send_mail( frm, to, subject, self.report, self.app.config, html=self.html_report )
|
||||
|
||||
@@ -28,7 +28,7 @@ from os.path import normpath, relpath
|
||||
from xml.etree import ElementInclude, ElementTree
|
||||
|
||||
from six import binary_type, iteritems, PY3, string_types, text_type
|
||||
from six.moves import email_mime_text, xrange, zip
|
||||
from six.moves import email_mime_text, email_mime_multipart, xrange, zip
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from six.moves.urllib import request as urlrequest
|
||||
|
||||
@@ -1205,19 +1205,51 @@ def size_to_bytes( size ):
|
||||
return int( size )
|
||||
|
||||
|
||||
def send_mail( frm, to, subject, body, config ):
|
||||
def send_mail( frm, to, subject, body, config, html=None ):
|
||||
"""
|
||||
Sends an email.
|
||||
|
||||
:type frm: str
|
||||
:param frm: from address
|
||||
|
||||
:type to: str
|
||||
:param to: to address
|
||||
|
||||
:type subject: str
|
||||
:param subject: Subject line
|
||||
|
||||
:type body: str
|
||||
:param body: Body text (should be plain text)
|
||||
|
||||
:type config: object
|
||||
:param config: Galaxy configuration object
|
||||
|
||||
:type html: str
|
||||
:param html: Alternative HTML representation of the body content. If
|
||||
provided will convert the message to a MIMEMultipart. (Default 'None')
|
||||
"""
|
||||
|
||||
to = listify( to )
|
||||
msg = email_mime_text.MIMEText( body.encode( 'ascii', 'replace' ) )
|
||||
if html:
|
||||
msg = email_mime_multipart.MIMEMultipart('alternative')
|
||||
else:
|
||||
msg = email_mime_text.MIMEText( body.encode( 'ascii', 'replace' ) )
|
||||
|
||||
msg[ 'To' ] = ', '.join( to )
|
||||
msg[ 'From' ] = frm
|
||||
msg[ 'Subject' ] = subject
|
||||
|
||||
if config.smtp_server is None:
|
||||
log.error( "Mail is not configured for this Galaxy instance." )
|
||||
log.info( msg )
|
||||
return
|
||||
|
||||
if html:
|
||||
mp_text = email_mime_text.MIMEText( body.encode( 'ascii', 'replace' ), 'plain' )
|
||||
mp_html = email_mime_text.MIMEText( html.encode( 'ascii', 'replace' ), 'html' )
|
||||
msg.attach(mp_text)
|
||||
msg.attach(mp_html)
|
||||
|
||||
smtp_ssl = asbool( getattr(config, 'smtp_ssl', False ) )
|
||||
if smtp_ssl:
|
||||
s = smtplib.SMTP_SSL()
|
||||
|
||||
Reference in New Issue
Block a user