{"id":1358,"date":"2024-01-25T17:36:53","date_gmt":"2024-01-25T16:36:53","guid":{"rendered":"https:\/\/www.symablog.de\/blog\/?p=1358"},"modified":"2024-01-25T17:37:00","modified_gmt":"2024-01-25T16:37:00","slug":"python-skript-zur-ueberwachung-einer-logdatei","status":"publish","type":"post","link":"https:\/\/www.symablog.de\/blog\/python-skript-zur-ueberwachung-einer-logdatei\/","title":{"rendered":"Python Skript zur \u00dcberwachung einer Logdatei"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">log_scriptmon.ini\n[constant]\nmonitored_file = \/home\/pi\/logmonitor\/test_events.log\n\ncounter_file = \/home\/pi\/logmonitor\/log_scriptmon.counter\nscript_logfile = \/home\/pi\/logmonitor\/log_scriptmon.log\nmax_run_diff = 600\n\n[logfile]\n# you have to prefer to combine search pattern as (MAJOR|CRITICAL|FATAL) instaed# to define more pattern in single lines\n# example  pattern1 = (MAJOR|CRI.*CAL|FATAL)\npattern1 = IN.O\npattern2 = CRITI.+\npattern3 = FATAL<\/pre>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">log_scriptmon.py\n#!\/usr\/bin\/env python\n# -*- coding: utf-8 -*-\n#    log_scriptmon.py\n#    Skript zum Monitoring von LOG-Dateien\n#\n\nimport os\nimport sys\nimport hashlib\nimport re\nimport time\nimport configparser\n\n\ndef read_configfile(fullfilepath):\n    configuration = configparser.ConfigParser()\n    configuration.read(fullfilepath)\n    return configuration\n\ndef file_exist(fullfilepath, error_return = 0):\n    if not os.path.isfile(fullfilepath):\n        if error_return:\n            print(f\"ERROR: file {fullfilepath} does not exist. EXIT {error_return}\")\n            sys.exit(error_return)  # Beende das Programm mit einem Fehlercode\n        else:\n            print(f\"Situation G - Die Datei {fullfilepath} existiert nicht.\")\n            return False\n    return True\n\ndef datei_groesse(fullfilepath):\n    if os.path.isfile(fullfilepath):\n        groesse = os.path.getsize(fullfilepath)\n        return int(groesse)\n    else:\n        return -1  # Fehlercode, wenn die Datei nicht existiert\n\ndef get_basename():\n    skript_name = sys.argv[0]\n    dummy = skript_name.split(\"\/\")\n    x = len(dummy) - 1\n    skript_name = dummy[x]\n    dummy = skript_name.split(\".\")\n    skript_name = dummy[0]\n    # print(skript_name)\n    return skript_name\n\ndef linecounter(fullfilepath):\n    with open(fullfilepath, 'r') as file:\n        anzahl_zeilen = sum(1 for zeile in file)\n    return int(anzahl_zeilen)\n\ndef calc_checksum(fullfilepath, algorithm=\"sha256\"):\n    # \u00d6ffne die Datei im Bin\u00e4rmodus und lese den Inhalt\n    with open(fullfilepath, 'rb') as datei:\n        # W\u00e4hle den gew\u00fcnschten Hash-Algorithmus\n        hash_algorithm = hashlib.new(algorithm)\n        # Lese die Datei blockweise und aktualisiere den Hash\n        blockgroesse = 4096  # Zum Beispiel 4 KB pro Block\n        for block in iter(lambda: datei.read(blockgroesse), b''):\n            hash_algorithm.update(block)\n    # Gib die hexadezimale Darstellung der Checksumme zur\u00fcck\n    checksum = hash_algorithm.hexdigest()\n    return checksum\n\ndef write_counterfile(fullfilepath,counterarray):\n    with open(fullfilepath, 'w') as file:\n        for element in counterarray:\n            file.write(str(element) + '\\n')\n    return\n\ndef read_counterfile(fullfilepath):\n    with open(fullfilepath, 'r') as file:\n        counterarray = [line.rstrip() for line in file.readlines()]\n    return counterarray\n\ndef search_in_file(search_pattern, fullfilepath,start_seek = 0):\n    with open(fullfilepath, 'r') as file:\n        file.seek(start_seek)\n        for line in file:\n            for pattern in search_pattern:\n                if re.search(pattern, line.strip(), re.IGNORECASE):\n                    print(f'MATCH:{line.strip()}')\n    return\n\ndef log(logtxt, fullfilepath):\n    with open(fullfilepath, 'a') as file:\n        logtxt = logtxt.strip()\n        file.write(str(logtxt) + '\\n')\n    return\n\nif __name__ == \"__main__\":\n    ################################################\n    # MAIN\n    ################################################\n\n    # READ THE INI-\/CONFIGFILE\n    basename    = get_basename()                   # scriptname\n    scriptdir   = '\/home\/pi\/logmonitor\/'           # scriptdir\n    configfile  = scriptdir + basename + \".ini\"    # ini-file\n    file_exist(configfile,2)                       # check file exists, exit 2\n    cfg = read_configfile(configfile)              # read ini-file\/config into cfg structure\n\n    monitoredfile = cfg.get(\"constant\", \"monitored_file\") # monitored logfile\n    counterfile = cfg.get(\"constant\", \"counter_file\")     # temporary data\n    logfile = cfg.get(\"constant\", \"script_logfile\")       # logfile of this script\n    max_run_diff = int(cfg.get(\"constant\", \"max_run_diff\"))   # max Zeitdiff.zw.2 L\u00e4ufen\n\n    # SEARCH PATTERN\n    search_pattern = []\n    for i in range(1, 9):\n        pattern_key = f\"pattern{i}\"\n        if cfg.has_option(\"logfile\", pattern_key):\n            search_pattern.append(cfg.get(\"logfile\", pattern_key))\n        else:\n            break  # ende der schleife, wenn ein pattern nicht mehr gefunden wird\n\n    # Standard Suchpattern, wenn kein pattern gefunden wurden\n    if not search_pattern:\n        search_pattern.append(\".*\")\n\n\n    print(\"start ... \")\n    print(f'Cache         : {counterfile}')\n    print(f'Search Pattern: {search_pattern}')\n    # print(\" \".join(map(str, search_pattern)))\n\n    file_exist(monitoredfile,1)  # existiert logfile nicht, exit 1\n    print(f'Monitor on      {monitoredfile}')\n\n    if file_exist(counterfile,0):\n        counterarray_last = read_counterfile(counterfile)\n    else:\n        counterarray_last = [\"0\", \"0\", \"0\", \"0\"]\n\n    checksum_last = counterarray_last[0]\n    filesize_last = int(counterarray_last[1])\n    anzlines_last = int(counterarray_last[2])\n    lastrund_last = int(counterarray_last[3])\n\n    checksum_curr = calc_checksum(monitoredfile) # C1 current checksum\n    filesize_curr = datei_groesse(monitoredfile) # C2 filesize\n    anzlines_curr = linecounter(monitoredfile)   # C3 linecount\n    lastrund_curr = int(time.time())       # C4 last rundate\n\n    run_diff = lastrund_curr - lastrund_last\n    write_counterfile(counterfile,[checksum_curr, filesize_curr, anzlines_curr, lastrund_curr])\n\n    print('---------------------')\n    print(f'checksum_last: {checksum_last}')\n    print(f'filesize_last: {filesize_last} Bytes')\n    print(f'anzlines_last: {anzlines_last}')\n    print(f'lastrund_last: {lastrund_last}')\n    print('---------------------')\n    print(f'checksum_curr: {checksum_curr}')\n    print(f'filesize_curr: {filesize_curr} Bytes')\n    print(f'anzlines_curr: {anzlines_curr}')\n    print(f'lastrund_curr: {lastrund_curr}')\n    print('---------------------')\n\n    # Decision Section\n    if (run_diff > max_run_diff):\n        print(f\"Situation A - first or new start with time difference over {max_run_diff} s, set seek to current file size and wait for next intervall.\")\n    elif (checksum_last == checksum_curr):\n        print(\"Situation B - old and current file identical, nothing to do\")\n    elif (checksum_last == \"0\") and (checksum_last != checksum_curr)  \\\n        and (filesize_last == 0) and (filesize_last &lt; filesize_curr):\n        print(\"Situation C - new file, read from start\")\n        search_in_file(search_pattern, monitoredfile, 0)\n    elif (anzlines_last &lt; anzlines_curr):\n        print(\"Situation D - normal growing file, read from last position\")\n        search_in_file(search_pattern, monitoredfile, filesize_last)\n    elif (anzlines_last > anzlines_curr) and (filesize_curr == 0):\n        print(\"Situation E - logrotate, new file empty - nothing to do\")\n    elif (anzlines_last > anzlines_curr):\n        print(\"Situation F - logrotate, read file from start\")\n        search_in_file(search_pattern, monitoredfile, 0)\n\n    print(\" ... ende \")<\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>log_scriptmon.ini [constant] monitored_file = \/home\/pi\/logmonitor\/test_events.log counter_file = \/home\/pi\/logmonitor\/log_scriptmon.counter script_logfile = \/home\/pi\/logmonitor\/log_scriptmon.log max_run_diff = 600 [logfile] # you have to prefer to combine search pattern as (MAJOR|CRITICAL|FATAL) instaed# to define more pattern in single lines # example pattern1 = (MAJOR|CRI.*CAL|FATAL) pattern1 &hellip; <a class=\"more-link\" href=\"https:\/\/www.symablog.de\/blog\/python-skript-zur-ueberwachung-einer-logdatei\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[1],"tags":[238],"class_list":["post-1358","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-python"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p37Rzq-lU","_links":{"self":[{"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/posts\/1358"}],"collection":[{"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/comments?post=1358"}],"version-history":[{"count":1,"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/posts\/1358\/revisions"}],"predecessor-version":[{"id":1359,"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/posts\/1358\/revisions\/1359"}],"wp:attachment":[{"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/media?parent=1358"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/categories?post=1358"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.symablog.de\/blog\/wp-json\/wp\/v2\/tags?post=1358"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}