def handleDeferreds(labels): """Remember last yield is the return value, don't use return""" results = {} descriptions = [] ret = {} code = 0 for l in labels: try: d = defer.maybeDeferred(func, l, *args[1:], **kwargs) wfd = defer.waitForDeferred(d) yield wfd ret = wfd.getResult() except: failure = Failure() des = "%s: %s" % \ (getException(failure),failure.getErrorMessage()) if failure.check(DroneCommandFailed): result[l] = failure.value.resultContext if 'description' not in result[l]: result[l]['description'] = des result[l]['stacktrace'] = failure.getTraceback() result[l]['error'] = True if 'code' not in result[l]: result[l]['code'] = 1 else: ret = { 'description': des, 'code': 1, 'error': True, 'stacktrace': failure.getTraceback() } if not ret: #NoneType detection ret = {'description': str(ret), 'code': 0} if 'code' in ret: code += abs(ret['code']) results[l] = ret try: descriptions.append(results[l]['description']) except: self.debugReport() results['code'] = code try: results['description'] = '\n'.join(descriptions) except: results['description'] = None if len(labels) == 0: Label = labels[0] else: Label = None ret = self.resultContext('%(description)s', label=Label, **results) yield ret
def handleDeferreds(labels): """Remember last yield is the return value, don't use return""" results = {} descriptions = [] ret = {} code = 0 for l in labels: try: d = defer.maybeDeferred(func, l, *args[1:], **kwargs) wfd = defer.waitForDeferred(d) yield wfd ret = wfd.getResult() except: failure = Failure() des = "%s: %s" % \ (getException(failure),failure.getErrorMessage()) if failure.check(DroneCommandFailed): result[l] = failure.value.resultContext if 'description' not in result[l]: result[l]['description'] = des result[l]['stacktrace'] = failure.getTraceback() result[l]['error'] = True if 'code' not in result[l]: result[l]['code'] = 1 else: ret = { 'description': des, 'code': 1, 'error': True, 'stacktrace': failure.getTraceback() } if not ret: #NoneType detection ret = {'description' : str(ret), 'code' : 0} if 'code' in ret: code += abs(ret['code']) results[l] = ret try: descriptions.append(results[l]['description']) except: self.debugReport() results['code'] = code try: results['description'] = '\n'.join(descriptions) except: results['description'] = None if len(labels) == 0: Label = labels[0] else: Label = None ret = self.resultContext('%(description)s',label=Label,**results) yield ret
def msgBufResponse(self, result): """Format results, encode, and respond""" response, contentType = result try: return { 'response': urllib.quote(blaster.Serialize().execute( contentType, drone.formatResults(response))), 'type': contentType, 'code': 200 } except: failure = Failure() Msg = { 'code': 1, 'description': failure.getErrorMessage(), 'stacktrace': failure.getTraceback(), 'error': True } return { 'response': urllib.quote(blaster.Serialize().execute(contentType, Msg)), 'type': 'text/plain', 'code': 500 }
def __call__(self, argstr): args = argstr.split() resultContext = None if not args: #return command usage methods = {} for name, args, doc in self.exposedMethodInfo: methods[name] = {'args': args, 'doc': doc} resultContext = dict(description=self.__doc__, methods=methods) yield resultContext else: method = args.pop(0) try: wfd = defer.waitForDeferred(self.invoke(method, args)) yield wfd resultContext = wfd.getResult() except: failure = Failure() if failure.check(DroneCommandFailed): resultContext = failure.value.resultContext else: #be nice and return something to the end user template = "[%(application)s] " template += "%s: %s" % (getException(failure), failure.getErrorMessage()) context = { 'error': True, 'code': -2, 'stacktrace': failure.getTraceback() } resultContext = self.resultContext(template, None, **context) yield resultContext
def err(message="", **context): failure = Failure() if message: message += '\n' message += failure.getTraceback() log(message, **context) return failure
def __call__(self, argstr): args = argstr.split() resultContext = None if not args: #return command usage methods = {} for name,args,doc in self.exposedMethodInfo: methods[name] = {'args' : args, 'doc' : doc} resultContext = dict(description=self.__doc__, methods=methods) yield resultContext else: method = args.pop(0) try: wfd = defer.waitForDeferred( self.invoke(method,args) ) yield wfd resultContext = wfd.getResult() except: failure = Failure() if failure.check(DroneCommandFailed): resultContext = failure.value.resultContext else: #be nice and return something to the end user template = "[%(application)s] " template += "%s: %s" % (getException(failure), failure.getErrorMessage()) context = {'error': True, 'code': -2, 'stacktrace': failure.getTraceback()} resultContext = self.resultContext(template, None, **context ) yield resultContext
def spider_error(failure: Failure, response: Response, spider: Spider): spider.logger.error("##### HANDLE ERROR #####") spider.logger.error(f'in {spider}') spider.logger.error(failure.type) spider.logger.error(failure.getErrorMessage()) spider.logger.error("###### TRACE BACK ######") spider.logger.error(failure.getTraceback()) spider.logger.error('########################')
def invoke(self, name, args): """Invoke Exposed Methods @param name (str) - name of method to invoke @param args (tuple) - arguments to pass to invoked method @return (defer.Deferred) """ if name not in self.exposedMethods: return defer.fail( DroneCommandFailed( self.resultContext( "[%(application)s] Unknown method '%(method)s'", method=name, error='unknown method'))) try: #our own form of maybeDeferred d = self.exposedMethods[name](*args) if isinstance(d, defer.Deferred): action = Action(' '.join([str(i) for i in \ (self.action, name) + tuple(args)]), d) return action.deferred elif isinstance(d, DroneCommandFailed): return defer.fail(d) elif isinstance(d, dict): return defer.succeed(d) elif isinstance(d, type(None)): #this just feels dirty return defer.succeed(d) elif isinstance(d, Failure): d.raiseException() #sigh #probably from a triggerred Event callback elif type(d) == types.InstanceType: return defer.succeed(None) return defer.fail(FormatError("Result is not formatted correctly you " + \ "must return self.resultContext or DroneCommandFailed." + \ "\nResult: <%s>" % (str(d),))) except: failure = Failure() if failure.check(DroneCommandFailed): template = "[%(application)s] %(description)s" context = failure.value.resultContext if not 'description' in context: context['description'] = failure.getErrorMessage() else: template = "[%(application)s] " + "%s: %s" % ( getException(failure), failure.getErrorMessage()) context = { 'error': True, 'code': -2, 'stacktrace': failure.getTraceback() } return defer.fail( DroneCommandFailed( self.resultContext(template, None, **context)))
def oops(self, *arg): """ Returns a C{False} status code for a remote call along with a string traceback of the exception raised. You can supply your own exception or L{Failure} instance. If you don't, the current exception will be used. """ if arg and isinstance(arg[0], Failure): failureObject = arg[0] else: failureObject = Failure(*arg) return False, failureObject.getTraceback()
def test_message_why_iserror(self): """ When message, why and isError is given, then message takes precedence and why and isError is ignored to construct message """ failure = Failure(ValueError()) self.wrapper({'message': ('mine', 'yours'), 'isError': True, 'why': 'reason', 'failure': failure}) self.assertEqual( self._formatted_event(), {'message': ('mineyours',), 'level': LogLevel.ERROR, 'traceback': failure.getTraceback(), 'exception_type': 'ValueError'})
def __init__(self, *args, **kwargs): self.data = kwargs.pop('data', None) self.cause = kwargs.pop('cause', None) default_code = self.default_error_code default_name = self.default_error_name or self.__class__.__name__ self.error_code = kwargs.pop('code', default_code) self.error_name = kwargs.pop('name', default_name) if args and isinstance(args[0], unicode): # Exception don't like passing them unicode strings # as a message. Here we do our best to encode it try: encoded = args[0].encode('utf8') except: encoded = args[0].encode('ascii', 'replace') args = (encoded, ) + args[1:] Exception.__init__(self, *args, **kwargs) self.cause_details = None self.cause_traceback = None try: from twisted.python.failure import Failure except ImportError: Failure = None if self.cause: if isinstance(self.cause, Exception): self.cause_details = get_exception_message(self.cause) elif Failure and isinstance(self.cause, Failure): self.cause_details = get_failure_message(self.cause) else: self.cause_details = "Unknown" if Failure and isinstance(self.cause, Failure): f = self.cause self.cause = f.value try: self.cause_traceback = f.getTraceback() except: # Ignore failure.NoCurrentExceptionError pass elif Failure: try: f = Failure() if f.value == self.cause: self.cause_traceback = f.getTraceback() except: # Ignore failure.NoCurrentExceptionError pass
def test_formatEmptyEventWithTraceback(self) -> None: """ An event with an empty C{log_format} key appends a traceback from the accompanying failure. """ try: raise CapturedError("This is a fake error") except CapturedError: f = Failure() event: LogEvent = {"log_format": ""} event["log_failure"] = f eventText = eventAsText(event, includeTimestamp=True, includeSystem=False) self.assertIn(str(f.getTraceback()), eventText) self.assertIn("This is a fake error", eventText)
def test_eventWithTraceback(self) -> None: """ An event with a C{log_failure} key will have a traceback appended. """ try: raise CapturedError("This is a fake error") except CapturedError: f = Failure() event: LogEvent = {"log_format": "This is a test log message"} event["log_failure"] = f eventText = eventAsText(event, includeTimestamp=True, includeSystem=False) self.assertIn(str(f.getTraceback()), eventText) self.assertIn("This is a test log message", eventText)
def move_to_failed_queue(self, job, *exc_info, **kwargs): """Default exception handler: move the job to the failed queue.""" failure = kwargs.get('failure') if failure is None: failure = Failure(exc_info[0], exc_info[1], exc_info[2]) exc_string = ''.join(traceback.format_exception(*exc_info)) else: exc_string = failure.getTraceback() meta = ','.join([item for item in job.meta.values()]) job.meta['failure'] = failure job.timeout = self.default_result_ttl self.log.msg('[%s] JOB_FAILED %s: %s' % (meta, job, exc_string)) yield self.failed_queue.quarantine(job, exc_info=exc_string)
def resultContext(self, template, instance=None, **context): """Creates a dict containg relevant contextual information about a result. You can override this method and tailor it to your liking. We typically use this to pass verbose structured data to a master DroneD controller (not provided with DroneD core) so that it may quickly make decisions based on the result of it's previous command and control activities. IF you set 'error' in the **context this will raise a server error at the remote end. This can be good or bad depending on your outlook on exceptions. Consider this your only warning. return dict """ if 'application' not in context: context['application'] = self.action failure = context.pop('error', False) if isinstance(failure, Failure): if 'description' not in context: context['description'] = '[%s] %s: %s' % \ (self.action, getException(failure), failure.getErrorMessage()) if 'code' not in context: context['code'] = -2 context['error'] = True context['stacktrace'] = failure.getTraceback() self.log('Result context during exception\n%(stacktrace)s' % context) return context #failed so bad we need to shortcut out else: context['error'] = bool(failure) if instance: #this was made for AppManager's if hasattr(instance, 'version'): context['version'] = instance.version if hasattr(instance, 'label'): context['label'] = instance.label if hasattr(instance, 'running'): context['running'] = instance.running try: #fail-safe in case someone is a bonehead context['description'] = template % context except: failure = Failure() context['description'] = '[%s] %s: %s' % \ (self.action, getException(failure), failure.getErrorMessage()) context['stacktrace'] = failure.getTraceback() if 'code' not in context: context['code'] = -2 #be nice to blaster api and the remote client context.update({'code': context.get('code', 0)}) return context
def invoke(self, name, args): """Invoke Exposed Methods @param name (str) - name of method to invoke @param args (tuple) - arguments to pass to invoked method @return (defer.Deferred) """ if name not in self.exposedMethods: return defer.fail(DroneCommandFailed(self.resultContext( "[%(application)s] Unknown method '%(method)s'", method=name, error='unknown method')) ) try: #our own form of maybeDeferred d = self.exposedMethods[name](*args) if isinstance(d, defer.Deferred): action = Action(' '.join([str(i) for i in \ (self.action, name) + tuple(args)]), d) return action.deferred elif isinstance(d, DroneCommandFailed): return defer.fail(d) elif isinstance(d, dict): return defer.succeed(d) elif isinstance(d, type(None)): #this just feels dirty return defer.succeed(d) elif isinstance(d, Failure): d.raiseException() #sigh #probably from a triggerred Event callback elif type(d) == types.InstanceType: return defer.succeed(None) return defer.fail(FormatError("Result is not formatted correctly you " + \ "must return self.resultContext or DroneCommandFailed." + \ "\nResult: <%s>" % (str(d),))) except: failure = Failure() if failure.check(DroneCommandFailed): template = "[%(application)s] %(description)s" context = failure.value.resultContext if not 'description' in context: context['description'] = failure.getErrorMessage() else: template = "[%(application)s] " + "%s: %s" % (getException(failure), failure.getErrorMessage()) context = {'error': True, 'code':-2, 'stacktrace': failure.getTraceback()} return defer.fail(DroneCommandFailed(self.resultContext(template, None, **context)) )
def resultContext(self, template, instance=None, **context): """Creates a dict containg relevant contextual information about a result. You can override this method and tailor it to your liking. We typically use this to pass verbose structured data to a master DroneD controller (not provided with DroneD core) so that it may quickly make decisions based on the result of it's previous command and control activities. IF you set 'error' in the **context this will raise a server error at the remote end. This can be good or bad depending on your outlook on exceptions. Consider this your only warning. return dict """ if 'application' not in context: context['application'] = self.action failure = context.pop('error', False) if isinstance(failure, Failure): if 'description' not in context: context['description'] = '[%s] %s: %s' % \ (self.action, getException(failure), failure.getErrorMessage()) if 'code' not in context: context['code'] = -2 context['error'] = True context['stacktrace'] = failure.getTraceback() self.log('Result context during exception\n%(stacktrace)s' % context) return context #failed so bad we need to shortcut out else: context['error'] = bool(failure) if instance: #this was made for AppManager's if hasattr(instance, 'version'): context['version'] = instance.version if hasattr(instance, 'label'): context['label'] = instance.label if hasattr(instance, 'running'): context['running'] = instance.running try: #fail-safe in case someone is a bonehead context['description'] = template % context except: failure = Failure() context['description'] = '[%s] %s: %s' % \ (self.action, getException(failure), failure.getErrorMessage()) context['stacktrace'] = failure.getTraceback() if 'code' not in context: context['code'] = -2 #be nice to blaster api and the remote client context.update({'code' : context.get('code',0) }) return context
def _formatTraceback(failure: Failure) -> str: """ Format a failure traceback, assuming UTF-8 and using a replacement strategy for errors. Every effort is made to provide a usable traceback, but should not that not be possible, a message and the captured exception are logged. @param failure: The failure to retrieve a traceback from. @return: The formatted traceback. """ try: traceback = failure.getTraceback() except BaseException as e: traceback = "(UNABLE TO OBTAIN TRACEBACK FROM EVENT):" + str(e) return traceback
def restart(self): """convenient restart method for an Application Instance""" result = None try: if self.running: d = self.stop() wfd = defer.waitForDeferred(d) yield wfd wfd.getResult() d = self.start() wfd = defer.waitForDeferred(d) yield wfd result = wfd.getResult() except: result = Failure() log('Unhandled exception\n' + result.getTraceback()) yield result
def test_message_why_iserror(self): """ When message, why and isError is given, then message takes precedence and why and isError is ignored to construct message """ failure = Failure(ValueError()) self.wrapper({ 'message': ('mine', 'yours'), 'isError': True, 'why': 'reason', 'failure': failure }) self.assertEqual( self._formatted_event(), { 'message': ('mineyours', ), 'level': LogLevel.ERROR, 'traceback': failure.getTraceback(), 'exception_type': 'ValueError' })
def err(self, _stuff=None, _why=None, **kwargs): """ This method is API-compatible with L{twisted.python.log.err} and exists for compatibility with that API. @param _stuff: Something that describes a problem. @type _stuff: L{Failure}, L{str}, or L{Exception} @param _why: A string describing what caused the failure. @type _why: L{str} @param kwargs: Additional fields. @type kwargs: L{dict} """ if _stuff is None: _stuff = Failure() elif isinstance(_stuff, Exception): _stuff = Failure(_stuff) if isinstance(_stuff, Failure): if _why: text = safe_str(_why) else: text = "Unhandled Error" text = "{why}\n{traceback}".format( why=text, traceback=_stuff.getTraceback(), ) self.newStyleLogger.emit(LogLevel.critical, text, failure=_stuff, why=_why, isError=1, **kwargs) else: # We got called with an invalid _stuff. self.newStyleLogger.emit(LogLevel.critical, repr(_stuff), why=_why, isError=1, **kwargs)
def test_formatUnformattableWithTraceback(self) -> None: """ An event with an unformattable value in the C{log_format} key still has a traceback appended. """ try: raise CapturedError("This is a fake error") except CapturedError: f = Failure() event = { "log_format": "{evil()}", "evil": lambda: 1 / 0, } event["log_failure"] = f eventText = eventAsText(event, includeTimestamp=True, includeSystem=False) self.assertIsInstance(eventText, str) self.assertIn(str(f.getTraceback()), eventText) self.assertIn("This is a fake error", eventText)
def droneblast(conversation, command): server = conversation.context.get('server') response = None d = None try: if not isinstance(server, Server): conversation.say('On what <b>server</b>?') raise AssertionError('incomplete converation context') options = {} if 'timeout' in conversation.context: options['timeout'] = conversation.context['timeout'] try: conversation.say("Running droned command...") d = server.manager.run(command, **options) deferreds = conversation.context.get('deferreds', []) deferreds.append(d) conversation.context.update({'deferreds': deferreds}) wfd = defer.waitForDeferred(d) yield wfd result = wfd.getResult() except: failure = Failure() if failure.check(DroneCommandFailed): rc = failure.value.resultContext conversation.say(rc.get('description') or str(rc), useHTML=False) else: conversation.say(failure.getTraceback(), useHTML=False) else: if isinstance(result, dict): output = result.values()[0].get('description', str(result)) else: output = str(result) deferreds = conversation.context.get('deferreds', []) try: deferreds.remove(d) except: pass conversation.context.update({'deferreds': deferreds}) conversation.say("Command completed\n%s" % output, useHTML=False) except AssertionError: pass except: result = Failure() yield result
def _finishFinished(self, results): # internal function to indicate that this step is done; this is separated # from finished() so that subclasses can override finished() if self.progress: self.progress.finish() try: hidden = self._maybeEvaluate(self.hideStepIf, results, self) except Exception: why = Failure() self.addHTMLLog("err.html", formatFailure(why)) self.addCompleteLog("err.text", why.getTraceback()) results = EXCEPTION hidden = False self.step_status.stepFinished(results) self.step_status.setHidden(hidden) self.releaseLocks() self.deferred.callback(results)
def test_format_failure(self): try: 1 / 0 except ZeroDivisionError: failure = Failure() log_system = factory.make_name("system") log_time = pick_log_time() self.assertThat( _formatModernEvent({ "log_time": log_time, "log_system": log_system, "log_level": self.log_level, "log_failure": failure, }), Equals( "%s %s: [%s] \n\t%s\n" % (logger.formatTime(log_time, DEFAULT_LOG_FORMAT_DATE), log_system, self.log_level.name, failure.getTraceback().replace("\n", "\n\t")), ), )
def send_outbound(self, phone): queue_key = self.r_key(self.redis_outbound_queue) sent_messages = [] while self.r_server.llen(queue_key): json_data = self.r_server.lpop(queue_key) message = TransportUserMessage.from_json(json_data) log.msg('Sending SMS to %s' % (message['to_addr'],)) # keep track of which Gammu messages were sent out for # what Vumi message gammu_messages = {} try: for gammu_message in self.construct_gammu_messages(message): overrides = { 'Number': message['to_addr'], # Send using the Phone's known SMSC 'SMSC': { 'Location': 1 }, # this will create submit message with request # for delivery report 'Type': 'Status_Report', } gammu_message.update(overrides) # keep the message reference for delivery reports send_sms_response = yield deferToThread(phone.SendSMS, gammu_message) gammu_messages[send_sms_response] = gammu_message # multiparts result in multiple acks yield self.publish_ack( user_message_id=message['message_id'], sent_message_id=send_sms_response) # collect for audit trail sent_messages.append((message, gammu_messages)) except gammu.GSMError, e: failure = Failure(e) self.send_failure(message, failure.value, failure.getTraceback())
def get_exception_traceback(exception=None, cleanup=False): #FIXME: Only work if the exception was raised in the current context f = Failure(exception) if exception and (f.value != exception): return "Not Traceback information available" io = StringIO.StringIO() tb = f.getTraceback() if cleanup: tb = clean_traceback(tb) print >> io, tb if isinstance(f.value, FeatError): if f.value.causeTraceback: print >> io, "\n\nCAUSED BY:\n\n" tb = f.value.causeTraceback if cleanup: tb = clean_traceback(tb) print >> io, tb return io.getvalue()
def test_formatUnformattableErrorWithTraceback(self) -> None: """ An event with an unformattable value in the C{log_format} key, that throws an exception when __repr__ is invoked still has a traceback appended. """ try: raise CapturedError("This is a fake error") except CapturedError: f = Failure() event: LogEvent = { "log_format": "{evil()}", "evil": lambda: 1 / 0, cast(str, Unformattable()): "gurk", } event["log_failure"] = f eventText = eventAsText(event, includeTimestamp=True, includeSystem=False) self.assertIsInstance(eventText, str) self.assertIn("MESSAGE LOST", eventText) self.assertIn(str(f.getTraceback()), eventText) self.assertIn("This is a fake error", eventText)
def __init__(self, *args, **kwargs): self.data = kwargs.pop('data', None) self.cause = kwargs.pop('cause', None) default_code = self.default_error_code default_name = self.default_error_name or self.__class__.__name__ self.error_code = kwargs.pop('code', default_code) self.error_name = kwargs.pop('name', default_name) Exception.__init__(self, *args, **kwargs) self.cause_details = None self.cause_traceback = None if self.cause: if isinstance(self.cause, Exception): self.cause_details = get_exception_message(self.cause) elif isinstance(self.cause, Failure): self.causeDetails = get_failure_message(self.cause) else: self.causeDetails = "Unknown" if isinstance(self.cause, Failure): f = self.cause self.cause = f.value try: self.cause_traceback = f.getTraceback() except: # Ignore failure.NoCurrentExceptionError pass else: try: f = Failure() if f.value == self.cause: self.cause_traceback = f.getTraceback() except: # Ignore failure.NoCurrentExceptionError pass
def msgBufResponse(self, result): """Format results, encode, and respond""" response, contentType = result try: return { 'response' : urllib.quote(blaster.Serialize().execute( contentType, drone.formatResults(response))), 'type' : contentType, 'code' : 200 } except: failure = Failure() Msg = { 'code' : 1, 'description' : failure.getErrorMessage(), 'stacktrace': failure.getTraceback(), 'error' : True } return { 'response' : urllib.quote(blaster.Serialize().execute( contentType, Msg)), 'type' : 'text/plain', 'code' : 500 }
def clean_traceback(failure: Failure) -> str: # FIXME: Amazing. cleaned_traceback = failure.getTraceback().replace('{', '').replace( '}', '') return cleaned_traceback