Sending email from raised exception in Python - python

I would like to send an email from all of my raised exceptions that appear in the console in a Python script. An example of this would be if a json-web service that I am consuming is down and logs an error message to my console; then I would like to send that in addition to any other errors that are logged in the console.
At the lowest level; here is an example of what I would encounter. I would like to email all associated errors with the script if it fails, or returns exit code 1
import json
import jsonpickle
import requests
import time
f2 = open('C:\Users\Administrator\Desktop\DetailView.json', 'r')
data2 = jsonpickle.encode(jsonpickle.decode(f2.read()) )
url2 = "HTTPERROR or ValueError prone URL that raises an exception"
headers2 = {'Content-type': 'text/plain', 'Accept': '/'}
r2 = requests.post(url2, data=data2, headers=headers2)
decoded2 = json.loads(r2.text)
Start = datetime.datetime.now()
ValueError: No JSON object could be decoded

You want to use the SMTP Handler offered in the logging module. You would put a try except block around your concerned code and every time an exception is thrown the logger will send an email.
For example:
try:
{my code}
except Exception as e:
logger.error("My code threw an error", exc_info=True)
{handle exception}
And you would have to add the SMTP handler to your logging config:
[handler_smtpHandler]
class=logging.handlers.SMTPHandler
level=WARN
formatter=simpleFormatter
args=('localhost', 'ALERT#myemail.com', ['recipient#email.com'], "ERROR SUBJECT")

Related

How do I catch errors using Zeep and Python 3.7

I am learning how to use Zeep as my soap client. I am able to connect to a WSDL and view services, however, I am stuck on how to catch all possible exceptions. I am only able to catch KeyError. I want to be able to catch a few more:
Basically something similar to the below http client example:
except (http.client.HTTPException, ValueError, KeyError, AttributeError) as e
I would want to use try.....except
try:
session = Session()
session.auth = HttpNtlmAuth(username, password)
request_data = {
}
client = Client(wsdl, transport=Transport(session=session))
response = client.service.GetPendingBills(**request_data)
billobj = json.loads(response)
print(billobj)
bills = (len(billobj["Bills"]))
except KeyError as e:
bills = 0
Maybe this is too late, but you can import zeep.exceptions and handle all kinds of exceptions that you have that way. You just need to check the exception and catch it as you have demonstrated above.
Solution is shown in this documentation
I decided to import requests and handle the exceptions as indicated below:
except (requests.exceptions.HTTPError, KeyError, TimeoutError) as e
Thanks

Python Error Handling when using requests

I wrote the script below to be able to connect to a remote server and get some data from the XML file. I added some error handling to be able to skip issues with some devices. For some reason whenever the script gets a 401 message back, it breaks the whole loop and I get the message "Could not properly read the csv file". I tried other ways of handling the exception and it would fail at other points. Any info on how to properly deal with this?
#!/usr/bin/python
import sys, re, csv, xmltodict
import requests, logging
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
def version(ip, username, password):
baseUrl = "https://" + ip
session = requests.Session()
session.verify = False
session.timeout = 45
print "Connecting to " + ip
try:
r = session.get(baseUrl + '/getxml?location=/Status', auth=(username, password))
r.raise_for_status()
except Exception as error:
print err
doc = xmltodict.parse(r.text)
version = str(doc['Status']['#version'])
def main():
try:
with open('list.csv', 'r') as file:
reader = csv.DictReader(file)
for row in reader:
version(row['ip'], row['Username'], row['Password'])
except Exception as error:
print ValueError("Could not properly read the csv file \r")
sys.exit(0)
if __name__ == "__main__":
main()
The doc and version variables in def version are outside the try: catch: so when r is None due to exception, the next 2 operations also fail, raising some uncaught exception. Which surfaces in main. Can you try including doc and version within the try: catch: and see if it works.
A related suggestion: catch specific exceptions as this helps know more about why your code crashed. ex. Response.raise_for_status() raises requests.exceptions.HTTPError. Catch that, raise all other exceptions. xml might raise something else, catch that, instead of catching ALL.

Generate http error from python3 requests

I have a simple long poll thing using python3 and the requests package. It currently looks something like:
def longpoll():
session = requests.Session()
while True:
try:
fetched = session.get(MyURL)
input = base64.b64decode(fetched.content)
output = process(data)
session.put(MyURL, data=base64.b64encode(response))
except Exception as e:
print(e)
time.sleep(10)
There is a case where instead of processing the input and puting the result, I'd like to raise an http error. Is there a simple way to do this from the high level Session interface? Or do I have to drill down to use the lower level objects?
Since You have control over the server you may want to reverse the 2nd call
Here is an example using bottle to recive the 2nd poll
def longpoll():
session = requests.Session()
while True: #I'm guessing that the server does not care that we call him a lot of times ...
try:
session.post(MyURL, {"ip_address": my_ip_address}) # request work or I'm alive
#input = base64.b64decode(fetched.content)
#output = process(data)
#session.put(MyURL, data=base64.b64encode(response))
except Exception as e:
print(e)
time.sleep(10)
#bottle.post("/process")
def process_new_work():
data = bottle.request.json()
output = process(data) #if an error is thrown an HTTP error will be returned by the framework
return output
This way the server will get the output or an bad HTTP status

