def __dowork__(work_input, work_output):
    # Unpack input
    if not isinstance(work_input, tuple) or len(work_input) < 1:
        raise ValueError("work_input must be a tuple containing the path for the input database")
    
    if not isinstance(work_output, tuple) or len(work_output) < 1:
        raise ValueError("work_output must be a tuple containing the path for the output html report")
    
    input_dir = work_input[0]
    output_file_path = work_output[0]

    # Events will be a list AslEvent objects
    # For some events "user" and "other details" can be an empty string (boot times for example)
    events = []

    for file_path in os.listdir(input_dir):
        file_path = path.join(input_dir, file_path)
        print("Reading: \"{0}\"".format(file_path))
        try:
            f = open(file_path, "rb")
        except IOError as e:
            print("Couldn't open file {0} ({1}). Skipping this file".format(file_path, e))
            continue

        try:
            db = ccl_asldb.AslDb(f)
        except ccl_asldb.AslDbError as e:
            print("Couldn't open file {0} ({1}). Skipping this file".format(file_path, e))
            f.close()
            continue

        for record in db:
            # *** boots ***
            if record.sender == "bootlog": 
                events.append(AslEvent(record.timestamp, EVENT_BOOT, "", ""))
            # *** shutdowns ***
            elif record.sender == "shutdown":
                events.append(AslEvent(record.timestamp, EVENT_SHUTDOWN, "", ""))
            # *** reboots ***
            elif record.sender == "reboot": 
                events.append(AslEvent(record.timestamp, EVENT_REBOOT, "", ""))
            # *** sleep/hibernation ***
            elif record.sender == "kernel" and record.message == "sleep": 
                events.append(AslEvent(record.timestamp, EVENT_HIBERNATE, "", ""))
            # *** wakes ***
            elif record.sender == "kernel" and record.message.startswith("Wake reason"): # wakes
                reason_match = re.search(r"(?<=Wake reason: )[A-z ]+", record.message)
                if reason_match:
                    reason = "{0} {1}".format(record.message, "({0})".format(WAKE_REASONS[reason_match.group(0).strip()]) if reason_match.group(0).strip() in WAKE_REASONS else "")
                else:
                    reason = record.message
                events.append(AslEvent(record.timestamp, EVENT_WAKE, "", reason))
            # *** logins ***
            elif record.sender in ("login", "loginwindow") and record.facility in ("com.apple.system.lastlog", "com.apple.system.utmpx"):
                login_user = record.key_value_dict["ut_user"] if "ut_user" in record.key_value_dict else ""
                login_requested_by = record.key_value_dict["ut_line"] if "ut_line" in record.key_value_dict else ""
                if "ut_type" in record.key_value_dict:
                    if record.key_value_dict["ut_type"] == "7":
                        login_status = "process starting"
                        login_event_type = EVENT_LOGINWINDOW_LOGIN if record.sender == "loginwindow" else EVENT_LOGIN_LOGIN
                    elif record.key_value_dict["ut_type"] == "8":
                        login_status = "process exiting"
                        login_event_type = EVENT_LOGINWINDOW_LOGOUT if record.sender == "loginwindow" else EVENT_LOGIN_LOGOUT
                    else:
                        login_status = "ut_type={0}".format(record.key_value_dict["ut_type"])
                        login_event_type = EVENT_LOGINWINDOW_UNKNOWN if record.sender == "loginwindow" else EVENT_LOGIN_UNKNOWN
                else:
                    login_status = "unknown"

                # a little but of user friendliness
                if login_requested_by.startswith("tty"):
                    login_requested_by += " (terminal window)"
                if record.sender == "loginwindow":
                    login_requested_by += " (login from login window GUI)"

                events.append(AslEvent(record.timestamp, login_event_type, login_user, "Login for: \"{0}\"; Status: \"{1}\"".format(login_requested_by, login_status)))
            # *** failed auth ***
            elif record.sender == "authorizationhost" and record.facility == "authpriv" and record.level == 3:
                auth_user_match = re.search("(?<=<).+(?=>)", record.message)
                auth_user = auth_user_match.group(0) if auth_user_match else "---unknown---"
                events.append(AslEvent(record.timestamp, EVENT_FAILED_AUTHORISATION, auth_user, record.message))
            # *** sudo ***
            elif record.sender == "sudo" and record.level == 5:
                sudo_message = record.message.strip()
                sudo_message_split = sudo_message.split(" : ", 1)
                if len(sudo_message_split) == 2:
                    sudo_user, sudo_details = sudo_message_split
                else:
                    sudo_user, sudo_details = "---unknown---", ""
                events.append(AslEvent(record.timestamp, EVENT_SUDO, sudo_user, sudo_details))

        f.close()

    # Open and write output
    output = open(output_file_path, "w", encoding="utf-8")
    output.write("Timestamp\tEvent Type\tUser\tOther Details\n")
    for event in sorted(events, key=lambda x: x.timestamp):
        output.write(event.to_tsv_line())
    output.close()
