openrvdas.logger.writers.timeout_writer

No module-level documentation available.
  1#!/usr/bin/env python3
  2
  3import threading
  4import time
  5
  6from logger.writers.writer import Writer  # noqa: E402
  7
  8
  9class TimeoutWriter(Writer):
 10    def __init__(self, writer, timeout, message=None, resume_message=None,
 11                 empty_is_okay=False, none_is_okay=False, **kwargs):
 12        """Instantiated with a client Writer instance (such as a
 13        LogfileWriter), an interval, a timeout and optional
 14        message. Expects its write() method to be called at least every
 15        'timeout' seconds. If it isn't, call the client's write method
 16        with 'message' to indicate that it has timed out. Once it receives
 17        a call to its write() method after timing out, call the client's
 18        write method with 'resume_message' to indicate that it is no
 19        longer timed out.
 20        ```
 21        writer         A client writer instance
 22
 23        timeout        Timeout interval in seconds
 24
 25        message        Message to be returned if client reader fails to return
 26                       a record within the timeout interval
 27
 28        resume_message Message to be returned when client returns a record after
 29                       having timed out
 30
 31        empty_is_okay If True, receiving an empty record is sufficient to reset
 32                      the timer.
 33        none_is_okay  If True, receiving a 'None' record is sufficient to reset
 34                        the timer.
 35        ```
 36        Sample config that echos stdin and issues timeouts if no input for 5 secs:
 37        ```
 38          readers:
 39          - class: TextFileReader
 40          transforms:
 41          - class: TimestampTransform
 42          writers:
 43          - class: TextFileWriter
 44          - class: TimeoutWriter
 45            kwargs:
 46              writer:
 47                class: TextFileWriter
 48              timeout: 5
 49              message: No message received for 5 seconds
 50              resume_message: Okay, got another message
 51        ```
 52        """
 53        # Initialize type checking
 54        super().__init__(**kwargs)  # processes 'quiet' and type hints
 55
 56        self.writer = writer
 57        self.timeout = timeout
 58        self.message = message or ('Timeout: no %s record received in %d seconds'
 59                                   % (writer, timeout))
 60        self.resume_message = resume_message or ('Timeout: %s record received'
 61                                                 % writer)
 62        self.empty_is_okay = empty_is_okay
 63        self.none_is_okay = none_is_okay
 64
 65        # When we got our last record (or were instantiated)
 66        self.last_record = time.time()
 67
 68        # Keep track of whether we're currently timed out or not
 69        self.timed_out = False
 70
 71        # Protect self.last_record and self.timed_out
 72        self.timeout_lock = threading.Lock()
 73
 74        # To let us cleanly exit _timeout_thread
 75        self.quit_signaled = False
 76
 77        # Start the timeout loop in a separate thread
 78        self.timeout_thread = threading.Thread(target=self._timeout_thread,
 79                                               name='timeout_thread', daemon=True)
 80        self.timeout_thread.start()
 81
 82    ############################
 83    def __del__(self):
 84        self.quit()
 85
 86    ############################
 87    def _timeout_thread(self):
 88        """Call client write() if we have/haven't had our own write() called
 89        within the alloted time.
 90        """
 91        while not self.quit_signaled:
 92            now = time.time()
 93            with self.timeout_lock:
 94                time_to_sleep = self.timeout - (now - self.last_record)
 95
 96                # If we're overdue for a record...
 97                if time_to_sleep < 0:
 98                    # If we weren't already timed out, we are now. Send message.
 99                    if not self.timed_out:
