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()