Handle python eval plugin execptions

Changes:
     - Code to handle various exception
     - Update documentation

Change-Id: Icd1e79ec7d3c9c9b1e1966538ebb1206df69c37c
Signed-off-by: George Keishing <gkeishin@in.ibm.com>
diff --git a/ffdc/docs/plugin.md b/ffdc/docs/plugin.md
index 22756e7..13fc72a 100644
--- a/ffdc/docs/plugin.md
+++ b/ffdc/docs/plugin.md
@@ -42,6 +42,20 @@
 ```
 
 Class function(s): plugins/plugin_class.py
+
+Example:
+```
+class  plugin_class:
+
+    def plugin_print_msg(msg):
+        print(msg)
+```
+
+In YAML plugin, you will need to pass self object as part of the arguments.
+
+Static Class function(s): plugins/plugin_class.py
+
+Example:
 ```
 class  plugin_class:
 
@@ -51,6 +65,8 @@
 ```
 
 This is to avoid passing object self in plugin args YAML when calling the class function(s).
+However python class static method has its own limitation, do not use unless needed.
+
 
 You can add your own plugin modules to extend further.
 
@@ -93,6 +109,23 @@
      - plugin_name:  return_value1,return_value2 = plugin.foo_func.print_vars
 ```
 
+Accessing a class method:
+
+The rule remains same as other functions, however for a class object plugin syntax
+
+```
+        - plugin_name: plugin.<file_name>.<class_object>.<class_method>
+```
+
+Example: (from the class example previously mentioned)
+```
+    - plugin:
+        - plugin_name: plugin.plugin_class.plugin_class.plugin_print_msg
+        - plugin_args:
+            - self
+            - "Hello Plugin call"
+```
+
 ### Plugin execution output for sample
 
 
@@ -128,7 +161,7 @@
         - None
 ```
 
-### Plugin ERROR directive Direcive
+### Plugin ERROR Direcive
 
 Error directive on plugin supported
 - exit_on_error       : If there was an error in a plugin stacked, the subsequent
diff --git a/ffdc/ffdc_collector.py b/ffdc/ffdc_collector.py
index 3f661ef..c91503a 100644
--- a/ffdc/ffdc_collector.py
+++ b/ffdc/ffdc_collector.py
@@ -901,11 +901,16 @@
             self.logger.debug("\tCall func: %s" % eval_string)
             result = eval(eval_string)
             self.logger.info("\treturn: %s" % str(result))
-        except (ValueError, SyntaxError, NameError) as e:
+        except (ValueError,
+                SyntaxError,
+                NameError,
+                AttributeError,
+                TypeError) as e:
             self.logger.error("\tERROR: execute_python_eval: %s" % e)
             # Set the plugin error state.
             plugin_error_dict['exit_on_error'] = True
-            pass
+            self.logger.info("\treturn: PLUGIN_EVAL_ERROR")
+            return 'PLUGIN_EVAL_ERROR'
 
         return result
 
@@ -979,7 +984,8 @@
             if global_plugin_dict:
                 resp = self.execute_python_eval(plugin_func)
                 # Update plugin vars dict if there is any.
-                self.response_args_data(resp)
+                if resp != 'PLUGIN_EVAL_ERROR':
+                    self.response_args_data(resp)
             else:
                 resp = self.execute_python_eval(plugin_func)
         except Exception as e:
@@ -988,6 +994,10 @@
             self.logger.error("\tERROR: execute_plugin_block: %s" % e)
             pass
 
+        # There is a real error executing the plugin function.
+        if resp == 'PLUGIN_EVAL_ERROR':
+            return resp
+
         # Check if plugin_expects_return (int, string, list,dict etc)
         if any('plugin_expects_return' in d for d in plugin_cmd_list):
             idx = self.key_index_list_dict('plugin_expects_return', plugin_cmd_list)