Advertisement
skybetik

OLT-zte send_telegram

Jun 8th, 2025 (edited)
1,086
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 34.30 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. # Відправка довгих повідомлень з розбиттям
  132. def send_long_telegram(msg, sent_messages, max_length=4000):
  133.     if len(msg) <= max_length:
  134.         send_telegram(msg, sent_messages)
  135.         return
  136.  
  137.     logging.info(f"Повідомлення перевищує {max_length} символів (довжина: {len(msg)}), розбиття на частини")
  138.     parts = []
  139.     current_part = f"📊 Звіт подій LAN за {date.today()}:\n\n"
  140.     entry_lines = []
  141.     lines = msg.split('\n')
  142.    
  143.     # Пропускаем шапку и собираем записи
  144.     for line in lines[2:]:  # Пропускаем первые две строки (шапка)
  145.         if line.strip() == "":  # Конец записи (пустая строка)
  146.             if entry_lines:
  147.                 entry_text = '\n'.join(entry_lines) + '\n\n'
  148.                 if len(current_part) + len(entry_text) > max_length:
  149.                     parts.append(current_part.strip())
  150.                     current_part = f"📊 Звіт подій LAN за {date.today()} (продовження):\n\n"
  151.                 current_part += entry_text
  152.                 entry_lines = []
  153.         else:
  154.             entry_lines.append(line)
  155.    
  156.     # Добавляем последнюю запись
  157.     if entry_lines:
  158.         entry_text = '\n'.join(entry_lines) + '\n\n'
  159.         if len(current_part) + len(entry_text) > max_length:
  160.             parts.append(current_part.strip())
  161.             current_part = f"📊 Звіт подій LAN за {date.today()} (продовження):\n\n"
  162.         current_part += entry_text
  163.    
  164.     # Добавляем текущую часть, если она не пуста
  165.     if current_part.strip() != f"📊 Звіт подій LAN за {date.today()} (продовження):":
  166.         parts.append(current_part.strip())
  167.  
  168.     # Отправляем части
  169.     for i, part in enumerate(parts, 1):
  170.         send_telegram(part, sent_messages)
  171.         logging.info(f"Відправлено частину {i} звіту (довжина: {len(part)} символів)")
  172.  
  173. # Відправка звіту про події LAN у Telegram (з очищенням lan_events.log)
  174. def send_lan_summary_to_telegram(sent_messages):
  175.     logging.info("Початок створення звіту про події LAN")
  176.     summary = defaultdict(lambda: {'los': 0, 'restore': 0})
  177.     today = str(date.today())
  178.  
  179.     try:
  180.         if not os.path.exists(LAN_EVENTS_LOG):
  181.             logging.info(f"Файл {LAN_EVENTS_LOG} не існує")
  182.         else:
  183.             with open(LAN_EVENTS_LOG, 'r', encoding='utf-8') as f:
  184.                 lines_processed = 0
  185.                 current_entry = []
  186.                 for line in f:
  187.                     line = line.strip()
  188.                     if not line:
  189.                         continue
  190.                     # Начало новой записи определяется по временной метке (YYYY-MM-DD HH:MM:SS, с опциональными миллисекундами)
  191.                     if re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:,\d+)?", line):
  192.                         if current_entry:  # Обрабатываем предыдущую запись
  193.                             lines_processed += 1
  194.                             entry_text = '\n'.join(current_entry)
  195.                             logging.debug(f"Обробка запису у {LAN_EVENTS_LOG}: {entry_text}")
  196.                             # Извлекаем порт, OLT и номер ONU
  197.                             port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  198.                             olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  199.                             onu_match = re.search(r"ONU №(\d+)", entry_text)
  200.                             if port_match and olt_match and onu_match:
  201.                                 port = port_match.group(1)
  202.                                 olt_name = olt_match.group(1)
  203.                                 olt_ip = olt_match.group(2)
  204.                                 onu_number = onu_match.group(1)
  205.                                 key = (port, olt_name, olt_ip, onu_number)
  206.                                 if "LAN LOS знайдено" in entry_text:
  207.                                     summary[key]['los'] += 1
  208.                                     logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  209.                                 elif "LAN LOS Restore знайдено" in entry_text:
  210.                                     summary[key]['restore'] += 1
  211.                                     logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  212.                             else:
  213.                                 logging.debug(f"Запис не відповідає формату port/olt/onu: {entry_text}")
  214.                             current_entry = []
  215.                         current_entry.append(line)
  216.                     else:
  217.                         current_entry.append(line)
  218.  
  219.                 # Обработка последней записи
  220.                 if current_entry:
  221.                     lines_processed += 1
  222.                     entry_text = '\n'.join(current_entry)
  223.                     logging.debug(f"Обробка останнього запису у {LAN_EVENTS_LOG}: {entry_text}")
  224.                     port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  225.                     olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  226.                     onu_match = re.search(r"ONU №(\d+)", entry_text)
  227.                     if port_match and olt_match and onu_match:
  228.                         port = port_match.group(1)
  229.                         olt_name = olt_match.group(1)
  230.                         olt_ip = olt_match.group(2)
  231.                         onu_number = onu_match.group(1)
  232.                         key = (port, olt_name, olt_ip, onu_number)
  233.                         if "LAN LOS знайдено" in entry_text:
  234.                             summary[key]['los'] += 1
  235.                             logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  236.                         elif "LAN LOS Restore знайдено" in entry_text:
  237.                             summary[key]['restore'] += 1
  238.                             logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  239.                     else:
  240.                         logging.debug(f"Останній запис не відповідає формату: {entry_text}")
  241.  
  242.                 logging.info(f"Оброблено {lines_processed} записів у {LAN_EVENTS_LOG}")
  243.  
  244.         # Формирование отчета
  245.         if summary:
  246.             msg = f"📊 Звіт подій LAN за {today}:\n\n"
  247.             for (port, olt_name, olt_ip, onu_number), counts in sorted(summary.items()):
  248.                 total = counts['los'] + counts['restore']
  249.                 msg += (
  250.                     f"🔢 ONU №{onu_number}\n"
  251.                     f"📍 Порт: {port}\n"
  252.                     f"🖥 OLT: {olt_name} ({olt_ip})\n"
  253.                     f"🔴 Втрата LAN: {counts['los']}\n"
  254.                     f"🟢 LAN відновлено: {counts['restore']}\n"
  255.                     f"🔢 Загалом: {total}\n\n"
  256.                 )
  257.         else:
  258.             msg = f"📊 Звіт подій LAN за {today}:\n\n⚠️ Подій LAN LOS або Restore не знайдено"
  259.  
  260.         send_long_telegram(msg.strip(), sent_messages)
  261.         logging.info("Звіт про події LAN відправлено в Telegram")
  262.  
  263.         # Очищаем lan_events.log после отправки
  264.         try:
  265.             with open(LAN_EVENTS_LOG, 'w', encoding='utf-8') as f:
  266.                 f.write('')
  267.             logging.info(f"Файл {LAN_EVENTS_LOG} очищено після відправки звіту")
  268.         except Exception as e:
  269.             logging.error(f"Помилка очищення {LAN_EVENTS_LOG}: {e}")
  270.  
  271.     except Exception as e:
  272.         logging.error(f"Помилка створення звіту LAN: {e}")
  273.  
  274. # Ручна перевірка звіту без очищення lan_events.log
  275. def manual_lan_summary():
  276.     sent_messages = load_sent_messages()
  277.     logging.info("Початок ручної перевірки звіту про події LAN")
  278.     summary = defaultdict(lambda: {'los': 0, 'restore': 0})
  279.     today = str(date.today())
  280.  
  281.     try:
  282.         if not os.path.exists(LAN_EVENTS_LOG):
  283.             logging.info(f"Файл {LAN_EVENTS_LOG} не існує")
  284.         else:
  285.             with open(LAN_EVENTS_LOG, 'r', encoding='utf-8') as f:
  286.                 lines_processed = 0
  287.                 current_entry = []
  288.                 for line in f:
  289.                     line = line.strip()
  290.                     if not line:
  291.                         continue
  292.                     # Начало новой записи определяется по временной метке
  293.                     if re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:,\d+)?", line):
  294.                         if current_entry:  # Обрабатываем предыдущую запись
  295.                             lines_processed += 1
  296.                             entry_text = '\n'.join(current_entry)
  297.                             logging.debug(f"Обробка запису у {LAN_EVENTS_LOG}: {entry_text}")
  298.                             port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  299.                             olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  300.                             onu_match = re.search(r"ONU №(\d+)", entry_text)
  301.                             if port_match and olt_match and onu_match:
  302.                                 port = port_match.group(1)
  303.                                 olt_name = olt_match.group(1)
  304.                                 olt_ip = olt_match.group(2)
  305.                                 onu_number = onu_match.group(1)
  306.                                 key = (port, olt_name, olt_ip, onu_number)
  307.                                 if "LAN LOS знайдено" in entry_text:
  308.                                     summary[key]['los'] += 1
  309.                                     logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  310.                                 elif "LAN LOS Restore знайдено" in entry_text:
  311.                                     summary[key]['restore'] += 1
  312.                                     logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  313.                             else:
  314.                                 logging.debug(f"Запис не відповідає формату port/olt/onu: {entry_text}")
  315.                             current_entry = []
  316.                         current_entry.append(line)
  317.                     else:
  318.                         current_entry.append(line)
  319.  
  320.                 # Обработка последней записи
  321.                 if current_entry:
  322.                     lines_processed += 1
  323.                     entry_text = '\n'.join(current_entry)
  324.                     logging.debug(f"Обробка останнього запису у {LAN_EVENTS_LOG}: {entry_text}")
  325.                     port_match = re.search(r"Порт: (gpon-onu_\d+/\d+/\d+(?::\d+)?)", entry_text)
  326.                     olt_match = re.search(r"OLT: (\S+) \((\d+\.\d+\.\d+\.\d+)\)", entry_text)
  327.                     onu_match = re.search(r"ONU №(\d+)", entry_text)
  328.                     if port_match and olt_match and onu_match:
  329.                         port = port_match.group(1)
  330.                         olt_name = olt_match.group(1)
  331.                         olt_ip = olt_match.group(2)
  332.                         onu_number = onu_match.group(1)
  333.                         key = (port, olt_name, olt_ip, onu_number)
  334.                         if "LAN LOS знайдено" in entry_text:
  335.                             summary[key]['los'] += 1
  336.                             logging.debug(f"Знайдено LAN LOS для {key} у {LAN_EVENTS_LOG}")
  337.                         elif "LAN LOS Restore знайдено" in entry_text:
  338.                             summary[key]['restore'] += 1
  339.                             logging.debug(f"Знайдено LAN LOS Restore для {key} у {LAN_EVENTS_LOG}")
  340.                     else:
  341.                         logging.debug(f"Останній запис не відповідає формату: {entry_text}")
  342.  
  343.                 logging.info(f"Оброблено {lines_processed} записів у {LAN_EVENTS_LOG}")
  344.  
  345.         # Формирование отчета
  346.         if summary:
  347.             msg = f"📊 Ручний звіт подій LAN за {today}:\n\n"
  348.             for (port, olt_name, olt_ip, onu_number), counts in sorted(summary.items()):
  349.                 total = counts['los'] + counts['restore']
  350.                 msg += (
  351.                     f"🔢 ONU №{onu_number}\n"
  352.                     f"📍 Порт: {port}\n"
  353.                     f"🖥 OLT: {olt_name} ({olt_ip})\n"
  354.                     f"🔴 Втрата LAN: {counts['los']}\n"
  355.                     f"🟢 LAN відновлено: {counts['restore']}\n"
  356.                     f"🔢 Загалом: {total}\n\n"
  357.                 )
  358.         else:
  359.             msg = f"📊 Ручний звіт подій LAN за {today}:\n\n⚠️ Подій LAN LOS або Restore не знайдено"
  360.  
  361.         send_long_telegram(msg.strip(), sent_messages)
  362.         logging.info("Ручний звіт про події LAN відправлено в Telegram")
  363.  
  364.     except Exception as e:
  365.         logging.error(f"Помилка створення ручного звіту LAN: {e}")
  366.  
  367. # Налаштування логування та перезапису файлів
  368. def setup_logging_and_messages():
  369.     try:
  370.         logging.info("Початок налаштування логування")
  371.         last_reset_date = None
  372.         if os.path.exists(LAST_RESET_FILE):
  373.             with open(LAST_RESET_FILE, 'r') as f:
  374.                 last_reset_date = f.read().strip()
  375.             logging.info(f"Прочитано дату останнього перезапису: {last_reset_date}")
  376.         else:
  377.             logging.info(f"Файл {LAST_RESET_FILE} не існує, буде створено")
  378.         today = str(date.today())
  379.         logging.info(f"Поточна дата: {today}")
  380.  
  381.         # Перевірка розміру логу
  382.         log_size_mb = os.path.getsize(LOG_FILE_PATH) / (1024 * 1024) if os.path.exists(LOG_FILE_PATH) else 0
  383.         logging.info("Розмір логу: " + str(round(log_size_mb, 2)) + " МБ")
  384.  
  385.         if last_reset_date != today:
  386.             sent_messages = load_sent_messages()
  387.             try:
  388.                 logging.basicConfig(
  389.                     filename=LOG_FILE_PATH,
  390.                     level=logging.INFO,
  391.                     format='%(asctime)s [%(levelname)s] %(message)s',
  392.                     filemode='w',
  393.                     force=True
  394.                 )
  395.                 logging.info(f"Лог перезаписано для нової доби (size={log_size_mb:.2f} МБ)")
  396.                 with open(SENT_MESSAGES_FILE, 'w', encoding='utf-8') as f:
  397.                     f.write('')
  398.                 logging.info("Файл sent_messages.txt перезаписано для нової доби")
  399.                 with open(LAST_RESET_FILE, 'w') as f:
  400.                     f.write(today)
  401.                 logging.info(f"Оновлено {LAST_RESET_FILE} з датою {today}")
  402.             except Exception as e:
  403.                 logging.error(f"Помилка при перезаписі файлів: {e}")
  404.                 raise
  405.         else:
  406.             logging.basicConfig(
  407.                 filename=LOG_FILE_PATH,
  408.                 level=logging.INFO,
  409.                 format='%(asctime)s [%(levelname)s] %(message)s',
  410.                 filemode='a',
  411.                 force=True
  412.             )
  413.             logging.info("Дата не змінилася, використовується режим додавання")
  414.     except Exception as e:
  415.         logging.error(f"Критична помилка налаштування: {e}")
  416.         print(f"Критична помилка налаштування: {e}")
  417.         raise
  418.  
  419. # Перевірка розміру файлів
  420. def check_file_size(file_path, file_name, max_size_mb=10):
  421.     try:
  422.         if os.path.exists(file_path):
  423.             size_mb = os.path.getsize(file_path) / (1024 * 1024)
  424.             if size_mb > max_size_mb:
  425.                 current_time = time.time()
  426.                 last_warning_time = last_size_warning.get(file_name, 0)
  427.                 if current_time - last_warning_time > 600:
  428.                     logging.warning(f"Розмір {file_name} перевищує {max_size_mb} МБ: {size_mb:.2f} МБ")
  429.                     last_size_warning[file_name] = current_time
  430.     except Exception as e:
  431.         logging.error(f"Помилка перевірки розміру {file_name}: {e}")
  432.  
  433. # Глобальні змінні
  434. current_interface = None
  435. current_olt_name = None
  436. current_olt_ip = None
  437. current_description = None
  438. onu_add_buffer = defaultdict(dict)
  439.  
  440. # Завантажуємо останню позицію
  441. def load_last_position():
  442.     if not os.path.exists(LAST_POSITION_FILE):
  443.         return 0, os.stat(LOG_FILE).st_ino if os.path.exists(LOG_FILE) else 0
  444.     try:
  445.         with open(LAST_POSITION_FILE, 'r') as f:
  446.             pos = f.read().strip()
  447.             if pos == '':
  448.                 return 0, os.stat(LOG_FILE).st_ino
  449.             return int(pos), os.stat(LOG_FILE).st_ino
  450.     except Exception as e:
  451.         logging.error(f"Помилка читання позиції з {LAST_POSITION_FILE}: {e}")
  452.         return 0, os.stat(LOG_FILE).st_ino if os.path.exists(LOG_FILE) else 0
  453.  
  454. # Зберігаємо останню позицію
  455. def save_last_position(position):
  456.     try:
  457.         with open(LAST_POSITION_FILE, 'w') as f:
  458.             f.write(str(position))
  459.     except Exception as e:
  460.         logging.error(f"Помилка збереження позиції в {LAST_POSITION_FILE}: {e}")
  461.  
  462. # Парсинг логу
  463. def parse_log(file_obj, start_pos, sent_messages):
  464.     global current_interface, current_olt_name, current_olt_ip, current_description
  465.     try:
  466.         file_obj.seek(start_pos)
  467.         file_size = os.path.getsize(LOG_FILE)
  468.         if start_pos > file_size:
  469.             logging.warning(f"start_pos ({start_pos}) більше file_size ({file_size}), скидаємо на 0")
  470.             start_pos = 0
  471.             file_obj.seek(0)
  472.         lines = file_obj.readlines()
  473.         end_pos = file_obj.tell()
  474.     except Exception as e:
  475.         logging.error(f"Помилка читання файлу логу: {e}")
  476.         return start_pos
  477.  
  478.     for line in lines:
  479.         line = line.strip().replace('#012', '').replace('#015', '')
  480.         if not line:
  481.             continue
  482.  
  483.         # Витягуємо ім'я та IP OLT
  484.         m_olt = re.search(r"\[(\S+) (\d+\.\d+\.\d+\.\d+)\]", line)
  485.         if m_olt:
  486.             current_olt_name = m_olt.group(1)
  487.             current_olt_ip = m_olt.group(2)
  488.  
  489.         # Витягуємо час
  490.         time_match = re.match(r"^\w+\s+\d+\s+(\d{2}:\d{2}:\d{2})", line)
  491.         time_str = time_match.group(1) if time_match else datetime.now().strftime("%H:%M:%S")
  492.         try:
  493.             event_time = datetime.strptime(time_str, "%H:%M:%S")
  494.             event_time = event_time.replace(year=datetime.now().year, month=datetime.now().month, day=datetime.now().day)
  495.         except ValueError as e:
  496.             logging.error(f"Помилка формату часу {time_str}: {e}")
  497.             continue
  498.  
  499.         # Перевіряємо OLT перед обробкою подій
  500.         if not current_olt_name or not current_olt_ip:
  501.             logging.warning(f"Пропущено подію через відсутність OLT: {line}")
  502.             continue
  503.  
  504.         # Витягуємо інтерфейс
  505.         m_intf = re.search(r"(?:interface\s+)(gpon-olt_\d+/\d+/\d+|gpon-onu_\d+/\d+/\d+:\d+)", line, re.IGNORECASE)
  506.         if m_intf:
  507.             current_interface = m_intf.group(1)
  508.             continue
  509.  
  510.         # Витягуємо description
  511.         m_desc = re.search(r"description\s+(\S+)", line, re.IGNORECASE)
  512.         if m_desc:
  513.             current_description = m_desc.group(1)
  514.             for key, data in list(onu_add_buffer.items()):
  515.                 if key[2] == current_interface or key[2].replace("gpon-olt_", "gpon-onu_") + f":{key[3]}" == current_interface:
  516.                     data['description'] = current_description
  517.                     desc_str = f"\n🏷 Опис: {data['description']}" if data['description'] else ""
  518.                     msg = (
  519.                         f"✅ ONU додано\n\n"
  520.                         f"🕒 Час: {data['time_str']}\n"
  521.                         f"🔢 ONU №{data['onu_number']}\n"
  522.                         f"📍 Порт: {data['onu_iface']}{desc_str}\n"
  523.                         f"🖥 OLT: {key[0]} ({key[1]})"
  524.                     )
  525.                     send_telegram(msg, sent_messages)
  526.                     del onu_add_buffer[key]
  527.             continue
  528.  
  529.         # LAN LOS Alarm
  530.         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)
  531.         if m_lan_los:
  532.             m_iface_num = re.search(r"<(gpon-onu_\d+/\d+/\d+):(\d+)>", line)
  533.             if m_iface_num:
  534.                 onu_iface = m_iface_num.group(1)
  535.                 onu_num = m_iface_num.group(2)
  536.                 desc_str = f"\n🏷 Опис: {current_description}" if current_description and current_interface == onu_iface else ""
  537.                 msg = (
  538.                     f"🔴 Втрата LAN-з'єднання\n\n"
  539.                     f"🕒 Час: {time_str}\n"
  540.                     f"🔢 ONU №{onu_num}\n"
  541.                     f"📍 Порт: {onu_iface}{desc_str}\n"
  542.                     f"🖥 OLT: {current_olt_name} ({current_olt_ip})"
  543.                 )
  544.                 lan_logger.warning(f"LAN LOS знайдено: {msg}")  # Записываем только в lan_events.log
  545.                 current_description = None
  546.             continue
  547.  
  548.         # LAN LOS Restore
  549.         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)
  550.         if m_lan_restore:
  551.             m_iface_num = re.search(r"<(gpon-onu_\d+/\d+/\d+):(\d+)>", line)
  552.             if m_iface_num:
  553.                 onu_iface = m_iface_num.group(1)
  554.                 onu_num = m_iface_num.group(2)
  555.                 desc_str = f"\n🏷 Опис: {current_description}" if current_description and current_interface == onu_iface else ""
  556.                 msg = (
  557.                     f"🟢 LAN-з'єднання відновлено\n\n"
  558.                     f"🕒 Час: {time_str}\n"
  559.                     f"🔢 ONU №{onu_num}\n"
  560.                     f"📍 Порт: {onu_iface}{desc_str}\n"
  561.                     f"🖥 OLT: {current_olt_name} ({current_olt_ip})"
  562.                 )
  563.                 lan_logger.warning(f"LAN LOS Restore знайдено: {msg}")  # Записываем только в lan_events.log
  564.                 current_description = None
  565.             continue
  566.  
  567.         # Видалення ONU
  568.         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)
  569.         if m_no_onu:
  570.             onu_iface = m_no_onu.group(2) or current_interface or "невідомий"
  571.             onu_number = m_no_onu.group(1) or m_no_onu.group(3)
  572.             desc_str = f"\n🏷 Опис: {current_description}" if current_description and current_interface == onu_iface else ""
  573.             msg = (
  574.                 f"❌ ONU видалено\n\n"
  575.                 f"🕒 Час: {time_str}\n"
  576.                 f"🔢 ONU №{onu_number}\n"
  577.                 f"📍 Порт: {onu_iface}{desc_str}\n"
  578.                 f"🖥 OLT: {current_olt_name} ({current_olt_ip})"
  579.             )
  580.             send_telegram(msg, sent_messages)
  581.             current_description = None
  582.             key = (current_olt_name, current_olt_ip, onu_iface, onu_number)
  583.             if key in onu_add_buffer:
  584.                 del onu_add_buffer[key]
  585.             continue
  586.  
  587.         # Додавання ONU
  588.         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)
  589.         if m_add_onu:
  590.             onu_iface = m_add_onu.group(1) or m_add_onu.group(3) or current_interface or "невідомий"
  591.             onu_number = m_add_onu.group(2) or m_add_onu.group(4) or m_add_onu.group(5)
  592.             key = (current_olt_name, current_olt_ip, onu_iface, onu_number)
  593.             onu_add_buffer[key] = {
  594.                 'time_str': time_str,
  595.                 'onu_iface': onu_iface,
  596.                 'onu_number': onu_number,
  597.                 'description': current_description if current_interface == onu_iface else None,
  598.                 'timestamp': datetime.now()
  599.             }
  600.             current_description = None
  601.             continue
  602.  
  603.     # Обробка відкладених подій ONU
  604.     current_time = datetime.now()
  605.     for key, data in list(onu_add_buffer.items()):
  606.         if (current_time - data['timestamp']).seconds >= 5:
  607.             desc_str = f"\n🏷 Опис: {data['description']}" if data['description'] else ""
  608.             msg = (
  609.                 f"✅ ONU додано\n\n"
  610.                 f"🕒 Час: {data['time_str']}\n"
  611.                 f"🔢 ONU №{data['onu_number']}\n"
  612.                 f"📍 Порт: {data['onu_iface']}{desc_str}\n"
  613.                 f"🖥 OLT: {key[0]} ({key[1]})"
  614.             )
  615.             send_telegram(msg, sent_messages)
  616.             del onu_add_buffer[key]
  617.  
  618.     return end_pos
  619.  
  620. # Моніторинг логу
  621. def monitor_log():
  622.     sent_messages = load_sent_messages()
  623.     if can_send_activation():
  624.         test_msg = f"🔔 Моніторинг OLT активовано\n\n🕒 Час: {datetime.now().strftime('%H:%M:%S')}"
  625.         send_telegram(test_msg, sent_messages)
  626.         save_activation_time()
  627.     last_pos, last_inode = load_last_position()
  628.  
  629.     while True:
  630.         try:
  631.             check_file_size(LOG_FILE_PATH, "olt_monitor.log", max_size_mb=10)
  632.             check_file_size(SENT_MESSAGES_FILE, "sent_messages.txt", max_size_mb=10)
  633.             check_file_size(LAN_EVENTS_LOG, "lan_events.log", max_size_mb=10)
  634.             if not os.path.exists(LOG_FILE):
  635.                 logging.error(f"Файл логу {LOG_FILE} не існує. Очікування 60 секунд")
  636.                 time.sleep(60)
  637.                 continue
  638.             current_inode = os.stat(LOG_FILE).st_ino
  639.             if current_inode != last_inode:
  640.                 logging.info(f"Виявлено новий inode для {LOG_FILE}, скидання позиції")
  641.                 last_pos, last_inode = 0, current_inode
  642.             with open(LOG_FILE, "r", encoding="utf-8") as f:
  643.                 new_pos = parse_log(f, last_pos, sent_messages)
  644.                 if new_pos != last_pos:
  645.                     save_last_position(new_pos)
  646.                     last_pos = new_pos
  647.             time.sleep(CHECK_INTERVAL)
  648.         except Exception as e:
  649.             logging.error(f"Критична помилка при обробці логу: {e}")
  650.             time.sleep(60)
  651.  
  652. # Планувальник для щоденного звіту
  653. def run_scheduler():
  654.     sent_messages = load_sent_messages()
  655.     schedule.every().day.at(REPORT_TIME).do(send_lan_summary_to_telegram, sent_messages)
  656.     while True:
  657.         schedule.run_pending()
  658.         time.sleep(60)
  659.  
  660. if __name__ == "__main__":
  661.     try:
  662.         setup_logging_and_messages()
  663.         # Перевіряємо аргумент командного рядка
  664.         if len(sys.argv) > 1 and sys.argv[1] == "--manual-report":
  665.             manual_lan_summary()
  666.         else:
  667.             # Запускаємо планувальник у окремому потоці
  668.             scheduler_thread = threading.Thread(target=run_scheduler, daemon=True)
  669.             scheduler_thread.start()
  670.             monitor_log()
  671.     except Exception as e:
  672.         logging.error(f"Помилка запуску програми: {e}")
  673.         raise
Tags: OLT-ZTE
Advertisement
Comments
  • skybetik
    14 days
    # 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
  • skybetik
    12 days
    # text 0.09 KB | 0 0
    1. fix
    2. esponse: {"ok":false,"error_code":400,"description":"Bad Request: message is too long"
Add Comment
Please, Sign In to add comment
Advertisement