Ejemplo n.º 1
0
    def run(self, loop=False):
        # If self.serial_params is None, it means that either read or
        # write device already exist, so we shouldn't actually run, or
        # we'll destroy them.
        if not self.serial_params:
            return
        """Create the virtual port with socat and start feeding it records from
        the designated logfile. If loop==True, loop when reaching end of input."""
        self.socat_thread = threading.Thread(target=self._run_socat,
                                             daemon=True)
        self.socat_thread.start()
        time.sleep(0.2)

        self.reader = LogfileReader(filebase=self.filebase,
                                    use_timestamps=True,
                                    record_format=self.record_format,
                                    time_format=self.time_format)

        self.writer = TextFileWriter(self.write_port, truncate=True)

        logging.info('Starting %s: %s', self.read_port, self.filebase)
        while not self.quit:
            try:
                record = self.reader.read()  # get the next record
                logging.debug('SimSerial got: %s', record)

                # End of input? If loop==True, re-open the logfile from the start
                if record is None:
                    if not loop:
                        break
                    self.reader = LogfileReader(
                        filebase=self.filebase,
                        use_timestamps=True,
                        record_format=self.record_format,
                        time_format=self.time_format)

                # We've now got a record. Try parsing timestamp off it
                try:
                    parsed_record = self.compiled_record_format.parse(
                        record).named
                    record = parsed_record['record']

                # We had a problem parsing. Discard record and try reading next one.
                except (KeyError, ValueError, AttributeError):
                    logging.warning('Unable to parse record into "%s"',
                                    self.record_format)
                    logging.warning('Record: %s', record)
                    continue

                if not record:
                    continue

                logging.debug('SimSerial writing: %s', record)
                self.writer.write(record)  # and write it to the virtual port
            except (OSError, KeyboardInterrupt):
                break

        # If we're here, we got None from our input, and are done. Signal
        # for run_socat to exit
        self.quit = True
Ejemplo n.º 2
0
    def run(self):
        """Create the virtual port with socat and start feeding it records from
    the designated logfile."""
        self.socat_thread = threading.Thread(target=self._run_socat)
        self.socat_thread.start()
        time.sleep(0.2)

        self.reader = LogfileReader(filebase=self.source_file,
                                    use_timestamps=self.use_timestamps)
        self.strip = SliceTransform('1:')  # strip off the first field)
        self.writer = TextFileWriter(self.write_port, truncate=True)

        while not self.quit:
            record = self.reader.read()  # get the next record
            logging.debug('SimSerial got: %s', record)
            if record is None:
                break
            record = self.strip.transform(record)  # strip the timestamp
            if record:
                logging.debug('SimSerial writing: %s', record)
                self.writer.write(record)  # and write it to the virtual port

        # If we're here, we got None from our input, and are done. Signal
        # for run_socat to exit
        self.quit = True
Ejemplo n.º 3
0
  def __init__(self, port, prefix=None, timestamp=False,
               time_format=TIME_FORMAT, filebase=None, eol='\n'):
    """
    ```
    port -  UDP port on which to write records.

    prefix - If non-empty, prefix to add

    timestamp = If True, apply current timestamp to record

    time_format - What format to use for timestamp

    filebase - Prefix string to be matched (with a following "*") to find
               files to be used. e.g. /tmp/log/NBP1406/knud/raw/NBP1406_knud
    ```
    """
    self.port = port
    self.prefix = PrefixTransform(prefix) if prefix else None
    self.timestamp = TimestampTransform() if timestamp else None
    self.time_format = time_format
    self.filebase = filebase

    # Do we have any files we can actually read from?
    if not glob.glob(filebase + '*'):
      logging.warning('No files matching "%s*"', filebase)
      self.quit_flag = True
      return

    self.reader = LogfileReader(filebase=filebase, use_timestamps=True,
                                time_format=self.time_format)
    self.slice_n = SliceTransform(fields='1:') # strip off timestamp
    self.writer = UDPWriter(port=port, eol=eol)

    self.first_time = True
    self.quit_flag = False