100                        self.timed_out = True
101                        self.writer.write(self.message)
102
103                    # Check again in timeout seconds
104                    time_to_sleep = self.timeout
105
106            # Whether or not we're timed out, snooze until we expect our
107            # next timeout.
108            time.sleep(time_to_sleep)
109
110    ############################
111    def quit(self):
112        self.quit_signaled = True
113
114    ############################
115    def write(self, record):
116        """Register that we've had a write() call; reset timeout timer."""
117        if record is None and not self.none_is_okay:
118            return
119        if not record and not self.empty_is_okay:
120            return
121
122        # If here, we got a bona fide record. Reset our timer.
123        with self.timeout_lock:
124            if self.timed_out:
125                self.timed_out = False
126                self.writer.write(self.resume_message)
127            self.last_record = time.time()
class TimeoutWriter(logger.writers.writer.Writer):
 10class TimeoutWriter(Writer):
 11    def __init__(self, writer, timeout, message=None, resume_message=None,
 12                 empty_is_okay=False, none_is_okay=False, **kwargs):
 13        """Instantiated with a client Writer instance (such as a
 14        LogfileWriter), an interval, a timeout and optional
 15        message. Expects its write() method to be called at least every
 16        'timeout' seconds. If it isn't, call the client's write method
 17        with 'message' to indicate that it has timed out. Once it receives
 18        a call to its write() method after timing out, call the client's
 19        write method with 'resume_message' to indicate that it is no
 20        longer timed out.
 21        ```
 22        writer         A client writer instance
 23
 24        timeout        Timeout interval in seconds
 25
 26        message        Message to be returned if client reader fails to return
 27                       a record within the timeout interval
 28
 29        resume_message Message to be returned when client returns a record after
 30                       having timed out
 31
 32        empty_is_okay If True, receiving an empty record is sufficient to reset
 33                      the timer.
 34        none_is_okay  If True, receiving a 'None' record is sufficient to reset
 35                        the timer.
 36        ```
 37        Sample config that echos stdin and issues timeouts if no input for 5 secs:
 38        ```
 39          readers:
 40          - class: TextFileReader
 41          transforms:
 42          - class: TimestampTransform
 43          writers:
 44          - class: TextFileWriter
 45          - class: TimeoutWriter
 46            kwargs:
 47              writer:
 48                class: TextFileWriter
 49              timeout: 5
 50              message: No message received for 5 seconds
 51              resume_message: Okay, got another message
 52        ```
 53        """
 54        # Initialize type checking
 55        super().__init__(**kwargs)  # processes 'quiet' and type hints
 56
 57        self.writer = writer
 58        self.timeout = timeout
 59        self.message = message or ('Timeout: no %s record received in %d seconds'
 60                                   % (writer, timeout))
 61        self.resume_message = resume_message or ('Timeout: %s record received'
 62                                                 % writer)
 63        self.empty_is_okay = empty_is_okay
 64        self.none_is_okay = none_is_okay
 65
 66        # When we got our last record (or were instantiated)
 67        self.last_record = time.time()
 68
 69        # Keep track of whether we're currently timed out or not
 70        self.timed_out = False
 71
 72        # Protect self.last_record and self.timed_out
 73        self.timeout_lock = threading.Lock()
 74
 75        # To let us cleanly exit _timeout_thread
 76        self.quit_signaled = False
 77
 78        # Start the timeout loop in a separate thread
 79        self.timeout_thread = threading.Thread(target=self._timeout_thread,
 80                                               name='timeout_thread', daemon=True)
 81        self.timeout_thread.start()
 82
 83    ############################
 84    def __del__(self):
 85        self.quit()
 86
 87    ############################
 88    def _timeout_thread(self):
 89        """Call client write() if we have/haven't had our own write() called
 90        within the alloted time.
 91        """
 92        while not self.quit_signaled:
 93            now = time.time()
 94            with self.timeout_lock:
 95                time_to_sleep = self.timeout - (now - self.last_record)
 96
 97                # If we're overdue for a record...
 98                if time_to_sleep < 0:
 99                    # If we weren't already timed out, we are now. Send message.
100                    if not self.timed_out:
101                        self.timed_out = True
102                        self.writer.write(self.message)
103
104                    # Check again in timeout seconds
105                    time_to_sleep = self.timeout
106
107            # Whether or not we're timed out, snooze until we expect our
108            # next timeout.
109            time.sleep(time_to_sleep)
110
111    ############################
112    def quit(self):
113        self.quit_signaled = True
114
115    ############################
116    def write(self, record):
117        """Register that we've had a write() call; reset timeout timer."""
118        if record is None and not self.none_is_okay:
119            return
120        if not record and not self.empty_is_okay:
121            return
122
123        # If here, we got a bona fide record. Reset our timer.
124        with self.timeout_lock:
125            if self.timed_out:
126                self.timed_out = False
127                self.writer.write(self.resume_message)
128            self.last_record = time.time()

Base class Writer about which we know nothing else. By default the input format is Unknown unless overridden.

Passes arguments quiet, encoding and encoding_errors up to BaseModule

