Commits

jordilin committed 4d0a7e5

executor to be triggered only if error, fatal or critical found

  • Participants
  • Parent commits 0728dfe

Comments (0)

Files changed (2)

File log4tailer/notifications.py

 from log4tailer.Timer import Timer
 from smtplib import *
 from log4tailer.TermColorCodes import TermColorCodes
+import subprocess
 
 
 class Print(object):
 class Executor(object):
     """Will execute a program if a certain condition is given"""
     PlaceHolders = '%s'
+    Pullers = ['ERROR', 'FATAL', 'CRITICAL']
 
     def __init__(self, properties):
         executable = properties.getValue('executor')
         if self.PlaceHolders in self.executable:
             self.full_trigger_active = True
 
-    def __build_trigger(self, logtrace, logpath):
-        trigger = ' '.join(self.executable)
+    def _build_trigger(self, logtrace, logpath):
         if self.full_trigger_active:
-            trigger = ' '.join(self.executable) % (logtrace, logpath)
-        return trigger
+            params = [logtrace, logpath]
+            trigger = []
+            for param in self.executable:
+                if param == self.PlaceHolders:
+                    param = params.pop(0) 
+                trigger.append(param)
+            return trigger
+        return self.executable
 
     def notify(self, message, log):
+        msg_level = message.getMessageLevel().upper()
+        if msg_level not in self.Pullers:
+            return
         logtrace, logpath = message.getPlainMessage()
-        trigger = self.__build_trigger(logtrace, logpath)
-        print trigger
-        os.system(trigger)
+        trigger = self._build_trigger(logtrace, logpath)
+        try:
+            subprocess.Popen(trigger)
+        except Exception, err:
+            # log4tailer should continue processing
+            print err
         

File test/test_executor.py

 import unittest
 import sys
 import mocker
+import time
 sys.path.append('..')
 from log4tailer import notifications
 from log4tailer.Properties import Property
 from log4tailer.Log import Log
 
 CONFIG = 'aconfig.txt'
+SYSOUT = sys.stdout
+
+class Writer:
+    def __init__(self):
+        self.captured = []
+    
+    def __len__(self):
+        return len(self.captured)
+
+    def write(self, txt):
+        self.captured.append(txt)
 
 class TestExecutor(unittest.TestCase):
     def setUp(self):
         self.mocker = mocker.Mocker()
+        sys.stdout = Writer()
     
     def testShouldReadExecutorFromConfigFile(self):
         fh = open(CONFIG, 'w')
         fh = open(CONFIG, 'w')
         fh.write('executor = ls -l %s %s\n')
         fh.close()
-        trigger = "ls -l this is a log trace anylog"
-        trace = "this is a log trace"
+        trace = "this is a FATAL log trace"
+        trigger = ['ls', '-l', trace, log.getLogPath() ]
         properties = Property(CONFIG)
         properties.parseProperties()
         executor = notifications.Executor(properties)
-        os_mock = self.mocker.replace('os')
-        os_mock.system(trigger)
+        os_mock = self.mocker.replace('subprocess')
+        os_mock.Popen(trigger)
         self.mocker.result(True)
         self.mocker.replay()
         message.parse(trace, log)
         logcolor = LogColors()
         message = Message(logcolor)
         log = Log('anylog')
+        logpath = log.getLogPath()
         fh = open(CONFIG, 'w')
         fh.write('executor = echo\n')
         fh.close()
-        trace = "this is a log trace"
+        trace = "this is a fatal log trace"
         properties = Property(CONFIG)
         properties.parseProperties()
         executor = notifications.Executor(properties)
         message.parse(trace, log)
+        trigger = executor._build_trigger(trace, logpath)
+        self.assertEqual(['echo'], trigger)
         executor.notify(message, log)
 
     def testShouldNotifyAndContinueIfExecutorFails(self):
         fh = open(CONFIG, 'w')
         fh.write('executor = anycommand\n')
         fh.close()
-        trace = "this is a log trace"
+        trace = "this is a critical log trace"
         properties = Property(CONFIG)
         properties.parseProperties()
         executor = notifications.Executor(properties)
         message.parse(trace, log)
         executor.notify(message, log)
+        self.assertTrue(sys.stdout.captured)
+
+    def testShouldContinueTailingIfExecutableTakesLongTime(self):
+        logcolor = LogColors()
+        message = Message(logcolor)
+        log = Log('anylog')
+        fh = open(CONFIG, 'w')
+        fh.write('executor = python executable.py\n')
+        fh.close()
+        trace = "this is an error log trace"
+        properties = Property(CONFIG)
+        properties.parseProperties()
+        executor = notifications.Executor(properties)
+        message.parse(trace, log)
+        start = time.time()
+        executor.notify(message, log)
+        finished = time.time()
+        ellapsed = start - finished
+        # executable.py sleeps for three seconds
+        self.assertTrue(ellapsed < 2)
+
+    def testShouldNotExecuteIfLevelNotInPullers(self):
+        logcolor = LogColors()
+        message = Message(logcolor)
+        log = Log('anylog')
+        fh = open(CONFIG, 'w')
+        fh.write('executor = anything %s %s\n')
+        fh.close()
+        trace = "this is an info log trace"
+        properties = Property(CONFIG)
+        properties.parseProperties()
+        executor = notifications.Executor(properties)
+        message.parse(trace, log)
+        executor.notify(message, log)
+        self.assertFalse(sys.stdout.captured)
+        trace = "this is an warning log trace"
+        sys.stdout.captured = []
+        message.parse(trace, log)
+        executor.notify(message, log)
+        self.assertFalse(sys.stdout.captured)
+        trace = "this is an fatal log trace"
+        message.parse(trace, log)
+        executor.notify(message, log)
+        self.assertTrue(sys.stdout.captured)
         
     def tearDown(self):
         self.mocker.restore()
         self.mocker.verify()
+        sys.stdout = SYSOUT
 
 if __name__ == '__main__':
     unittest.main()