How to log to Kubernetes Container Log from Python process - python

With Kubernetes Container running a Python script:
import time
while True:
try:
for i in range(10):
if i==0:
raise Exception('Exception occurred!')
except:
pass
time.sleep(1)
I would like to pass the Exception's message 'Exception occurred!' down to the Container so this error message could be seen with:
kubectl describe pod pod_id
Would it be possible?

Anything you print() will be visible in kubectl logs. (You may need to set an environment variable PYTHONUNBUFFERED=1 in your pod spec.)
Your code as you've written it will never print anything. The construct
try:
...
except:
pass
silently ignores any and all exceptions out of the try block. The bare except: even captures some system-level exceptions like SystemExit or KeyboardInterrupt; this is almost always wrong. Often you want your except blocks to be as tightly scoped as you can, and the Python tutorial on user-defined exceptions is a helpful pattern.
(The exception to this, particularly in a Kubernetes context, is that you will often want a very broad exception handler to do something like return an HTTP 500 error to a network request, rather than crashing the application.)
A better example might look like:
import time
class OneException(Exception):
pass
def iteration():
for i in range(10):
try:
if i == 1:
raise OneException("it is one")
print(i, math.sqrt(i), math.sqrt(-i))
# will work when i==0 but fail when i==2
except OneException as e:
print(i, repr(e))
# and proceed to the next iteration
if __name__ == '__main__':
while True:
# The top-level loop. We want a very broad catch here.
try:
iteration()
except Exception as e:
print('iteration failed', repr(e))
time.sleep(1)

Related

Circuit Python MQTT Exception Block

I'm using the Adafruit Circuit Python MQTT library and am trying to catch the errors being generated.
while True:
try:
# Poll the message queue
mqtt_client.loop()
except (ValueError, RuntimeError, MMQTTException) as e:
print("Failed to get data, retrying\n", e)
mqtt_client.reconnect()
# continue
time.sleep(1)
But this generates the following error:
NameError: name 'MMQTTException' is not defined
Any ideas how I should properly catch this error?
The library has the following error class. I'm guessing it needs to be exposed somehow?
class MMQTTException(Exception):
"""MiniMQTT Exception class."""
# pylint: disable=unnecessary-pass
# pass
If you did something like
import adafruit_minimqtt.adafruit_minimqtt as MQTT
in order to be able to use mqtt_client = MQTT.MQTT(...), then you need to refer to this other class similarly, as MQTT.MMQTTException.

can i raise exception from inside a function in the 'try:' block when client disconnects from the server?

im trying to build a simple server-client chatroom with python socket.
i have the following code:
def handle_connection(client):
while(1):
try:
message = receive_message()
broadcast(message["data"])
except: # for now i don't mind which exception
print("client disconnected")
def receive_message(client_socket):
try:
message_header = client_socket.recv(HEADER)
if len(message_header) == 0:
return False
message_length = int(message_header.decode("utf-8"))
message = client_socket.recv(message_length).decode("utf-8")
return {"header": message_header, "data": message}
except: # most likely will trigger when a client disconnects
return False
where receive_message() calls inside of it to client.recv(HEADER) and returns either False when there is no message, or {"header": msg_header, "data": msg} when everything is ok.
my question is: if client.recv() fails inside of receive_message() due to the client CLI closing, will it raise the exception and print "client disconnected", or not?
i did come up with the following solution i think works:
i defined a function called handle_disconnection() that handles all the content inside of the except in the code above.
def handle_connection(client_socket):
while 1:
try:
message = receive_message()
if not message:
handle_disconnection(client_socket)
break
broadcast(message["data"])
except: # client disconnected
handle_disconnection(client_socket)
break
is this a valid and/or right programming approach to the problem?
if this approach is wrong, how can i handle it correctly?
If client.recv() will raise an exception you will handle it inside of receive_message() and handle_connection() will not receive the exception.
I suggest you to identify situations when you want to control the flow with exceptions or with if-else. I think receive_message() should return a value of message or throw ConnectionError when there are connection issues. In case when there are no messages from the socket you can return None or raise NoMessagesAvailableError.
There is also a rule that tells you should catch specified exceptions, not all of them. Your code will print client disconnected when you are out of memory.

What is the proper way to try / except a timeout in Python

