def _parse_event_log()

in utils/ptreetime/ptreetime.py [0:0]


def _parse_event_log(path):
    # Load the file as JSON.
    with open(path) as f:
        data = json.load(f)
        command = data['command']
        events_data = data['events']

    # Convert the events data into events.
    def convert_event(data):
        evt_name = data.pop('evt', '').strip()
        evt_class = _event_classes.get(evt_name)
        if evt_class is None:
            raise ValueError("unknown event: %r" % ((evt_name, data),))

        try:
            return evt_class(**data)
        except TypeError:
            raise ValueError("invalid event: %r (unable to instantiate %r)" % (
                    (evt_name, data), evt_class))
    events = [convert_event(d)
              for d in events_data]

    # Order all of the events by timestamp.
    events.sort(key = lambda event: event.timestamp)

    # Check that the file is complete.
    if not events:
        raise ValueError("data file has no events: %r" % (path,))
    if not isinstance(events[0], PTreeStartEvent):
        raise ValueError("data file %r starts with unexpected event %r" % (
              path, events[0]))
    if not isinstance(events[-1], PTreeStopEvent):
        raise ValueError("data file %r ends with unexpected event %r" % (
              path, events[-1]))

    # Get the target PID.
    target = events[0].target
    target_start_timestamp = events[0].timestamp

    # Drop the start and stop events.
    events = events[1:-1]

    # Build the process tree list.
    def get_record_for_pid(pid):
        # Lookup the PID.
        record = active_processes.get(pid)
        if record is not None:
            return record

        # The PID was unknown, create a record for it.
        active_processes[pid] = record = ProcessInfo(pid)

        # Add to the list of all records.
        all_records.append(record)
        roots.add(record)

        return record

    all_records = []
    roots = set()
    target_root = None
    active_processes = {}
    active_spawn_args = {}
    for event in events:
        # Handle the exit of the target process specially.
        if event.pid == target:
            if not isinstance(event, PTreeProcExitEvent):
                raise RuntimeError("unexpected event for target %r" % (
                        event,))

            assert isinstance(event, PTreeProcExitEvent)
            target_root = get_record_for_pid(event.pid)
            roots.remove(target_root)
            target_root.start_timestamp = target_start_timestamp
            target_root.exit_timestamp = event.timestamp
            target_root.name = event.name
            del active_processes[event.pid]
            continue

        # First, lookup or create an entry for the parent process.
        parent_process = get_record_for_pid(event.parent)

        # Get the record for this PID.
        child_process = get_record_for_pid(event.pid)

        # If this is a create event, store the timestamp and add it to the
        # parent.
        if isinstance(event, PTreeProcCreateEvent):
            if child_process.parent:
                raise RuntimeError("multiple create events for %r" % (
                        event,))
            child_process.parent = parent_process
            child_process.start_timestamp = event.timestamp
            parent_process.children.append(child_process)
            roots.remove(child_process)

            child_process.args = active_spawn_args.pop(event.parent, None)
            if child_process.args is not None:
                child_process.name = os.path.basename(child_process.args[0])
            continue

        # Otherwise, handle the various "user" events.
        if isinstance(event, PTreeUserStartupEvent):
            child_process.user_start_timestamp = event.timestamp
            child_process.startup_user_time = event.user_time
            child_process.startup_system_time = event.system_time
            continue
        if isinstance(event, PTreeUserExecEvent):
            # If the child process already has arguments defined, then the
            # process is re-exec'ing itself. Create a new process entry.
            if child_process.args is not None:
                child_process.exit_timestamp = \
                    child_process.user_exit_timestamp = event.timestamp
                child_process.user_time = event.user_time
                child_process.system_time = event.system_time
                # FIXME: Get utime and stime available here, and copy.
                del active_processes[event.pid]

                child_process = get_record_for_pid(event.pid)
                child_process.parent = parent_process
                child_process.start_timestamp = event.timestamp
                child_process.args = event.args
                child_process.name = os.path.basename(child_process.args[0])
                parent_process.children.append(child_process)
                roots.remove(child_process)
            else:
                child_process.args = event.args
                child_process.name = os.path.basename(child_process.args[0])
            continue
        if isinstance(event, PTreeUserSpawnEvent):
            active_spawn_args[event.pid] = event.args
            continue
        if isinstance(event, PTreeUserExitEvent):
            child_process.user_exit_timestamp = event.timestamp
            child_process.user_time = event.user_time
            child_process.system_time = event.system_time
            continue

        # Otherwise, this is an exit event, store the event information and
        # update the parent and active process list.
        if child_process.parent is None:
            warning('found stray exit: %r' % (
                    (event.timestamp, event.pid, event.name),))
            child_process.parent = parent_process
            parent_process.children.append(child_process)
            roots.remove(child_process)
        assert isinstance(event, PTreeProcExitEvent)
        child_process.exit_timestamp = event.timestamp
        child_process.name = event.name
        del active_processes[event.pid]

    return target_root, roots, active_processes