def __main__():

    debug = False
    # Skip manual check
    if len(sys.argv) > 1:
        if sys.argv[1] == 'manualcheck':
            print 'Manual check: skipping'
            exit(0)
        if sys.argv[1] == 'debug':
            print '******* DEBUG MODE ********'
            debug = True

    # Determine logformat based on OS version
    logFormat = 1
    if getOsVersion() < 10:
        logFormat = 0

    if getOsVersion() >= 11:
        #If on 10.11 or higher, skip rest of this script
        return

    # Set path according to logformat
    if logFormat == 0:
        input_dir = '/var/log/performance/'
    else:
        input_dir = '/var/log/servermetricsd/'

    output_file_path = '/usr/local/munki/preflight.d/cache/servermetrics.json'

    out = {}

    if os.path.isdir(input_dir):
        for file_path in os.listdir(input_dir):
            file_path = path.join(input_dir, file_path)
            if debug:
                print("Reading: \"{0}\"".format(file_path))
            try:
                f = open(file_path, "rb")
            except IOError as e:
                if debug:
                    print("Couldn't open file {0} ({1}). Skipping this file".
                          format(file_path, e))
                continue

            try:
                db = ccl_asldb.AslDb(f)
            except ccl_asldb.AslDbError as e:
                if debug:
                    print("Couldn't open file {0} ({1}). Skipping this file".
                          format(file_path, e))
                f.close()
                continue

            timestamp = ''

            for record in db:
                if debug:
                    print "%s %s" % (record.timestamp,
                                     record.message.decode('UTF-8'))
                # print(record.key_value_dict);

                fmt_timestamp = record.timestamp.strftime('%Y-%m-%d %H:%M:%S')
                if fmt_timestamp != timestamp:
                    timestamp = fmt_timestamp
                    out[timestamp] = [0] * 16

                if logFormat == 0:
                    for key in record.key_value_dict:
                        #print "%s %s" % (key, record.key_value_dict[key])
                        # Look up key in index
                        index = FMT_PREV.get(key, -1)
                        if index >= 0:
                            try:
                                val = float(record.key_value_dict[key])
                                if 'CPU' in key:
                                    # correct cpu usage (has to be a fraction)
                                    val = val / 100
                                elif 'Memory' in key:
                                    # correct memory usage
                                    val = val * 4096
                                out[timestamp][index] = val
                            except ValueError as e:
                                continue
                elif logFormat == 1:
                    key_val = [x.strip() for x in record.message.split(':')]
                    index = EVENTS.get(key_val[0], -1)
                    if index >= 0:
                        try:
                            out[timestamp][index] = float(key_val[1])
                        except ValueError as e:
                            continue

            f.close()
    else:
        if debug:
            print "Log directory %s not found" % input_dir

    # Open and write output
    output = open(output_file_path, "w")
    output.write(json.dumps(out))
    output.close()
def __dowork__(work_input, work_output):
    # Unpack input
    if not isinstance(work_input, tuple) or len(work_input) < 1:
        raise ValueError(
            "work_input must be a tuple containing the path for the input database"
        )

    if not isinstance(work_output, tuple) or len(work_output) < 1:
        raise ValueError(
            "work_output must be a tuple containing the path for the output html report"
        )

    input_dir = work_input[0]
    output_file_path = work_output[0]

    # Going to write the power events and order them in memory. Should never be an issue, but if it is, here is where it needs to be fixed.
    power_events = []

    for file_path in os.listdir(input_dir):
        file_path = path.join(input_dir, file_path)
        print("Reading {0}".format(file_path))
        try:
            f = open(file_path, "rb")
        except IOError as e:
            print("Couldn't open file {0} ({1}). Skipping this file".format(
                file_path, e))
            continue

        try:
            db = ccl_asldb.AslDb(f)
        except ccl_asldb.AslDbError as e:
            print("Couldn't open file {0} ({1}). Skipping this file".format(
                file_path, e))
            f.close()
            continue

        for record in db:
            # Reasons to skip
            if record.sender != "powerd":
                continue
            if "com.apple.message.domain" not in record.key_value_dict:
                continue
            if record.key_value_dict["com.apple.message.domain"].lower(
            ) not in ("com.apple.powermanagement.sleep",
                      "com.apple.powermanagement.wake"):
                continue

            # OK, we have a record we want, pull out the charge value using regular expressions (now I have two problems etc.)
            charge_match = re.search(r"\d{1,3}(?=%)", record.message)
            if not charge_match:
                print(
                    "An entry in {0} which looked legit didn't have a charge percentage, skipping..."
                    .format(file_path))
                continue
            power_source_match = re.search("(?<=Using )([A-z]+)",
                                           record.message)
            power_source = power_source_match.group(
                0) if power_source_match else ""

            power_events.append(
                (record.timestamp, charge_match.group(0), power_source))

        f.close()

    # Sort and write out
    out = open(output_file_path, "w", encoding="utf-8")
    for charge_tuple in sorted(power_events, key=lambda x: x[0]):
        out.write("{0:%d/%m/%Y %H:%M:%S},{1},{2}\n".format(
            charge_tuple[0], charge_tuple[1], charge_tuple[2]))

    out.close()