
Недавно на работе меня попросили придумать рабочую задачку для студентов. Поскольку я работаю в инфраструктурной команде, мои повседневные задачи вряд ли подходят для их домашек или курсовых работ. Чтобы найти подходящую идею, я начал перебирать инструменты, которыми мы с командой часто пользуемся. Большинство из них интегрированы с чатами и ботами, и один из ключевых инструментов — это Алерт Бот. Он отслеживает логи и отправляет оповещения, если происходит что-то необычное. Это позволяет нам быстрее обнаруживать и устранять инциденты.
Когда я придумал эту задачу для студентов, мне пришло в голову, что подобный функционал может быть полезен многим. Возможно, кто-то сможет адаптировать это решение под свои нужды и облегчить себе жизнь, автоматизируя процесс мониторинга и реагирования на инциденты. Собственно этим я бы и хотел поделиться в своей статье.
Описание задачи
Итак, студентам предлагается разработать бота, который будет анализировать логи сервера и отправлять уведомления в Telegram, если обнаруживает ошибки или другие аномалии. Основные требования к проекту:
-
Мониторинг логов: Бот должен периодически проверять указанный файл логов и искать в нем ошибки.
-
Фильтрация данных: Необходимо отфильтровать важные сообщения (например, с уровнем ERROR или CRITICAL) и игнорировать менее значимые (DEBUG, INFO).
-
Отправка уведомлений: При обнаружении ошибок бот должен отправлять сообщение в Telegram-чат.
-
Конфигурируемость: Настройки, такие как путь к логам, частота проверки и идентификатор чата, должны быть легко изменяемы.
Архитектура решения
Наш бот будет состоять из следующих основных компонентов:
-
Лог-файл: Файл, содержащий журналы событий сервера, который бот будет анализировать.
-
Анализатор логов: Модуль, который читает файл логов и извлекает из него важные сообщения.
-
Telegram-бот: Модуль, который отправляет найденные ошибки в указанный чат.
Эти компоненты должны взаимодействовать между собой, обеспечивая непрерывный мониторинг логов и оперативное уведомление о проблемах.
Генерация логов
Давайте начнем с моделирования деятельности сервера, чтобы у нас были логи для анализа. Мы создадим скрипт на Go, который будет генерировать логи с разными уровнями сообщений (например, INFO, WARNING, ERROR) в случайном порядке.
Предположим, что наш «сервер» будет периодически генерировать события с различными уровнями важности. Для этого напишем скрипт, который будет записывать логи в файл.
1. Создание функции для чтения и записи строчек в файл
Сначала создадим функции, которые будут считывать логи и писать их:
func readLines(fileName string) ([]string, error) { file, err := os.Open(fileName) if os.IsNotExist(err) { return []string{}, nil } else if err != nil { return nil, err } defer file.Close() var lines []string scanner := bufio.NewScanner(file) for scanner.Scan() { lines = append(lines, scanner.Text()) } return lines, scanner.Err() } func writeLines(lines []string, fileName string) error { file, err := os.Create(fileName) if err != nil { return err } defer file.Close() writer := bufio.NewWriter(file) for _, line := range lines { fmt.Fprintln(writer, line) } return writer.Flush() }
2. Функции для генерации логов
Теперь создадим функции, которые будут генерировать нам непосредственно сами логи
var ( logLevels = []string{"DEBUG", "INFO", "ERROR"} mu sync.Mutex ) func generateLog() { mu.Lock() defer mu.Unlock() lines, err := readLines(logFileName) if err != nil { fmt.Println("Error reading log file:", err) return } if len(lines) >= maxLines { lines = lines[len(lines)-maxLines+1:] } logLine := fmt.Sprintf("%s [%s] %s\n", time.Now().Format(time.RFC3339), logLevels[rand.Intn(len(logLevels))], generateRandomMessage()) lines = append(lines, logLine) err = writeLines(lines, logFileName) if err != nil { fmt.Println("Error writing to log file:", err) } } func generateRandomMessage() string { messages := []string{ "User logged in", "File uploaded", "Error processing request", "User logged out", "Database connection established", "Invalid input received", } return messages[rand.Intn(len(messages))] }
3. Основная функция для генерации логов
Теперь объединим всё вместе в основной функции, которая будет периодически генерировать и записывать лог-сообщения:
const ( logFileName = "logs.log" maxLines = 200 ) func main() { rand.Seed(time.Now().UnixNano()) go func() { for { generateLog() time.Sleep(time.Millisecond * 100) } }() select {} }
Важно помнить, что логи не должны храниться бесконечно. Со временем их количество может значительно возрасти, что приведет к увеличению объема файла и возможным проблемам с производительностью. Чтобы этого избежать, следует установить разумные ограничения на количество сохраняемых записей. В данном примере мы ограничиваемся хранением последних 200 логов
Продолжение разработки бота на Go
Теперь, когда у нас есть сгенерированные логи, приступим к разработке бота, который будет их анализировать и отправлять уведомления в Telegram. Ниже описаны основные шаги для создания такого бота.
1. Установка необходимых библиотек
Для работы с Telegram и анализа логов нам потребуются несколько внешних библиотек. В Go это можно сделать с помощью go get:
go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5
Эта библиотека предоставит нам интерфейс для взаимодействия с Telegram.
2. Чтение и анализ логов
Первый шаг в нашем боте — это чтение логов и поиск в них ошибок. Мы будем использовать функцию для чтения файла и фильтрации важных сообщений.
package main import ( "bufio" "fmt" "os" "strings" "time" ) func readLogs(logFilePath string) ([]string, error) { file, err := os.Open(logFilePath) if err != nil { return nil, err } defer file.Close() var importantLogs []string scanner := bufio.NewScanner(file) for scanner.Scan() { logLine := scanner.Text() if strings.Contains(logLine, "ERROR") || strings.Contains(logLine, "CRITICAL") { importantLogs = append(importantLogs, logLine) } } if err := scanner.Err(); err != nil { return nil, err } return importantLogs, nil }
3. Отправка уведомлений в Telegram
Следующим шагом будет отправка уведомлений в Telegram. Для этого воспользуемся библиотекой telegram-bot-api.
package main import ( "log" "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) func sendTelegramNotification(bot *tgbotapi.BotAPI, chatID int64, message string) { msg := tgbotapi.NewMessage(chatID, message) _, err := bot.Send(msg) if err != nil { log.Printf("Error sending message: %v", err) } }
4. Основная функция для мониторинга логов и отправки уведомлений
Теперь объединим всё вместе в основной функции. Она будет периодически проверять логи и отправлять уведомления, если обнаружены ошибки.
package main import ( "fmt" "log" "time" "os" "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) func main() { logFilePath := "server.log" botToken := "YOUR_TELEGRAM_BOT_TOKEN" chatID := int64(YOUR_CHAT_ID) bot, err := tgbotapi.NewBotAPI(botToken) if err != nil { log.Panic(err) } log.Printf("Authorized on account %s", bot.Self.UserName) for { importantLogs, err := readLogs(logFilePath) if err != nil { log.Printf("Error reading log file: %v", err) continue } for _, logMessage := range importantLogs { sendTelegramNotification(bot, chatID, logMessage) } time.Sleep(10 * time.Second) // Проверяем логи каждые 10 секунд } }
5. Конфигурируемость
Для удобства можно вынести параметры, такие как путь к логам, токен бота и идентификатор чата, в конфигурационный файл или использовать переменные окружения. Это упростит адаптацию бота к разным условиям эксплуатации.
Пример использования переменных окружения:
package main import ( "os" "log" ) func main() { logFilePath := os.Getenv("LOG_FILE_PATH") botToken := os.Getenv("TELEGRAM_BOT_TOKEN") chatID := os.Getenv("TELEGRAM_CHAT_ID") if logFilePath == "" || botToken == "" || chatID == "" { log.Fatal("Missing necessary environment variables") } // Остальной код... }
Теперь, когда бот готов, его можно развернуть на сервере или в облаке и использовать для мониторинга логов в реальных условиях. Опытные разработчики, вероятно, уже знакомы с подобными задачами, но надеюсь, что эта статья оказалась полезной для тех, кто только начинает свой путь в программировании, работает над своими пет-проектами или делает первые шаги в индустрии. Создание таких инструментов — отличный способ приобрести навыки, которые пригодятся в реальной работе.
ссылка на оригинал статьи https://habr.com/ru/articles/835756/
Добавить комментарий