After a server upgrade, I'm having an issue with a python script eating up all the server connections because it appears that after a timeout it doesn't actually end the loop. The code looks like:
if os.name == 'posix':
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(__TIMEOUT__)
try:
self.inputline = self.rfile.readline()
except IOError:
continue
if os.name == 'posix':
signal.alarm(0)
The signal occurs and all that does is set a terminated variable to 1 and print a log about the time out. The while looks like while not self.terminated:. My guess is that because it has except IOError: the except doesn't occur and it's still sitting on the readline(). So the question is, what is the proper way to ensure the SIGALRM will cause the continue which will end the loop and exit the script?
TIA!!
In handle_timeout() you can raise an exception to get your try to wake up. Then catch that exception in your try/except:
def handle_timeout(signum, frame):
raise KeyboardInterrupt('received signal to exit')
while not terminated:
try:
self.inputline = self.rfile.readline()
except IOError, KeyboardInterrupt:
terminated = True
continue

Adding timeout in subprocess.check_output

I am developing a small tool in Python 2.7 and using subprocess module. I am using this module to run commands on remote devices using its check_output function. There might be a situation in which the remote device is not functioning and therefore I am getting the following response:
Timeout: No Response from 10.xxx.xxx.xxx
Following is my code:
try:
x=subprocess.check_output(command, shell=True)
except Exception:
print ("Some issues in fetching details")
exit()
else:
print (x)
I want to put timeout into this function so that if after a certain amount of time, no response is recieved, my code goes in the Exception part and prints the given message. I tried using timeout argument in the check_output command but after running my script with timeout argument, it is immediately printing the message given in the Exception part.
What I tried:
try:
x=subprocess.check_output(command, shell=True, timeout=5)
except Exception:
print ("Some issues in fetching details")
exit()
else:
print (x)
My guess is that you are running your code in Python 2.
If that is the case, subprocess.check_output() does not accept a timeout parameter, and the function will fail immediately with:
TypeError: __init__() got an unexpected keyword argument 'timeout'
But, because you are catching all exceptions and printing a generic message, you don't see the actual exception, and you assume that the command is timing out immediately.
One way to fix this problem is to run your code in Python 3.
Whether you are running Python 2 or 3, I recommend that you do not catch all exceptions, or that you at least print the value of the exception so that you can see the actual cause, e.g.
try:
x=subprocess.check_output(command, shell=True, timeout=5)
except subprocess.TimeoutExpired as exc:
print("Command timed out: {}".format(exc))
exit()
else:
print (x)
which explicitly checks for a timeout exception. All other exceptions are propagated as usual and so are not masked by your "catch all" code. Or,
try:
x=subprocess.check_output(command, shell=True, timeout=5)
except Exception as exc:
print("Command failed: {}".format(exc))
exit()
else:
print (x)
but the former is preferred.
Edit
OP can't use Python 3. If you are using Linux then you could use the timeout command, e.g.
x = subprocess.check_output('timeout 5 {}'.format(command), shell=True)
On timeout this will raise an exception with a particular exit status value of 124:
subprocess.CalledProcessError: Command 'timeout 5 sleep 10' returned non-zero exit status 124
BTW you shouldn't use the shell=True option as there are security implications as mentioned in the documentation. Instead you should pass a list of strings to check_output() like this:
from shlex import shlex
command = shlex('timeout 5 {}'.format(command))
try:
x = subprocess.check_output(command)
except subprocess.CalledProcessError as exc:
if exc.returncode == 124:
print "Command timed out"
else:
raise
If you are using another OS (or you don't want to use timeout) then you can run your subprocess in a separate thread and have your main thread time it out if required. See this other question, Using module 'subprocess' with timeout, for details about how to do that.
Python 2.7 does not support timeout parameter. You can instead use EasyProcess. This is a layer on top of subprocess module and pretty easy to use.

Python: except EOFError: ... doesn't work

I have a try/except block that sends a message and waits for confirmation from client. If the client terminates, pickle raises an EOFError, but the code below does not catch the error and execute the graceful shut down. It instead prints stack trace. I assume it has to do with the line "except socket.error, EOFError:" - am I using the wrong syntax to handle both socket.error and EOFError there?
try:
msgs = [1]
self.sock.send(pickle.dumps(msgs))
rdy = pickle.loads(self.sock.recv(2097152))
except socket.error, EOFError:
print 'log socketmanager closing'
self.terminate()
break
In Python 2.x, the form except a, b catches an exception of type a and assign it to a variable called b. In your case this would result in EOFError being ignored. Try this instead:
...
except (socket.error, EOFError):
...
Edit: to elaborate, the new syntax in Python 3.0, and available, though not required, in 2.6+, for capturing the value of an exception is except a as b.
break is causing the error, it can only be used inside a for loop or a try/finally block, not try/except, see docs and more.

Categories

Resources