Ejemplo n.º 4
0
    def test_use_timestamp(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            tmpfilename = tmpdirname + '/mylog-2017-02-02'
            sample_lines = SAMPLE_DATA.split('\n')
            create_file(tmpfilename, sample_lines)

            reader = LogfileReader(tmpfilename, use_timestamps=True)
            for line in sample_lines:
                self.assertEqual(line, reader.read())
            self.assertEqual(None, reader.read())
Ejemplo n.º 5
0
    def run(self, loop=False):
        # If self.serial_params is None, it means that either read or
        # write device already exist, so we shouldn't actually run, or
        # we'll destroy them.
        if not self.serial_params:
            return
        """Create the virtual port with socat and start feeding it records from
    the designated logfile. If loop==True, loop when reaching end of input."""
        self.socat_thread = threading.Thread(target=self._run_socat,
                                             daemon=True)
        self.socat_thread.start()
        time.sleep(0.2)

        self.reader = LogfileReader(filebase=self.filebase,
                                    use_timestamps=True,
                                    time_format=self.time_format)

        self.slice_n = SliceTransform(
            '1:')  # strip off the first field (timestamp)
        self.writer = TextFileWriter(self.write_port, truncate=True)

        logging.info('Starting %s: %s', self.read_port, self.filebase)
        while not self.quit:
            try:
                record = self.reader.read()  # get the next record
                logging.debug('SimSerial got: %s', record)

                # End of input? If loop==True, re-open the logfile from the start
                if record is None:
                    if not loop:
                        break
                    self.reader = LogfileReader(filebase=self.filebase,
                                                use_timestamps=True,
                                                time_format=self.time_format)

                record = self.slice_n.transform(record)  # strip the timestamp
                if not record:
                    continue
                if self.timestamp:  # do we want to add a timestamp?
                    record = self.timestamp.transform(record)
                if self.prefix:  # do we want to add prefix?
                    record = self.prefix.transform(record)

                logging.debug('SimSerial writing: %s', record)
                self.writer.write(record)  # and write it to the virtual port
            except (OSError, KeyboardInterrupt):
                break

        # If we're here, we got None from our input, and are done. Signal
        # for run_socat to exit
        self.quit = True
Ejemplo n.º 6
0
    def run(self, loop=False):
        """Start reading and writing data. If loop==True, loop when reaching
        end of input.
        """
        logging.info('Starting %s: %s', self.port, self.filebase)
        try:
            while not self.quit_flag:
                record = self.reader.read()

                # If we don't have a record, we're (probably) at the end of
                # the file. If it's the first time we've tried reading, it
                # means we probably didn't get a usable file. Either break out
                # (if we're not looping, or if we don't have a usable file),
                # or start reading from the beginning (if we are looping and
                # have a usable file).
                if not record:
                    if not loop or self.first_time:
                        break
                    logging.info('Looping instrument %s', self.prefix)
                    self.reader = LogfileReader(
                        filebase=self.filebase,
                        record_format=self.record_format,
                        use_timestamps=True)
                    continue

                # We've now got a record. Try parsing timestamp off it
                try:
                    parsed_record = self.compiled_record_format.parse(
                        record).named
                    record = parsed_record['record']

                # We had a problem parsing. Discard record and try reading next one.
                except (KeyError, ValueError, AttributeError):
                    logging.warning('Unable to parse record into "%s"',
                                    self.record_format)
                    logging.warning('Record: %s', record)
                    continue

                if not record:
                    continue

                self.writer.write(record)
                self.first_time = False

        except (OSError, KeyboardInterrupt):
            self.quit_flag = True

        logging.info('Finished %s', self.prefix)
Ejemplo n.º 7
0
    def test_tail_false(self):
        # Don't specify 'tail' and expect there to be no data
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)

            # Create a file slowly, one line at a time
            target = 'mylogfile'
            tmpfilename = tmpdirname + '/' + target
            sample_lines = SAMPLE_DATA.split('\n')
            threading.Thread(target=create_file,
                             args=(tmpfilename, sample_lines, 0.25)).start()

            time.sleep(0.05)  # let the thread get started

            # Read, and wait for lines to come
            reader = LogfileReader(tmpfilename, tail=False)
            self.assertEqual(None, reader.read())
Ejemplo n.º 8
0
    def test_interval(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            tmpfilename = tmpdirname + '/mylog-2017-02-02'
            sample_lines = SAMPLE_DATA.split('\n')
            create_file(tmpfilename, sample_lines)

            interval = 0.2
            reader = LogfileReader(tmpfilename, interval=interval)
            then = 0
            for line in sample_lines:
                self.assertEqual(line, reader.read())
                now = time.time()
                if then:
                    self.assertAlmostEqual(now - then, interval, places=1)
                then = now

            self.assertEqual(None, reader.read())
Ejemplo n.º 9
0
  def run(self, loop=False):
    """Start reading and writing data. If loop==True, loop when reaching
    end of input.
    """
    logging.info('Starting %s: %s', self.port, self.filebase)
    try:
      while not self.quit_flag:
        record = self.reader.read()

        # If we don't have a record, we're (probably) at the end of
        # the file. If it's the first time we've tried reading, it
        # means we probably didn't get a usable file. Either break out
        # (if we're not looping, or if we don't have a usable file),
        # or start reading from the beginning (if we are looping and
        # have a usable file).
        if not record:
          if not loop or self.first_time:
            break
          logging.info('Looping instrument %s', self.prefix)
          self.reader = LogfileReader(filebase=self.filebase,
                                      use_timestamps=True)
          continue

        # Strip off timestamp
        record =  self.slice_n.transform(record)
        if not record:
          continue
        record = record.strip()
        if not record:
          continue

        if self.timestamp:      # do we want to add a timestamp?
          record = self.timestamp.transform(record)
        if self.prefix:         # do we want to add prefix?
          record = self.prefix.transform(record)

        self.writer.write(record)
        self.first_time = False

    except (OSError, KeyboardInterrupt):
      self.quit_flag = True

    logging.info('Finished %s', self.prefix)
Ejemplo n.º 10
0
    def test_tail_true(self):
        # Do the same thing as test_tail_false, but specify tail=True. We should
        # now get all the lines that are eventually written to the file.
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)

            # Create a file slowly, one line at a time
            target = 'mylogfile'
            tmpfilename = tmpdirname + '/' + target
            sample_lines = SAMPLE_DATA.split('\n')
            threading.Thread(target=create_file,
                             args=(tmpfilename, sample_lines, 0.25)).start()

            time.sleep(0.05)  # let the thread get started

            # Read, and wait for lines to come
            reader = LogfileReader(tmpfilename, tail=True)
            for line in sample_lines:
                self.assertEqual(line, reader.read())