How to POST data from Zenoss to a URL using a python script

With the risk to be a little off-topic I'll give it a try:
I have a small script written in python, which is supposed to POST some data on a specific URL. The problem is:
I am integrating this script in zenoss:
Here is the path from zenoss (GUI)
`Events(http://ip:port/zport/dmd/Events/evconsole)->click on some event class->settings->transform(here I copy-paste my script)`
When the events are triggered, the script is called, but no data it's POSTed to the other IP (a different server) even if the script is running correctly - I don't get any error messages in logs or in the GUI. So, I guess there are some restrictions at the network level and somehow the POSTed data isn't sent by Zenoss.
Could you please guys tell me what should I modify (perhaps a .conf file or hosts file) or what should I do to be able to POST some data on another server ?
The code is here (if relevant):
import urllib2 as urllib
from urllib import urlencode
from os.path import join as joinPath
from traceback import print_tb
from os.path import isfile
from sys import exc_info
gh_url = 'http://ip/txsms.cgi'
APPLICATION_PATH = '/srv/sms_alert/'
ALERT_POINT_PATH = joinPath(APPLICATION_PATH, 'alert_contact')
try:
evt.data = 'Some text'
isInProduction = False
if evt.prodState == 1000:
isInProduction = True
if isInProduction and isfile(ALERT_POINT_PATH):
alertContactContent = None
with open(ALERT_POINT_PATH, 'r') as alertContactFile:
alertContactContent = alertContactFile.read()
alertContactContent = alertContactContent.splitlines()
if alertContactContent:
evt.summary = '#[ SMS ALERT ]# {}'.format(evt.summary)
for alertContactContentLine in alertContactContent:
data = {'phonenr': alertContactContentLine, 'smstxt': evt.summary, 'Submit': 'SendSms'}
urllib.urlencode(data)
req = urllib.Request(gh_url, data)
password_manager = urllib.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, gh_url, 'admin', 'password')
auth_manager = urllib.HTTPBasicAuthHandler(password_manager)
opener = urllib.build_opener(auth_manager)
urllib.install_opener(opener)
handler = urllib.urlopen(req)
else:
evt.summary = '#[ ERROR: SMS ALERT NO CONTACT ]# {}'.format(evt.summary)
except Exception as e:
ex_type, ex, tb = exc_info()
print('\n #[ERROR]# TRANSFORM: exception: {ex}\n'.format(ex=e))
print('\n #[ERROR]# TRANSFORM: exception traceback: {trace}\n'.format(trace=print_tb(tb)))
So to be more specific:
I am trying to authenticate and then POST some data to: http://ip/txsms.cgi. If I am running the script directly from my CentOS machine (and remove the events - as they can be used only inside zenoss) it works and it accomplishes what I want, but when I copy-paste the code in Zenoss, the data isn't POSTed.
Any ideas on this ? (how can I have this done)

How to get response on error in SUDS?

If i have some bad authorization data (for example wrong password) SUDS rises exception (400, u'Bad Request') from which i cant get anything, but in teh log is response, which contains data that password is wrong, but how to get this response? I tried like this:
except Exception as e:
print str(e)
print self._client.last_received()
It prints:
(400, u'Bad Request')
None
But in log there is long xml which contains <SOAP-ENV:Reason><SOAP-ENV:Text xml:lang="en">Sender not authorized</SOAP-ENV:Text></SOAP-ENV:Reason>
I am pulling this out of a comment and into an answer because of the code block.
import suds.client
try:
auth_url = "https://url.to.my.service/authenticator?wsdl"
auth_client = suds.client.Client(auth_url)
cookie = auth_client.service.authenticate(user,password)
except Exception as e:
print str(e)
print auth_client.last_received()
Using this code, I receive the appropriate response from my service if I pass an invalid password:
Server raised fault: 'error.pwd.incorrect'
None
And an appropriate response if I pass an invalid user id:
Server raised fault: 'error.uid.missing'
None
Something you may want to consider doing, is changing your except statement to catch suds.WebFault instead of the generic exception. There may be something else that is occurring and triggering your exception block.
One other thing that may help with your issue, is to pass faults=True in your Client() call.
The Client can be configured to throw web faults as WebFault or to
return a tuple (, )
The code I posted above would look like this:
auth_client = suds.client.Client(auth_url, faults=True)

Categories

Resources