TimeoutWriter( writer, timeout, message=None, resume_message=None, empty_is_okay=False, none_is_okay=False, **kwargs)
11    def __init__(self, writer, timeout, message=None, resume_message=None,
12                 empty_is_okay=False, none_is_okay=False, **kwargs):
13        """Instantiated with a client Writer instance (such as a
14        LogfileWriter), an interval, a timeout and optional
15        message. Expects its write() method to be called at least every
16        'timeout' seconds. If it isn't, call the client's write method
17        with 'message' to indicate that it has timed out. Once it receives
18        a call to its write() method after timing out, call the client's
19        write method with 'resume_message' to indicate that it is no
20        longer timed out.
21        ```
22        writer         A client writer instance
23
24        timeout        Timeout interval in seconds
25
26        message        Message to be returned if client reader fails to return
27                       a record within the timeout interval
28
29        resume_message Message to be returned when client returns a record after
30                       having timed out
31
32        empty_is_okay If True, receiving an empty record is sufficient to reset
33                      the timer.
34        none_is_okay  If True, receiving a 'None' record is sufficient to reset
35                        the timer.
36        ```
37        Sample config that echos stdin and issues timeouts if no input for 5 secs:
38        ```
39          readers:
40          - class: TextFileReader
41          transforms:
42          - class: TimestampTransform
43          writers:
44          - class: TextFileWriter
45          - class: TimeoutWriter
46            kwargs:
47              writer:
48                class: TextFileWriter
49              timeout: 5
50              message: No message received for 5 seconds
51              resume_message: Okay, got another message
52        ```
53        """
54        # Initialize type checking
55        super().__init__(**kwargs)  # processes 'quiet' and type hints
56
57        self.writer = writer
58        self.timeout = timeout
59        self.message = message or ('Timeout: no %s record received in %d seconds'
60                                   % (writer, timeout))
61        self.resume_message = resume_message or ('Timeout: %s record received'
62                                                 % writer)
63        self.empty_is_okay = empty_is_okay
64        self.none_is_okay = none_is_okay
65
66        # When we got our last record (or were instantiated)
67        self.last_record = time.time()
68
69        # Keep track of whether we're currently timed out or not
70        self.timed_out = False
71
72        # Protect self.last_record and self.timed_out
73        self.timeout_lock = threading.Lock()
74
75        # To let us cleanly exit _timeout_thread
76        self.quit_signaled = False
77
78        # Start the timeout loop in a separate thread
79        self.timeout_thread = threading.Thread(target=self._timeout_thread,
80                                               name='timeout_thread', daemon=True)
81        self.timeout_thread.start()

Instantiated with a client Writer instance (such as a LogfileWriter), an interval, a timeout and optional message. Expects its write() method to be called at least every 'timeout' seconds. If it isn't, call the client's write method with 'message' to indicate that it has timed out. Once it receives a call to its write() method after timing out, call the client's write method with 'resume_message' to indicate that it is no longer timed out.

writer         A client writer instance

timeout        Timeout interval in seconds

message        Message to be returned if client reader fails to return
               a record within the timeout interval

resume_message Message to be returned when client returns a record after
               having timed out

empty_is_okay If True, receiving an empty record is sufficient to reset
              the timer.
none_is_okay  If True, receiving a 'None' record is sufficient to reset
                the timer.

Sample config that echos stdin and issues timeouts if no input for 5 secs:

  readers:
  - class: TextFileReader
  transforms:
  - class: TimestampTransform
  writers:
  - class: TextFileWriter
  - class: TimeoutWriter
    kwargs:
      writer:
        class: TextFileWriter
      timeout: 5
      message: No message received for 5 seconds
      resume_message: Okay, got another message
writer
timeout
message
resume_message
empty_is_okay
none_is_okay
last_record
timed_out
timeout_lock
quit_signaled
timeout_thread
def quit(self):
112    def quit(self):
113        self.quit_signaled = True
def write(self, record):
116    def write(self, record):
117        """Register that we've had a write() call; reset timeout timer."""
118        if record is None and not self.none_is_okay:
119            return
120        if not record and not self.empty_is_okay:
121            return
122
123        # If here, we got a bona fide record. Reset our timer.
124        with self.timeout_lock:
125            if self.timed_out:
126                self.timed_out = False
127                self.writer.write(self.resume_message)
128            self.last_record = time.time()

Register that we've had a write() call; reset timeout timer.