Advertisement
skybetik

OLT-zte send_telegram

Jun 8th, 2025 (edited)
1,038
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 32.14 KB | Fixit | 0 0
  1. import re
  2. import os
  3. import requests
  4. import time
  5. from datetime import datetime, date
  6. from collections import defaultdict
  7. import configparser
  8. import logging
  9. import schedule
  10. import threading
  11. import sys
  12.  
  13. # Налаштування логів
  14. LOG_FILE_PATH = '/opt/olt_monitor/olt_monitor.log'
  15. LAN_EVENTS_LOG = '/opt/olt_monitor/lan_events.log'  
  16. SENT_MESSAGES_FILE = '/opt/olt_monitor/sent_messages.txt'
  17. LAST_RESET_FILE = '/opt/olt_monitor/last_log_reset.txt'
  18. LAST_ACTIVATION_FILE = '/opt/olt_monitor/last_activation.txt'
  19.  
  20. # Створення lan_events.log при старті, якщо не існує
  21. if not os.path.exists(LAN_EVENTS_LOG):
  22.     try:
  23.         with open(LAN_EVENTS_LOG, 'w', encoding='utf-8') as f:
  24.             f.write('')
  25.         logging.info(f"Створено файл {LAN_EVENTS_LOG}")
  26.     except Exception as e:
  27.         logging.error(f"Помилка створення {LAN_EVENTS_LOG}: {e}")
  28.         raise
  29.  
  30. # Налаштування логгера для lan_events.log
  31. lan_logger = logging.getLogger('lan_events')
  32. lan_handler = logging.FileHandler(LAN_EVENTS_LOG, encoding='utf-8')
  33. lan_handler.setFormatter(logging.Formatter('%(asctime)s [%(levelname)s] %(message)s'))
  34. lan_logger.addHandler(lan_handler)
  35. lan_logger.setLevel(logging.INFO)
  36.  
  37. # Змінна для відстеження часу попереджень
  38. last_size_warning = {}
  39.  
  40. # Налаштування логування в консоль і olt_monitor.log
  41. logging.basicConfig(
  42.     level=logging.INFO,
  43.     format='%(asctime)s [%(levelname)s] %(message)s',
  44.     handlers=[logging.StreamHandler(), logging.FileHandler(LOG_FILE_PATH, encoding='utf-8')]
  45. )
  46.  
  47. # Завантаження конфігурації
  48. config = configparser.ConfigParser()
  49. try:
  50.     config.read('/opt/olt_monitor/config.ini')
  51. except Exception as e:
  52.     logging.error(f"Помилка читання config.ini: {e}")
  53.     raise
  54.  
  55. # Конфігурація
  56. try:
  57.     TELEGRAM_BOT_TOKEN = config.get('Settings', 'TelegramBotToken')
  58.     TELEGRAM_CHAT_IDS = config.get('Settings', 'TelegramChatIDs').split(',')
  59.     REPORT_TIME = config.get('Settings', 'ReportTime', fallback='06:00')
  60.     LOG_FILE = config.get('Settings', 'LogFile', fallback='/var/log/zte.log')
  61.     LAST_POSITION_FILE = config.get('Settings', 'LastPositionFile', fallback='/opt/olt_monitor/last_position.txt')
  62.     CHECK_INTERVAL = config.getint('Settings', 'CheckInterval', fallback=5)
  63. except Exception as e:
  64.     logging.error(f"Помилка парсингу конфігурації: {e}")
  65.     raise
  66.  
  67. # Завантажуємо відправлені повідомлення
  68. def load_sent_messages():
  69.     if not os.path.exists(SENT_MESSAGES_FILE):
  70.         return set()
  71.     try:
  72.         with open(SENT_MESSAGES_FILE, 'r', encoding='utf-8') as f:
  73.             return set(line.strip() for line in f if line.strip())
  74.     except Exception as e:
  75.         logging.error(f"Помилка читання файлу {SENT_MESSAGES_FILE}: {e}")
  76.         return set()
  77.  
  78. # Зберігаємо нове повідомлення
  79. def save_sent_message(msg, sent_messages):
  80.     try:
  81.         with open(SENT_MESSAGES_FILE, 'a', encoding='utf-8') as f:
  82.             f.write(msg + '\n')
  83.         sent_messages.add(msg)
  84.     except Exception as e:
  85.         logging.error(f"Помилка збереження повідомлення в {SENT_MESSAGES_FILE}: {e}")
  86.  
  87. # Перевірка часу останнього повідомлення про активацію
  88. def can_send_activation():
  89.     if not os.path.exists(LAST_ACTIVATION_FILE):
  90.         return True
  91.     try:
  92.         with open(LAST_ACTIVATION_FILE, 'r') as f:
  93.             last_time = float(f.read().strip())
  94.         return (time.time() - last_time) > 300  # 5 хвилин
  95.     except Exception as e:
  96.         logging.error(f"Помилка читання {LAST_ACTIVATION_FILE}: {e}")
  97.         return True
  98.  
  99. # Зберігаємо час активації
  100. def save_activation_time():
  101.     try:
  102.         with open(LAST_ACTIVATION_FILE, 'w') as f:
  103.             f.write(str(time.time()))
  104.     except Exception as e:
  105.         logging.error(f"Помилка збереження {LAST_ACTIVATION_FILE}: {e}")
  106.  
  107. # Відправка повідомлення в Telegram
  108. def send_telegram(msg, sent_messages):
  109.     if msg in sent_messages:
  110.         logging.warning(f"Повідомлення вже відправлено, пропущено: {msg}")
  111.         return
  112.     url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
  113.     for chat_id in TELEGRAM_CHAT_IDS:
  114.         try:
  115.             response = requests.post(url, data={"chat_id": chat_id.strip(), "text": msg}, timeout=10)
  116.             response.raise_for_status()
  117.             logging.info(f"Повідомлення успішно відправлено в Telegram (chat_id: {chat_id}): {msg}")
  118.             save_sent_message(msg, sent_messages)
  119.         except requests.RequestException as e:
  120.             error_msg = f"Помилка відправки в Telegram для chat_id {chat_id}: {e}, response: {response.text if 'response' in locals() else 'немає відповіді'}"
  121.             logging.error(error_msg)
  122.             critical_msg = f"⚠️ Критична помилка в olt_monitor.py:\n{error_msg}"
  123.             if critical_msg not in sent_messages:
  124.                 try:
  125.                     for critical_chat_id in TELEGRAM_CHAT_IDS:
  126.                         requests.post(url, data={"chat_id": critical_chat_id.strip(), "text": critical_msg}, timeout=10)
  127.                     save_sent_message(critical_msg, sent_messages)
  128.                 except Exception as critical_e:
  129.                     logging.error(f"Не вдалося відправити критичну помилку в Telegram: {critical_e}")
  130.  
  131. # Відправка звіту про події LAN у Telegram (з очищенням lan_events.log)
  132. def send_lan_summary_to_telegram(sent_messages):
  133.     logging.info("Початок створення звіту про події LAN")
  134.     summary = defaultdict(lambda: {'los': 0, 'restore': 0})
  135.     today = str(date.today())
  136.  
  137.     try:
  138.         if not os.path.exists(LAN_EVENTS_LOG):
  139.             logging.info(f"Файл {LAN_EVENTS_LOG} не існує")
  140.         else:
  141.             with open(LAN_EVENTS_LOG, 'r', encoding='utf-8') as f:
  142.                 lines_processed = 0
  143.                 current_entry = []
  144.                 for line in f:
  145.                     line = line.strip()
  146.                     if not line:
  147.                         continue
  148.                     # Начало новой записи определяется по временной метке (YYYY-MM-DD HH:MM:SS, с опциональными миллисекундами)
  149.                     if re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:,\d+)?", line):
  150.                         if current_entry:  # Обрабатываем предыдущую запись
  151.                             lines_processed += 1
  152.                             entry_text = '\n'.join(current_entry)
  153.                             logging.debug(f"Обробка запису у {LAN_EVENTS_LOG}: {entry_text}")
  154.                             # Извлекаем порт, OLT и номер ONU
  155.                             port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  156.                             olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  157.                             onu_match = re.search(r"ONU №(\d+)", entry_text)
  158.                             if port_match and olt_match and onu_match:
  159.                                 port = port_match.group(1)
  160.                                 olt_name = olt_match.group(1)
  161.                                 olt_ip = olt_match.group(2)
  162.                                 onu_number = onu_match.group(1)
  163.                                 key = (port, olt_name, olt_ip, onu_number)
  164.                                 if "LAN LOS знайдено" in entry_text:
  165.                                     summary[key]['los'] += 1
  166.                                     logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  167.                                 elif "LAN LOS Restore знайдено" in entry_text:
  168.                                     summary[key]['restore'] += 1
  169.                                     logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  170.                             else:
  171.                                 logging.debug(f"Запис не відповідає формату port/olt/onu: {entry_text}")
  172.                             current_entry = []
  173.                         current_entry.append(line)
  174.                     else:
  175.                         current_entry.append(line)
  176.  
  177.                 # Обработка последней записи
  178.                 if current_entry:
  179.                     lines_processed += 1
  180.                     entry_text = '\n'.join(current_entry)
  181.                     logging.debug(f"Обробка останнього запису у {LAN_EVENTS_LOG}: {entry_text}")
  182.                     port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  183.                     olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  184.                     onu_match = re.search(r"ONU №(\d+)", entry_text)
  185.                     if port_match and olt_match and onu_match:
  186.                         port = port_match.group(1)
  187.                         olt_name = olt_match.group(1)
  188.                         olt_ip = olt_match.group(2)
  189.                         onu_number = onu_match.group(1)
  190.                         key = (port, olt_name, olt_ip, onu_number)
  191.                         if "LAN LOS знайдено" in entry_text:
  192.                             summary[key]['los'] += 1
  193.                             logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  194.                         elif "LAN LOS Restore знайдено" in entry_text:
  195.                             summary[key]['restore'] += 1
  196.                             logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  197.                     else:
  198.                         logging.debug(f"Останній запис не відповідає формату: {entry_text}")
  199.  
  200.                 logging.info(f"Оброблено {lines_processed} записів у {LAN_EVENTS_LOG}")
  201.  
  202.         # Формирование отчета
  203.         if summary:
  204.             msg = f"📊 Звіт подій LAN за {today}:\n\n"
  205.             for (port, olt_name, olt_ip, onu_number), counts in sorted(summary.items()):
  206.                 total = counts['los'] + counts['restore']
  207.                 msg += (
  208.                     f"🔢 ONU №{onu_number}\n"
  209.                     f"📍 Порт: {port}\n"
  210.                     f"🖥 OLT: {olt_name} ({olt_ip})\n"
  211.                     f"🔴 Втрата LAN: {counts['los']}\n"
  212.                     f"🟢 LAN відновлено: {counts['restore']}\n"
  213.                     f"🔢 Загалом: {total}\n\n"
  214.                 )
  215.         else:
  216.             msg = f"📊 Звіт подій LAN за {today}:\n\n⚠️ Подій LAN LOS або Restore не знайдено"
  217.  
  218.         send_telegram(msg.strip(), sent_messages)
  219.         logging.info("Звіт про події LAN відправлено в Telegram")
  220.  
  221.         # Очищаем lan_events.log после отправки
  222.         try:
  223.             with open(LAN_EVENTS_LOG, 'w', encoding='utf-8') as f:
  224.                 f.write('')
  225.             logging.info(f"Файл {LAN_EVENTS_LOG} очищено після відправки звіту")
  226.         except Exception as e:
  227.             logging.error(f"Помилка очищення {LAN_EVENTS_LOG}: {e}")
  228.  
  229.     except Exception as e:
  230.         logging.error(f"Помилка створення звіту LAN: {e}")
  231.  
  232. # Ручна перевірка звіту без очищення lan_events.log
  233. def manual_lan_summary():
  234.     sent_messages = load_sent_messages()
  235.     logging.info("Початок ручної перевірки звіту про події LAN")
  236.     summary = defaultdict(lambda: {'los': 0, 'restore': 0})
  237.     today = str(date.today())
  238.  
  239.     try:
  240.         if not os.path.exists(LAN_EVENTS_LOG):
  241.             logging.info(f"Файл {LAN_EVENTS_LOG} не існує")
  242.         else:
  243.             with open(LAN_EVENTS_LOG, 'r', encoding='utf-8') as f:
  244.                 lines_processed = 0
  245.                 current_entry = []
  246.                 for line in f:
  247.                     line = line.strip()
  248.                     if not line:
  249.                         continue
  250.                     # Начало новой записи определяется по временной метке
  251.                     if re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:,\d+)?", line):
  252.                         if current_entry:  # Обрабатываем предыдущую запись
  253.                             lines_processed += 1
  254.                             entry_text = '\n'.join(current_entry)
  255.                             logging.debug(f"Обробка запису у {LAN_EVENTS_LOG}: {entry_text}")
  256.                             port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  257.                             olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  258.                             onu_match = re.search(r"ONU №(\d+)", entry_text)
  259.                             if port_match and olt_match and onu_match:
  260.                                 port = port_match.group(1)
  261.                                 olt_name = olt_match.group(1)
  262.                                 olt_ip = olt_match.group(2)
  263.                                 onu_number = onu_match.group(1)
  264.                                 key = (port, olt_name, olt_ip, onu_number)
  265.                                 if "LAN LOS знайдено" in entry_text:
  266.                                     summary[key]['los'] += 1
  267.                                     logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  268.                                 elif "LAN LOS Restore знайдено" in entry_text:
  269.                                     summary[key]['restore'] += 1
  270.                                     logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  271.                             else:
  272.                                 logging.debug(f"Запис не відповідає формату port/olt/onu: {entry_text}")
  273.                             current_entry = []
  274.                         current_entry.append(line)
  275.                     else:
  276.                         current_entry.append(line)
  277.  
  278.                 # Обработка последней записи
  279.                 if current_entry:
  280.                     lines_processed += 1
  281.                     entry_text = '\n'.join(current_entry)
  282.                     logging.debug(f"Обробка останнього запису у {LAN_EVENTS_LOG}: {entry_text}")
  283.                     port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  284.                     olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  285.                     onu_match = re.search(r"ONU №(\d+)", entry_text)
  286.                     if port_match and olt_match and onu_match:
  287.                         port = port_match.group(1)
  288.                         olt_name = olt_match.group(1)
  289.                         olt_ip = olt_match.group(2)
  290.                         onu_number = onu_match.group(1)
  291.                         key = (port, olt_name, olt_ip, onu_number)
  292.                         if "LAN LOS знайдено" in entry_text:
  293.                             summary[key]['los'] += 1
  294.                             logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  295.                         elif "LAN LOS Restore знайдено" in entry_text:
  296.                             summary[key]['restore'] += 1
  297.                             logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  298.                     else:
  299.                         logging.debug(f"Останній запис не відповідає формату: {entry_text}")
  300.  
  301.                 logging.info(f"Оброблено {lines_processed} записів у {LAN_EVENTS_LOG}")
  302.  
  303.         # Формирование отчета
  304.         if summary:
  305.             msg = f"📊 Ручний звіт подій LAN за {today}:\n\n"
  306.             for (port, olt_name, olt_ip, onu_number), counts in sorted(summary.items()):
  307.                 total = counts['los'] + counts['restore']
  308.                 msg += (
  309.                     f"🔢 ONU №{onu_number}\n"
  310.                     f"📍 Порт: {port}\n"
  311.                     f"🖥 OLT: {olt_name} ({olt_ip})\n"
  312.                     f"🔴 Втрата LAN: {counts['los']}\n"
  313.                     f"🟢 LAN відновлено: {counts['restore']}\n"
  314.                     f"🔢 Загалом: {total}\n\n"
  315.                 )
  316.         else:
  317.             msg = f"📊 Ручний звіт подій LAN за {today}:\n\n⚠️ Подій LAN LOS або Restore не знайдено"
  318.  
  319.         send_telegram(msg.strip(), sent_messages)
  320.         logging.info("Ручний звіт про події LAN відправлено в Telegram")
  321.  
  322.     except Exception as e:
  323.         logging.error(f"Помилка створення ручного звіту LAN: {e}")
  324.  
  325. # Налаштування логування та перезапису файлів
  326. def setup_logging_and_messages():
  327.     try:
  328.         logging.info("Початок налаштування логування")
  329.         last_reset_date = None
  330.         if os.path.exists(LAST_RESET_FILE):
  331.             with open(LAST_RESET_FILE, 'r') as f:
  332.                 last_reset_date = f.read().strip()
  333.             logging.info(f"Прочитано дату останнього перезапису: {last_reset_date}")
  334.         else:
  335.             logging.info(f"Файл {LAST_RESET_FILE} не існує, буде створено")
  336.         today = str(date.today())
  337.         logging.info(f"Поточна дата: {today}")
  338.  
  339.         # Перевірка розміру логу
  340.         log_size_mb = os.path.getsize(LOG_FILE_PATH) / (1024 * 1024) if os.path.exists(LOG_FILE_PATH) else 0
  341.         logging.info("Розмір логу: " + str(round(log_size_mb, 2)) + " МБ")
  342.  
  343.         if last_reset_date != today:
  344.             sent_messages = load_sent_messages()
  345.             try:
  346.                 logging.basicConfig(
  347.                     filename=LOG_FILE_PATH,
  348.                     level=logging.INFO,
  349.                     format='%(asctime)s [%(levelname)s] %(message)s',
  350.                     filemode='w',
  351.                     force=True
  352.                 )
  353.                 logging.info(f"Лог перезаписано для нової доби (size={log_size_mb:.2f} МБ)")
  354.                 with open(SENT_MESSAGES_FILE, 'w', encoding='utf-8') as f:
  355.                     f.write('')
  356.                 logging.info("Файл sent_messages.txt перезаписано для нової доби")
  357.                 with open(LAST_RESET_FILE, 'w') as f:
  358.                     f.write(today)
  359.                 logging.info(f"Оновлено {LAST_RESET_FILE} з датою {today}")
  360.             except Exception as e:
  361.                 logging.error(f"Помилка при перезаписі файлів: {e}")
  362.                 raise
  363.         else:
  364.             logging.basicConfig(
  365.                 filename=LOG_FILE_PATH,
  366.                 level=logging.INFO,
  367.                 format='%(asctime)s [%(levelname)s] %(message)s',
  368.                 filemode='a',
  369.                 force=True
  370.             )
  371.             logging.info("Дата не змінилася, використовується режим додавання")
  372.     except Exception as e:
  373.         logging.error(f"Критична помилка налаштування: {e}")
  374.         print(f"Критична помилка налаштування: {e}")
  375.         raise
  376.  
  377. # Перевірка розміру файлів
  378. def check_file_size(file_path, file_name, max_size_mb=10):
  379.     try:
  380.         if os.path.exists(file_path):
  381.             size_mb = os.path.getsize(file_path) / (1024 * 1024)
  382.             if size_mb > max_size_mb:
  383.                 current_time = time.time()
  384.                 last_warning_time = last_size_warning.get(file_name, 0)
  385.                 if current_time - last_warning_time > 600:
  386.                     logging.warning(f"Розмір {file_name} перевищує {max_size_mb} МБ: {size_mb:.2f} МБ")
  387.                     last_size_warning[file_name] = current_time
  388.     except Exception as e:
  389.         logging.error(f"Помилка перевірки розміру {file_name}: {e}")
  390.  
  391. # Глобальні змінні
  392. current_interface = None
  393. current_olt_name = None
  394. current_olt_ip = None
  395. current_description = None
  396. onu_add_buffer = defaultdict(dict)
  397.  
  398. # Завантажуємо останню позицію
  399. def load_last_position():
  400.     if not os.path.exists(LAST_POSITION_FILE):
  401.         return 0, os.stat(LOG_FILE).st_ino if os.path.exists(LOG_FILE) else 0
  402.     try:
  403.         with open(LAST_POSITION_FILE, 'r') as f:
  404.             pos = f.read().strip()
  405.             if pos == '':
  406.                 return 0, os.stat(LOG_FILE).st_ino
  407.             return int(pos), os.stat(LOG_FILE).st_ino
  408.     except Exception as e:
  409.         logging.error(f"Помилка читання позиції з {LAST_POSITION_FILE}: {e}")
  410.         return 0, os.stat(LOG_FILE).st_ino if os.path.exists(LOG_FILE) else 0
  411.  
  412. # Зберігаємо останню позицію
  413. def save_last_position(position):
  414.     try:
  415.         with open(LAST_POSITION_FILE, 'w') as f:
  416.             f.write(str(position))
  417.     except Exception as e:
  418.         logging.error(f"Помилка збереження позиції в {LAST_POSITION_FILE}: {e}")
  419.  
  420. # Парсинг логу
  421. def parse_log(file_obj, start_pos, sent_messages):
  422.     global current_interface, current_olt_name, current_olt_ip, current_description
  423.     try:
  424.         file_obj.seek(start_pos)
  425.         file_size = os.path.getsize(LOG_FILE)
  426.         if start_pos > file_size:
  427.             logging.warning(f"start_pos ({start_pos}) більше file_size ({file_size}), скидаємо на 0")
  428.             start_pos = 0
  429.             file_obj.seek(0)
  430.         lines = file_obj.readlines()
  431.         end_pos = file_obj.tell()
  432.     except Exception as e:
  433.         logging.error(f"Помилка читання файлу логу: {e}")
  434.         return start_pos
  435.  
  436.     for line in lines:
  437.         line = line.strip().replace('#012', '').replace('#015', '')
  438.         if not line:
  439.             continue
  440.  
  441.         # Витягуємо ім'я та IP OLT
  442.         m_olt = re.search(r"\[(\S+) (\d+\.\d+\.\d+\.\d+)\]", line)
  443.         if m_olt:
  444.             current_olt_name = m_olt.group(1)
  445.             current_olt_ip = m_olt.group(2)
  446.  
  447.         # Витягуємо час
  448.         time_match = re.match(r"^\w+\s+\d+\s+(\d{2}:\d{2}:\d{2})", line)
  449.         time_str = time_match.group(1) if time_match else datetime.now().strftime("%H:%M:%S")
  450.         try:
  451.             event_time = datetime.strptime(time_str, "%H:%M:%S")
  452.             event_time = event_time.replace(year=datetime.now().year, month=datetime.now().month, day=datetime.now().day)
  453.         except ValueError as e:
  454.             logging.error(f"Помилка формату часу {time_str}: {e}")
  455.             continue
  456.  
  457.         # Перевіряємо OLT перед обробкою подій
  458.         if not current_olt_name or not current_olt_ip:
  459.             logging.warning(f"Пропущено подію через відсутність OLT: {line}")
  460.             continue
  461.  
  462.         # Витягуємо інтерфейс
  463.         m_intf = re.search(r"(?:interface\s+)(gpon-olt_\d+/\d+/\d+|gpon-onu_\d+/\d+/\d+:\d+)", line, re.IGNORECASE)
  464.         if m_intf:
  465.             current_interface = m_intf.group(1)
  466.             continue
  467.  
  468.         # Витягуємо description
  469.         m_desc = re.search(r"description\s+(\S+)", line, re.IGNORECASE)
  470.         if m_desc:
  471.             current_description = m_desc.group(1)
  472.             for key, data in list(onu_add_buffer.items()):
  473.                 if key[2] == current_interface or key[2].replace("gpon-olt_", "gpon-onu_") + f":{key[3]}" == current_interface:
  474.                     data['description'] = current_description
  475.                     desc_str = f"\n🏷 Опис: {data['description']}" if data['description'] else ""
  476.                     msg = (
  477.                         f"✅ ONU додано\n\n"
  478.                         f"🕒 Час: {data['time_str']}\n"
  479.                         f"🔢 ONU №{data['onu_number']}\n"
  480.                         f"📍 Порт: {data['onu_iface']}{desc_str}\n"
  481.                         f"🖥 OLT: {key[0]} ({key[1]})"
  482.                     )
  483.                     send_telegram(msg, sent_messages)
  484.                     del onu_add_buffer[key]
  485.             continue
  486.  
  487.         # LAN LOS Alarm
  488.         m_lan_los = re.search(r"(?:GponRm notify:.*)?<gpon-onu_\d+/\d+/\d+:\d+>\s*SubType:\d+\s*Pos:\d+\s*ONU Uni lan los\. alarm", line, re.IGNORECASE)
  489.         if m_lan_los:
  490.             m_iface_num = re.search(r"<(gpon-onu_\d+/\d+/\d+):(\d+)>", line)
  491.             if m_iface_num:
  492.                 onu_iface = m_iface_num.group(1)
  493.                 onu_num = m_iface_num.group(2)
  494.                 desc_str = f"\n🏷 Опис: {current_description}" if current_description and current_interface == onu_iface else ""
  495.                 msg = (
  496.                     f"🔴 Втрата LAN-з'єднання\n\n"
  497.                     f"🕒 Час: {time_str}\n"
  498.                     f"🔢 ONU №{onu_num}\n"
  499.                     f"📍 Порт: {onu_iface}{desc_str}\n"
  500.                     f"🖥 OLT: {current_olt_name} ({current_olt_ip})"
  501.                 )
  502.                 lan_logger.warning(f"LAN LOS знайдено: {msg}")  # Записываем только в lan_events.log
  503.                 current_description = None
  504.             continue
  505.  
  506.         # LAN LOS Restore
  507.         m_lan_restore = re.search(r"(?:GponRm notify:.*)?<gpon-onu_\d+/\d+/\d+:\d+>\s*SubType:\d+\s*Pos:\d+\s*ONU Uni lan los\. restore", line, re.IGNORECASE)
  508.         if m_lan_restore:
  509.             m_iface_num = re.search(r"<(gpon-onu_\d+/\d+/\d+):(\d+)>", line)
  510.             if m_iface_num:
  511.                 onu_iface = m_iface_num.group(1)
  512.                 onu_num = m_iface_num.group(2)
  513.                 desc_str = f"\n🏷 Опис: {current_description}" if current_description and current_interface == onu_iface else ""
  514.                 msg = (
  515.                     f"🟢 LAN-з'єднання відновлено\n\n"
  516.                     f"🕒 Час: {time_str}\n"
  517.                     f"🔢 ONU №{onu_num}\n"
  518.                     f"📍 Порт: {onu_iface}{desc_str}\n"
  519.                     f"🖥 OLT: {current_olt_name} ({current_olt_ip})"
  520.                 )
  521.                 lan_logger.warning(f"LAN LOS Restore знайдено: {msg}")  # Записываем только в lan_events.log
  522.                 current_description = None
  523.             continue
  524.  
  525.         # Видалення ONU
  526.         m_no_onu = re.search(r"\b(?:no\s+onu|ont delete)\s+(\d+)(?:\s+\d+)?|ont delete\s+(\d+/\d+/\d+)\s+(\d+)", line, re.IGNORECASE)
  527.         if m_no_onu:
  528.             onu_iface = m_no_onu.group(2) or current_interface or "невідомий"
  529.             onu_number = m_no_onu.group(1) or m_no_onu.group(3)
  530.             desc_str = f"\n🏷 Опис: {current_description}" if current_description and current_interface == onu_iface else ""
  531.             msg = (
  532.                 f"❌ ONU видалено\n\n"
  533.                 f"🕒 Час: {time_str}\n"
  534.                 f"🔢 ONU №{onu_number}\n"
  535.                 f"📍 Порт: {onu_iface}{desc_str}\n"
  536.                 f"🖥 OLT: {current_olt_name} ({current_olt_ip})"
  537.             )
  538.             send_telegram(msg, sent_messages)
  539.             current_description = None
  540.             key = (current_olt_name, current_olt_ip, onu_iface, onu_number)
  541.             if key in onu_add_buffer:
  542.                 del onu_add_buffer[key]
  543.             continue
  544.  
  545.         # Додавання ONU
  546.         m_add_onu = re.search(r"\b(?:onu\s+add|ont add)\s+(\d+)\s+(\d+)|ont add\s+(\d+/\d+/\d+)\s+(\d+)|onu\s+(\d+)\s+type\s+\S+\s+sn\s+\S+", line, re.IGNORECASE)
  547.         if m_add_onu:
  548.             onu_iface = m_add_onu.group(1) or m_add_onu.group(3) or current_interface or "невідомий"
  549.             onu_number = m_add_onu.group(2) or m_add_onu.group(4) or m_add_onu.group(5)
  550.             key = (current_olt_name, current_olt_ip, onu_iface, onu_number)
  551.             onu_add_buffer[key] = {
  552.                 'time_str': time_str,
  553.                 'onu_iface': onu_iface,
  554.                 'onu_number': onu_number,
  555.                 'description': current_description if current_interface == onu_iface else None,
  556.                 'timestamp': datetime.now()
  557.             }
  558.             current_description = None
  559.             continue
  560.  
  561.     # Обробка відкладених подій ONU
  562.     current_time = datetime.now()
  563.     for key, data in list(onu_add_buffer.items()):
  564.         if (current_time - data['timestamp']).seconds >= 5:
  565.             desc_str = f"\n🏷 Опис: {data['description']}" if data['description'] else ""
  566.             msg = (
  567.                 f"✅ ONU додано\n\n"
  568.                 f"🕒 Час: {data['time_str']}\n"
  569.                 f"🔢 ONU №{data['onu_number']}\n"
  570.                 f"📍 Порт: {data['onu_iface']}{desc_str}\n"
  571.                 f"🖥 OLT: {key[0]} ({key[1]})"
  572.             )
  573.             send_telegram(msg, sent_messages)
  574.             del onu_add_buffer[key]
  575.  
  576.     return end_pos
  577.  
  578. # Моніторинг логу
  579. def monitor_log():
  580.     sent_messages = load_sent_messages()
  581.     if can_send_activation():
  582.         test_msg = f"🔔 Моніторинг OLT активовано\n\n🕒 Час: {datetime.now().strftime('%H:%M:%S')}"
  583.         send_telegram(test_msg, sent_messages)
  584.         save_activation_time()
  585.     last_pos, last_inode = load_last_position()
  586.  
  587.     while True:
  588.         try:
  589.             check_file_size(LOG_FILE_PATH, "olt_monitor.log", max_size_mb=10)
  590.             check_file_size(SENT_MESSAGES_FILE, "sent_messages.txt", max_size_mb=10)
  591.             check_file_size(LAN_EVENTS_LOG, "lan_events.log", max_size_mb=10)
  592.             if not os.path.exists(LOG_FILE):
  593.                 logging.error(f"Файл логу {LOG_FILE} не існує. Очікування 60 секунд")
  594.                 time.sleep(60)
  595.                 continue
  596.             current_inode = os.stat(LOG_FILE).st_ino
  597.             if current_inode != last_inode:
  598.                 logging.info(f"Виявлено новий inode для {LOG_FILE}, скидання позиції")
  599.                 last_pos, last_inode = 0, current_inode
  600.             with open(LOG_FILE, "r", encoding="utf-8") as f:
  601.                 new_pos = parse_log(f, last_pos, sent_messages)
  602.                 if new_pos != last_pos:
  603.                     save_last_position(new_pos)
  604.                     last_pos = new_pos
  605.             time.sleep(CHECK_INTERVAL)
  606.         except Exception as e:
  607.             logging.error(f"Критична помилка при обробці логу: {e}")
  608.             time.sleep(60)
  609.  
  610. # Планувальник для щоденного звіту
  611. def run_scheduler():
  612.     sent_messages = load_sent_messages()
  613.     schedule.every().day.at(REPORT_TIME).do(send_lan_summary_to_telegram, sent_messages)
  614.     while True:
  615.         schedule.run_pending()
  616.         time.sleep(60)
  617.  
  618. if __name__ == "__main__":
  619.     try:
  620.         setup_logging_and_messages()
  621.         # Перевіряємо аргумент командного рядка
  622.         if len(sys.argv) > 1 and sys.argv[1] == "--manual-report":
  623.             manual_lan_summary()
  624.         else:
  625.             # Запускаємо планувальник у окремому потоці
  626.             scheduler_thread = threading.Thread(target=run_scheduler, daemon=True)
  627.             scheduler_thread.start()
  628.             monitor_log()
  629.     except Exception as e:
  630.         logging.error(f"Помилка запуску програми: {e}")
  631.         raise
  632.  
Tags: OLT-ZTE
Advertisement
Comments
  • skybetik
    1 day
    # text 0.28 KB | 0 0
    1. cat config.ini
    2.  
    3. [Settings]
    4. TelegramBotToken = 1233445657786867867868658
    5. TelegramChatIDs = id1,id2,id3
    6. SentMessagesFile = /opt/olt_monitor/sent_messages.txt
    7. LogFile = /var/log/zte.log
    8. LastPositionFile = /opt/olt_monitor/last_position.txt
    9. CheckInterval = 5
    10. ReportTime = 08:00
Add Comment
Please, Sign In to add comment
Advertisement