Ejemplo n.º 11
0
    def test_use_timestamps(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            tmpfilename = tmpdirname + '/mylog-2017-02-02'
            sample_lines = SAMPLE_DATA.split('\n')
            create_file(tmpfilename, sample_lines)

            # Logs timestamps were created artificially with ~0.25 intervals
            interval = 0.25
            reader = LogfileReader(tmpfilename, use_timestamps=True)
            then = 0
            for line in sample_lines:
                result = reader.read()
                self.assertEqual(line, result)
                now = time.time()
                if then:
                    self.assertAlmostEqual(now - then, interval, places=1)
                then = now

            self.assertEqual(None, reader.read())
Ejemplo n.º 12
0
    def __init__(self, port, filebase, instrument):
        """
        ```
        port -  UDP port on which to write records.

        filebase - Prefix string to be matched (with a following "*") to fine
                   files to be used. e.g. /tmp/log/NBP1406/knud/raw/NBP1406_knud

        instrument - Instrument name prefix to add before sendind out on wire
        ```
        """
        self.filebase = filebase
        self.reader = LogfileReader(filebase=filebase, use_timestamps=True)
        self.slice_n = SliceTransform(
            fields='1:')  # grab 2nd and subsequent fields
        self.timestamp = TimestampTransform()
        self.prefix = PrefixTransform(instrument)
        self.writer = UDPWriter(port=port)
        self.instrument = instrument
        self.first_time = True
        self.quit_flag = False
Ejemplo n.º 13
0
    def __init__(self,
                 port,
                 filebase=None,
                 record_format=None,
                 time_format=TIME_FORMAT,
                 eol='\n'):
        """
        ```
        port -  UDP port on which to write records.

        time_format - What format to use for timestamp

        filebase - Prefix string to be matched (with a following "*") to find
                   files to be used. e.g. /tmp/log/NBP1406/knud/raw/NBP1406_knud

        record_format
                     If specified, a custom record format to use for extracting
                     timestamp and record. The default is '{timestamp:ti} {record}'
        ```
        """
        self.port = port
        self.time_format = time_format
        self.filebase = filebase
        self.record_format = record_format or '{timestamp:ti} {record}'
        self.compiled_record_format = parse.compile(self.record_format)

        # Do we have any files we can actually read from?
        if not glob.glob(filebase + '*'):
            logging.warning('No files matching "%s*"', filebase)
            self.quit_flag = True
            return

        self.reader = LogfileReader(filebase=filebase,
                                    use_timestamps=True,
                                    record_format=self.record_format,
                                    time_format=self.time_format)
        self.writer = UDPWriter(port=port, eol=eol)

        self.first_time = True
        self.quit_flag = False
Ejemplo n.º 14
0
    def run(self, loop=False):
        """Create the virtual port with socat and start feeding it records from
        the designated logfile. If loop==True, loop when reaching end of input."""
        self.socat_thread = threading.Thread(target=self._run_socat,
                                             daemon=True)
        self.socat_thread.start()
        time.sleep(0.2)

        self.reader = LogfileReader(filebase=self.source_file,
                                    use_timestamps=self.use_timestamps,
                                    time_format=self.time_format)

        self.strip = SliceTransform('1:')  # strip off the first field)
        self.writer = TextFileWriter(self.write_port, truncate=True)

        while not self.quit:
            try:
                record = self.reader.read()  # get the next record
                logging.debug('SimSerial got: %s', record)

                # End of input? If loop==True, re-open the logfile from the start
                if record is None:
                    if not loop:
                        break
                    self.reader = LogfileReader(
                        filebase=self.source_file,
                        use_timestamps=self.use_timestamps)

                record = self.strip.transform(record)  # strip the timestamp
                if record:
                    logging.debug('SimSerial writing: %s', record)
                    self.writer.write(
                        record)  # and write it to the virtual port
            except (OSError, KeyboardInterrupt):
                break

        # If we're here, we got None from our input, and are done. Signal
        # for run_socat to exit
        self.quit = True
Ejemplo n.º 15
0
    def test_basic_seek(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            filebase = tmpdirname + '/mylog-'
            sample_lines = []
            for f in sorted(SAMPLE_DATA_2):
                create_file(filebase + f, SAMPLE_DATA_2[f])
                sample_lines.extend(SAMPLE_DATA_2[f])
            START_TIMESTAMP = get_msec_timestamp(sample_lines[0])
            END_TIMESTAMP = get_msec_timestamp(sample_lines[-1])

            reader = LogfileReader(filebase)
            self.assertEqual(START_TIMESTAMP, reader.seek_time(0, 'start'))
            self.assertEqual(sample_lines[0], reader.read())
            self.assertEqual(START_TIMESTAMP + 1000,
                             reader.seek_time(1000, 'start'))
            self.assertEqual(sample_lines[4], reader.read())
            self.assertEqual(sample_lines[5], reader.read())
            self.assertEqual(END_TIMESTAMP, reader.seek_time(0, 'end'))
            self.assertEqual(None, reader.read())
Ejemplo n.º 16
0
class SimNetwork:
    """Open a network port and feed stored logfile data to it."""

    ############################

    def __init__(self, port, filebase, instrument):
        """
        ```
        port -  UDP port on which to write records.

        filebase - Prefix string to be matched (with a following "*") to fine
                   files to be used. e.g. /tmp/log/NBP1406/knud/raw/NBP1406_knud

        instrument - Instrument name prefix to add before sendind out on wire
        ```
        """
        self.filebase = filebase
        self.reader = LogfileReader(filebase=filebase, use_timestamps=True)
        self.slice_n = SliceTransform(
            fields='1:')  # grab 2nd and subsequent fields
        self.timestamp = TimestampTransform()
        self.prefix = PrefixTransform(instrument)
        self.writer = UDPWriter(port=port)
        self.instrument = instrument
        self.first_time = True
        self.quit_flag = False

    ############################
    def run(self, loop=False):
        """Start reading and writing data. If loop==True, loop when reaching
        end of input.
        """
        logging.info('Starting %s', self.instrument)
        try:
            while not self.quit_flag:
                record = self.reader.read()

                # If we don't have a record, we're (probably) at the end of
                # the file. If it's the first time we've tried reading, it
                # means we probably didn't get a usable file. Either break out
                # (if we're not looping, or if we don't have a usable file),
                # or start reading from the beginning (if we are looping and
                # have a usable file).
                if not record:
                    if not loop or self.first_time:
                        break
                    logging.info('Looping instrument %s', self.instrument)
                    self.reader = LogfileReader(filebase=self.filebase,
                                                use_timestamps=True)
                    continue

                # Strip off timestamp and tack on a new one
                record = self.slice_n.transform(record)
                record = self.timestamp.transform(record)

                # Add instrument name back on, and write to specified network
                record = self.prefix.transform(record)
                self.writer.write(record)
                self.first_time = False

        except (OSError, KeyboardInterrupt):
            self.quit_flag = True

        logging.info('Finished %s', self.instrument)
Ejemplo n.º 17
0
class SimSerial:
    """Create a virtual serial port and feed stored logfile data to it."""

    ############################
    def __init__(self,
                 port,
                 source_file,
                 use_timestamps=True,
                 baudrate=9600,
                 bytesize=8,
                 parity='N',
                 stopbits=1,
                 timeout=None,
                 xonxoff=False,
                 rtscts=False,
                 write_timeout=None,
                 dsrdtr=False,
                 inter_byte_timeout=None,
                 exclusive=None):
        """Takes source file, whether to deliver data at rate indicated by
    timestamps, and the standard parameters that a serial port takes."""
        self.source_file = source_file
        self.use_timestamps = use_timestamps

        # We'll create two virtual ports: 'port' and 'port_in'; we will write
        # to port_in and read the values back out from port
        self.read_port = port
        self.write_port = port + '_in'

        self.serial_params = {
            'baudrate': baudrate,
            'byteside': bytesize,
            'parity': parity,
            'stopbits': stopbits,
            'timeout': timeout,
            'xonxoff': xonxoff,
            'rtscts': rtscts,
            'write_timeout': write_timeout,
            'dsrdtr': dsrdtr,
            'inter_byte_timeout': inter_byte_timeout,
            'exclusive': exclusive
        }
        self.quit = False

        # Finally, check that our needed 'socat' actually exists
        if not subprocess.run(['which', 'socat'],
                              stdout=subprocess.PIPE).stdout:
            raise NameError(
                'Executable "socat" not found on path. Please refer '
                'to installation guide to install socat.')

    ############################
    def _run_socat(self):
        """Internal: run the actual command."""
        verbose = '-d'
        write_port_params = 'pty,link=%s,raw,echo=0' % self.write_port
        read_port_params = 'pty,link=%s,raw,echo=0' % self.read_port

        cmd = [
            '/usr/bin/env',
            'socat',
            verbose,
            #verbose,   # repeating makes it more verbose
            read_port_params,
            write_port_params,
        ]
        try:
            # Run socat process using Popen, checking every second or so whether
            # it's died (poll() != None) or we've gotten a quit signal.
            logging.info('Calling: %s', ' '.join(cmd))
            socat_process = subprocess.Popen(cmd)
            while not self.quit and not socat_process.poll():
                try:
                    socat_process.wait(1)
                except subprocess.TimeoutExpired:
                    pass

        except Exception as e:
            logging.error('ERROR: socat command: %s', e)

        # If here, process has terminated, or we've seen self.quit. We
        # want both to be true: if we've terminated, set self.quit so that
        # 'run' loop can exit. If self.quit, terminate process.
        if self.quit:
            socat_process.kill()
        else:
            self.quit = True
        logging.info('Finished: %s', ' '.join(cmd))

    ############################
    def run(self):
        """Create the virtual port with socat and start feeding it records from
    the designated logfile."""
        self.socat_thread = threading.Thread(target=self._run_socat)
        self.socat_thread.start()
        time.sleep(0.2)

        self.reader = LogfileReader(filebase=self.source_file,
                                    use_timestamps=self.use_timestamps)
        self.strip = SliceTransform('1:')  # strip off the first field)
        self.writer = TextFileWriter(self.write_port, truncate=True)

        while not self.quit:
            record = self.reader.read()  # get the next record
            logging.debug('SimSerial got: %s', record)
            if record is None:
                break
            record = self.strip.transform(record)  # strip the timestamp
            if record:
                logging.debug('SimSerial writing: %s', record)
                self.writer.write(record)  # and write it to the virtual port

        # If we're here, we got None from our input, and are done. Signal
        # for run_socat to exit
        self.quit = True
Ejemplo n.º 18
0
    def test_read_time_range(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            filebase = tmpdirname + '/mylog-'
            sample_lines = []
            for f in sorted(SAMPLE_DATA_2):
                create_file(filebase + f, SAMPLE_DATA_2[f])
                sample_lines.extend(SAMPLE_DATA_2[f])
            START_TIMESTAMP = get_msec_timestamp(sample_lines[0])
            END_TIMESTAMP = get_msec_timestamp(sample_lines[-1])

            reader = LogfileReader(filebase)
            records = reader.read_time_range(START_TIMESTAMP, END_TIMESTAMP)
            self.assertEqual(records, sample_lines[:-1])
            records = reader.read_time_range(START_TIMESTAMP,
                                             END_TIMESTAMP + .01)
            self.assertEqual(records, sample_lines)
            records = reader.read_time_range(START_TIMESTAMP + 1,
                                             END_TIMESTAMP)
            self.assertEqual(records, sample_lines[1:-1])
            records = reader.read_time_range(START_TIMESTAMP + 1,
                                             END_TIMESTAMP + 1)
            self.assertEqual(records, sample_lines[1:])
            records = reader.read_time_range(START_TIMESTAMP + .001, None)
            self.assertEqual(records, sample_lines[1:])
            records = reader.read_time_range(None, END_TIMESTAMP)
            self.assertEqual(records, sample_lines[:-1])
            records = reader.read_time_range(None, None)
            self.assertEqual(records, sample_lines)
            records = reader.read_time_range(START_TIMESTAMP, START_TIMESTAMP)
            self.assertEqual(records, [])
            records = reader.read_time_range(START_TIMESTAMP + 1000, None)
            self.assertEqual(records, sample_lines[4:])
            records = reader.read_time_range(START_TIMESTAMP + 1000,
                                             END_TIMESTAMP - 1000)
            self.assertEqual(records, sample_lines[4:9])
            records = reader.read_time_range(START_TIMESTAMP + 1000,
                                             START_TIMESTAMP + 500)
            self.assertEqual(records, [])
            with self.assertRaises(ValueError):
                records = reader.read_time_range(START_TIMESTAMP - 1,
                                                 END_TIMESTAMP)
Ejemplo n.º 19
0
    def test_seek_after_reading_to_end(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            filebase = tmpdirname + '/mylog-'
            sample_lines = []
            for f in sorted(SAMPLE_DATA_2):
                create_file(filebase + f, SAMPLE_DATA_2[f])
                sample_lines.extend(SAMPLE_DATA_2[f])
            START_TIMESTAMP = get_msec_timestamp(sample_lines[0])
            END_TIMESTAMP = get_msec_timestamp(sample_lines[-1])

            reader = LogfileReader(filebase)
            while reader.read() is not None:
                pass
            self.assertEqual(END_TIMESTAMP, reader.seek_time(0, 'current'))
            self.assertEqual(None, reader.read())
            self.assertEqual(END_TIMESTAMP, reader.seek_time(0, 'end'))
            self.assertEqual(None, reader.read())
            self.assertEqual(END_TIMESTAMP - 1000,
                             reader.seek_time(-1000, 'current'))
            self.assertEqual(sample_lines[9], reader.read())
            while reader.read() is not None:
                pass
            self.assertEqual(END_TIMESTAMP - 1000,
                             reader.seek_time(-1000, 'end'))
            self.assertEqual(sample_lines[9], reader.read())
Ejemplo n.º 20
0
    def test_seek_current(self):
        with tempfile.TemporaryDirectory() as tmpdirname:
            logging.info('created temporary directory "%s"', tmpdirname)
            filebase = tmpdirname + '/mylog-'
            sample_lines = []
            for f in sorted(SAMPLE_DATA_2):
                create_file(filebase + f, SAMPLE_DATA_2[f])
                sample_lines.extend(SAMPLE_DATA_2[f])
            START_TIMESTAMP = get_msec_timestamp(sample_lines[0])
            END_TIMESTAMP = get_msec_timestamp(sample_lines[-1])

            reader = LogfileReader(filebase)
            self.assertEqual(START_TIMESTAMP, reader.seek_time(0, 'current'))
            self.assertEqual(START_TIMESTAMP + 1000,
                             reader.seek_time(1000, 'current'))

            # the first record with t >= START_TIMESTAMP + 1000 (= 1509840000441.672) is sample_lines[4]
            timestamp_of_expected_next_record = get_msec_timestamp(
                sample_lines[4])  # 1509840000460.595
            self.assertEqual(timestamp_of_expected_next_record,
                             reader.seek_time(0, 'current'))
            self.assertEqual(timestamp_of_expected_next_record - 500,
                             reader.seek_time(-500, 'current'))

            # now the expected next record is sample_lines[3], since it's the first one with
            # t > timestamp_of_expected_next_record - 500 (= 1509839999960.595)
            self.assertEqual(sample_lines[3], reader.read())
            self.assertEqual(sample_lines[4], reader.read())

            # now seek to a time later than the last timestamp: check that the returned
            # time is the requested time, and that a subsequent read() returns None
            timestamp_of_expected_next_record = get_msec_timestamp(
                sample_lines[5])
            self.assertEqual(timestamp_of_expected_next_record + 10000,
                             reader.seek_time(10000, 'current'))
            self.assertEqual(None, reader.read())

            # check that 'current' time is now END_TIMESTAMP (= 1509840002486.203)
            self.assertEqual(END_TIMESTAMP, reader.seek_time(0, 'current'))

            # go back one second (to 1509840001486.203)
            # next record should be sample_lines[9] (t = 1509840001726.024)
            self.assertEqual(END_TIMESTAMP - 1000,
                             reader.seek_time(-1000, 'current'))
            self.assertEqual(sample_lines[9], reader.read())
Ejemplo n.º 21
0
                for filename in new_args.file.split(','):
                    readers.append(
                        TextFileReader(
                            file_spec=filename,
                            tail=all_args.tail,
                            refresh_file_spec=all_args.refresh_file_spec))

            if new_args.network:
                for addr in new_args.network.split(','):
                    readers.append(NetworkReader(network=addr))

            if new_args.logfile:
                for filebase in new_args.logfile.split(','):
                    readers.append(
                        LogfileReader(
                            filebase=filebase,
                            use_timestamps=all_args.logfile_use_timestamps,
                            refresh_file_spec=all_args.refresh_file_spec))

            # For each comma-separated spec, parse out values for
            # user@host:database:data_id[:message_type]. We count on
            # --database_password having been specified somewhere.
            if new_args.database:
                password = all_args.database_password
                (user, host_db) = new_args.database.split('@')
                (host, database) = host_db.split(':', maxsplit=1)
                if ':' in database:
                    (database, fields) = database.split(':')
                else:
                    fields = None
                readers.append(
                    DatabaseReader(fields=fields,
Ejemplo n.º 22
0
class SimSerial:
    """Create a virtual serial port and feed stored logfile data to it."""

    ############################

    def __init__(self,
                 port,
                 time_format=TIME_FORMAT,
                 filebase=None,
                 record_format=None,
                 eol='\n',
                 baudrate=9600,
                 bytesize=8,
                 parity='N',
                 stopbits=1,
                 timeout=None,
                 xonxoff=False,
                 rtscts=False,
                 write_timeout=None,
                 dsrdtr=False,
                 inter_byte_timeout=None,
                 exclusive=None):
        """
        Simulate a serial port, feeding it data from the specified file.

        ```
        port - Temporary serial port to create and make available for reading
               records.

        filebase     Possibly wildcarded string specifying files to be opened.

        record_format
                     If specified, a custom record format to use for extracting
                     timestamp and record. The default is '{timestamp:ti} {record}'.

        time_format - What format to use for timestamp
        ```
        """
        # We'll create two virtual ports: 'port' and 'port_in'; we will write
        # to port_in and read the values back out from port
        self.read_port = port
        self.write_port = port + '_in'
        self.time_format = time_format
        self.filebase = filebase
        self.record_format = record_format or '{timestamp:ti} {record}'
        self.compiled_record_format = parse.compile(self.record_format)
        self.eol = eol
        self.serial_params = None

        # Complain, but go ahead if read_port or write_port exist.
        for path in [self.read_port, self.write_port]:
            if os.path.exists(path):
                logging.warning('Path %s exists; overwriting!', path)

        # Do we have any files we can actually read from?
        if not glob.glob(filebase + '*'):
            logging.warning('No files matching "%s*"', filebase)
            return

        # Set up our parameters
        self.serial_params = {
            'baudrate': baudrate,
            'byteside': bytesize,
            'parity': parity,
            'stopbits': stopbits,
            'timeout': timeout,
            'xonxoff': xonxoff,
            'rtscts': rtscts,
            'write_timeout': write_timeout,
            'dsrdtr': dsrdtr,
            'inter_byte_timeout': inter_byte_timeout,
            'exclusive': exclusive
        }
        self.quit = False

    ############################
    def run(self, loop=False):
        # If self.serial_params is None, it means that either read or
        # write device already exist, so we shouldn't actually run, or
        # we'll destroy them.
        if not self.serial_params:
            return

        try:
            # Create simulated serial port (something like /dev/ttys2), and link
            # it to the port they want to connect to (like /tmp/tty_s330).
            write_fd, read_fd = pty.openpty()  # open the pseudoterminal
            true_read_port = os.ttyname(
                read_fd)  # this is the true filename of port

            # Get rid of any previous symlink if it exists, and symlink the new pty
            try:
                os.unlink(self.read_port)
            except FileNotFoundError:
                pass
            os.symlink(true_read_port, self.read_port)

            self.reader = LogfileReader(filebase=self.filebase,
                                        use_timestamps=True,
                                        record_format=self.record_format,
                                        time_format=self.time_format)
            logging.info('Starting %s: %s', self.read_port, self.filebase)
            while not self.quit:
                try:
                    record = self.reader.read()  # get the next record
                    logging.debug('SimSerial got: %s', record)

                    # End of input? If loop==True, re-open the logfile from the start
                    if record is None:
                        if not loop:
                            break

                        self.reader = LogfileReader(
                            filebase=self.filebase,
                            use_timestamps=True,
                            record_format=self.record_format,
                            time_format=self.time_format)

                    # We've now got a record. Try parsing timestamp off it
                    try:
                        parsed_record = self.compiled_record_format.parse(
                            record).named
                        record = parsed_record['record']

                    # We had a problem parsing. Discard record and try reading next one.
                    except (KeyError, ValueError, TypeError, AttributeError):
                        logging.warning('Unable to parse record into "%s"',
                                        self.record_format)
                        logging.warning('Record: %s', record)
                        continue

                    if not record:
                        continue

                    logging.debug('SimSerial writing: %s', record)
                    os.write(write_fd, (record + self.eol).encode('utf8'))

                except (OSError, KeyboardInterrupt):
                    break

            # If we're here, we got None from our input, and are done. Signal
            # for run_socat to exit
            self.quit = True

        finally:
            # Get rid of the symlink we've created
            os.unlink(self.read_port)
Ejemplo n.º 23
0
class SimSerial:
  """Create a virtual serial port and feed stored logfile data to it."""
  ############################
  def __init__(self, port, prefix=None, timestamp=False,
               time_format=TIME_FORMAT, filebase=None, eol='\n',
               baudrate=9600, bytesize=8, parity='N', stopbits=1,
               timeout=None, xonxoff=False, rtscts=False, write_timeout=None,
               dsrdtr=False, inter_byte_timeout=None, exclusive=None):
    """
    Simulate a serial port, feeding it data from the specified file.

    ```
    port - Temporary serial port to create and make available for reading
           records.

    prefix - If non-empty, prefix name prefix to add

    timestamp = If True, apply current timestamp to record

    time_format - What format to use for timestamp
    ```
    """
    # We'll create two virtual ports: 'port' and 'port_in'; we will write
    # to port_in and read the values back out from port
    self.read_port = port
    self.write_port = port + '_in'
    self.prefix = PrefixTransform(prefix) if prefix else None
    self.timestamp = TimestampTransform() if timestamp else None
    self.time_format = time_format
    self.filebase = filebase
    self.serial_params = None

    # Complain, but go ahead if read_port or write_port exist.
    for path in [self.read_port, self.write_port]:
      if os.path.exists(path):
        logging.warning('Path %s exists; overwriting!')

    # Do we have any files we can actually read from?
    if not glob.glob(filebase + '*'):
      logging.warning('%s: no files matching "%s*"', prefix, filebase)
      return

    # Set up our parameters
    self.serial_params = {'baudrate': baudrate,
                          'byteside': bytesize,
                          'parity': parity,
                          'stopbits': stopbits,
                          'timeout': timeout,
                          'xonxoff': xonxoff,
                          'rtscts': rtscts,
                          'write_timeout': write_timeout,
                          'dsrdtr': dsrdtr,
                          'inter_byte_timeout': inter_byte_timeout,
                          'exclusive': exclusive}
    self.quit = False

    # Finally, find path to socat executable
    self.socat_path = None
    for socat_path in ['/usr/bin/socat', '/usr/local/bin/socat']:
      if os.path.exists(socat_path) and os.path.isfile(socat_path):
        self.socat_path = socat_path
    if not self.socat_path:
      raise NameError('Executable "socat" not found on path. Please refer '
                      'to installation guide to install socat.')

  ############################
  def _run_socat(self):
    """Internal: run the actual command."""
    verbose = '-d'
    write_port_params =   'pty,link=%s,raw,echo=0' % self.write_port
    read_port_params = 'pty,link=%s,raw,echo=0' % self.read_port

    cmd = [self.socat_path,
           verbose,
           #verbose,   # repeating makes it more verbose
           read_port_params,
           write_port_params,
          ]
    try:
      # Run socat process using Popen, checking every second or so whether
      # it's died (poll() != None) or we've gotten a quit signal.
      logging.info('Calling: %s', ' '.join(cmd))
      socat_process = subprocess.Popen(cmd)
      while not self.quit and not socat_process.poll():
        try:
          socat_process.wait(1)
        except subprocess.TimeoutExpired:
          pass

    except Exception as e:
      logging.error('ERROR: socat command: %s', e)

    # If here, process has terminated, or we've seen self.quit. We
    # want both to be true: if we've terminated, set self.quit so that
    # 'run' loop can exit. If self.quit, terminate process.
    if self.quit:
      socat_process.kill()
    else:
      self.quit = True
    logging.info('Finished: %s', ' '.join(cmd))

  ############################
  def run(self, loop=False):
    # If self.serial_params is None, it means that either read or
    # write device already exist, so we shouldn't actually run, or
    # we'll destroy them.
    if not self.serial_params:
      return

    """Create the virtual port with socat and start feeding it records from
    the designated logfile. If loop==True, loop when reaching end of input."""
    self.socat_thread = threading.Thread(target=self._run_socat, daemon=True)
    self.socat_thread.start()
    time.sleep(0.2)

    self.reader = LogfileReader(filebase=self.filebase, use_timestamps=True,
                                time_format=self.time_format)

    self.slice_n = SliceTransform('1:') # strip off the first field (timestamp)
    self.writer = TextFileWriter(self.write_port, truncate=True)

    logging.info('Starting %s: %s', self.read_port, self.filebase)
    while not self.quit:
      try:
        record = self.reader.read() # get the next record
        logging.debug('SimSerial got: %s', record)

        # End of input? If loop==True, re-open the logfile from the start
        if record is None:
          if not loop:
            break
          self.reader = LogfileReader(filebase=self.filebase,
                                      use_timestamps=True,
                                      time_format=self.time_format)

        record = self.slice_n.transform(record)  # strip the timestamp
        if not record:
          continue
        if self.timestamp:      # do we want to add a timestamp?
          record = self.timestamp.transform(record)
        if self.prefix:         # do we want to add prefix?
          record = self.prefix.transform(record)

        logging.debug('SimSerial writing: %s', record)
        self.writer.write(record)   # and write it to the virtual port
      except (OSError, KeyboardInterrupt):
        break

    # If we're here, we got None from our input, and are done. Signal
    # for run_socat to exit
    self.quit = True
Ejemplo n.º 24
0
    def run(self, loop=False):
        # If self.serial_params is None, it means that either read or
        # write device already exist, so we shouldn't actually run, or
        # we'll destroy them.
        if not self.serial_params:
            return

        try:
            # Create simulated serial port (something like /dev/ttys2), and link
            # it to the port they want to connect to (like /tmp/tty_s330).
            write_fd, read_fd = pty.openpty()  # open the pseudoterminal
            true_read_port = os.ttyname(
                read_fd)  # this is the true filename of port

            # Get rid of any previous symlink if it exists, and symlink the new pty
            try:
                os.unlink(self.read_port)
            except FileNotFoundError:
                pass
            os.symlink(true_read_port, self.read_port)

            self.reader = LogfileReader(filebase=self.filebase,
                                        use_timestamps=True,
                                        record_format=self.record_format,
                                        time_format=self.time_format)
            logging.info('Starting %s: %s', self.read_port, self.filebase)
            while not self.quit:
                try:
                    record = self.reader.read()  # get the next record
                    logging.debug('SimSerial got: %s', record)

                    # End of input? If loop==True, re-open the logfile from the start
                    if record is None:
                        if not loop:
                            break

                        self.reader = LogfileReader(
                            filebase=self.filebase,
                            use_timestamps=True,
                            record_format=self.record_format,
                            time_format=self.time_format)

                    # We've now got a record. Try parsing timestamp off it
                    try:
                        parsed_record = self.compiled_record_format.parse(
                            record).named
                        record = parsed_record['record']

                    # We had a problem parsing. Discard record and try reading next one.
                    except (KeyError, ValueError, TypeError, AttributeError):
                        logging.warning('Unable to parse record into "%s"',
                                        self.record_format)
                        logging.warning('Record: %s', record)
                        continue

                    if not record:
                        continue

                    logging.debug('SimSerial writing: %s', record)
                    os.write(write_fd, (record + self.eol).encode('utf8'))

                except (OSError, KeyboardInterrupt):
                    break

            # If we're here, we got None from our input, and are done. Signal
            # for run_socat to exit
            self.quit = True

        finally:
            # Get rid of the symlink we've created
            os.unlink(self.read_port)
Ejemplo n.º 25
0
class SimUDP:
    """Open a network port and feed stored logfile data to it."""

    ############################

    def __init__(self,
                 port,
                 filebase=None,
                 record_format=None,
                 time_format=TIME_FORMAT,
                 eol='\n'):
        """
        ```
        port -  UDP port on which to write records.

        time_format - What format to use for timestamp

        filebase - Prefix string to be matched (with a following "*") to find
                   files to be used. e.g. /tmp/log/NBP1406/knud/raw/NBP1406_knud

        record_format
                     If specified, a custom record format to use for extracting
                     timestamp and record. The default is '{timestamp:ti} {record}'
        ```
        """
        self.port = port
        self.time_format = time_format
        self.filebase = filebase
        self.record_format = record_format or '{timestamp:ti} {record}'
        self.compiled_record_format = parse.compile(self.record_format)

        # Do we have any files we can actually read from?
        if not glob.glob(filebase + '*'):
            logging.warning('No files matching "%s*"', filebase)
            self.quit_flag = True
            return

        self.reader = LogfileReader(filebase=filebase,
                                    use_timestamps=True,
                                    record_format=self.record_format,
                                    time_format=self.time_format)
        self.writer = UDPWriter(port=port, eol=eol)

        self.first_time = True
        self.quit_flag = False

    ############################
    def run(self, loop=False):
        """Start reading and writing data. If loop==True, loop when reaching
        end of input.
        """
        logging.info('Starting %s: %s', self.port, self.filebase)
        try:
            while not self.quit_flag:
                record = self.reader.read()

                # If we don't have a record, we're (probably) at the end of
                # the file. If it's the first time we've tried reading, it
                # means we probably didn't get a usable file. Either break out
                # (if we're not looping, or if we don't have a usable file),
                # or start reading from the beginning (if we are looping and
                # have a usable file).
                if not record:
                    if not loop or self.first_time:
                        break
                    logging.info('Looping instrument %s', self.prefix)
                    self.reader = LogfileReader(
                        filebase=self.filebase,
                        record_format=self.record_format,
                        use_timestamps=True)
                    continue

                # We've now got a record. Try parsing timestamp off it
                try:
                    parsed_record = self.compiled_record_format.parse(
                        record).named
                    record = parsed_record['record']

                # We had a problem parsing. Discard record and try reading next one.
                except (KeyError, ValueError, AttributeError):
                    logging.warning('Unable to parse record into "%s"',
                                    self.record_format)
                    logging.warning('Record: %s', record)
                    continue

                if not record:
                    continue

                self.writer.write(record)
                self.first_time = False

        except (OSError, KeyboardInterrupt):
            self.quit_flag = True

        logging.info('Finished %s', self.prefix)
Ejemplo n.º 26
0
class SimUDP:
  """Open a network port and feed stored logfile data to it."""
  ############################
  def __init__(self, port, prefix=None, timestamp=False,
               time_format=TIME_FORMAT, filebase=None, eol='\n'):
    """
    ```
    port -  UDP port on which to write records.

    prefix - If non-empty, prefix to add

    timestamp = If True, apply current timestamp to record

    time_format - What format to use for timestamp

    filebase - Prefix string to be matched (with a following "*") to find
               files to be used. e.g. /tmp/log/NBP1406/knud/raw/NBP1406_knud
    ```
    """
    self.port = port
    self.prefix = PrefixTransform(prefix) if prefix else None
    self.timestamp = TimestampTransform() if timestamp else None
    self.time_format = time_format
    self.filebase = filebase

    # Do we have any files we can actually read from?
    if not glob.glob(filebase + '*'):
      logging.warning('No files matching "%s*"', filebase)
      self.quit_flag = True
      return

    self.reader = LogfileReader(filebase=filebase, use_timestamps=True,
                                time_format=self.time_format)
    self.slice_n = SliceTransform(fields='1:') # strip off timestamp
    self.writer = UDPWriter(port=port, eol=eol)

    self.first_time = True
    self.quit_flag = False

  ############################
  def run(self, loop=False):
    """Start reading and writing data. If loop==True, loop when reaching
    end of input.
    """
    logging.info('Starting %s: %s', self.port, self.filebase)
    try:
      while not self.quit_flag:
        record = self.reader.read()

        # If we don't have a record, we're (probably) at the end of
        # the file. If it's the first time we've tried reading, it
        # means we probably didn't get a usable file. Either break out
        # (if we're not looping, or if we don't have a usable file),
        # or start reading from the beginning (if we are looping and
        # have a usable file).
        if not record:
          if not loop or self.first_time:
            break
          logging.info('Looping instrument %s', self.prefix)
          self.reader = LogfileReader(filebase=self.filebase,
                                      use_timestamps=True)
          continue

        # Strip off timestamp
        record =  self.slice_n.transform(record)
        if not record:
          continue
        record = record.strip()
        if not record:
          continue

        if self.timestamp:      # do we want to add a timestamp?
          record = self.timestamp.transform(record)
        if self.prefix:         # do we want to add prefix?
          record = self.prefix.transform(record)

        self.writer.write(record)
        self.first_time = False

    except (OSError, KeyboardInterrupt):
      self.quit_flag = True

    logging.info('Finished %s', self.prefix)
Ejemplo n.º 27
0
          port = int(addr[-1])  # port is last arg
          if len(addr) > 1:
            source = addr[-2] # source (multi/broadcast) is prev arg
          if len(addr) > 2:
            parser.error('Format error for --udp argument. Format '
                         'should be [source:]port')
          readers.append(UDPReader(port=port, source=source, eol=eol))

      if new_args.redis:
        for channel in new_args.redis.split(','):
          readers.append(RedisReader(channel=channel))

      if new_args.logfile:
        for filebase in new_args.logfile.split(','):
          readers.append(LogfileReader(
            filebase=filebase, use_timestamps=all_args.logfile_use_timestamps,
            time_format=all_args.time_format,
            refresh_file_spec=all_args.refresh_file_spec))

      if new_args.cached_data_server:
        fields = new_args.cached_data_server
        server = None
        if fields.find('@') > 0:
          fields, server = fields.split('@')
        subscription = {'fields': {f:{'seconds':0} for f in fields.split(',')}}
        if server:
          readers.append(CachedDataReader(subscription=subscription,
                                          data_server=server))
        else:
          readers.append(CachedDataReader(subscription=subscription))

      # For each comma-separated spec, parse out values for