Это моя первая статья на Хабре, пишу её по ходу своего обучения. За подсказки буду очень благодарен.
Здесь автор говорит о том, какими должны быть логи. В своем цикле статей я покажу вам как можно сделать подобное логирование своими руками на GO.
Итак начнём. Для начала нам необходимо сделать простейший tcp сервер:
package main import ( "log" "net" ) func main() { //вешаем сервер на 2000 порт l, err := net.Listen("tcp", ":2000") if err != nil { log.Fatal(err) } defer l.Close() for { //В вечном цикле "слушаем" 2000 порт. Ждём подключения conn, err := l.Accept() if err != nil { log.Fatal(err) } //К нам кто то подключился. Откроем для него свою горутину go func(c net.Conn) { //создаём буфер для получения данных из вне. buf := make([]byte, 1024) //открываем ещё один вечный цикл для того чтобы можно было получить n количество сообщений, // а не одно for { //Полученную информацию пишем в буфер c.Read(buf) log.Print(string(buf)) } }(conn) } }
Теперь запускаем наш сервер и в новом окошке терминала делаем как-то так:
Теперь нам надо распознавать команды. Сделаем мини api.
//типы лог сообщений
Debug|][|что писать в лог буфер->150 записей
Info|][|что писать в лог буфер->100 записей
Warn|][|что писать в лог буфер->50 записей
Error|][|что писать в лог буфер->25 записей
Fatal|][|что писать в лог буфер->0 записей
//данные с буфера переместить в бд
UnloadTheCacheDB|][|null
//очистить буфер не перемещая данные в бд
ClearCache|][|null
package main import ( "log" "net" "strings" ) func main() { l, err := net.Listen("tcp", ":2000") if err != nil { log.Fatal(err) } defer l.Close() for { conn, err := l.Accept() if err != nil { log.Fatal(err) } go func(c net.Conn) { buf := make([]byte, 1024) for { c.Read(buf) result := strings.Split(string(buf), "|][|") switch result[0] { case "Debug": log.Print("Debug log сообщение=" + result[1]) case "Info": log.Print("Info log сообщение=" + result[1]) case "Warn": log.Print("Warn log сообщение=" + result[1]) case "Error": log.Print("Error log сообщение=" + result[1]) case "Fatal": log.Print("Fatal log сообщение=" + result[1]) case "UnloadTheCacheDB": case "ClearCache": default: log.Print("case Default\n") c.Close() return } } c.Close() }(conn) } }
Команда == лог сообщения различаем.
Теперь у вас два пути. Прикрутить сюда мемкеш и писать в бд пачками из него, или сидеть и ждать следующей статьи, где будет исправлен конфликт между go рутинами.
Вот полный код. Работает всё отлично, правда, если в 1 поток. Как только разберусь с блокировкой данных, обновлю статью.
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" //можно подключить любую sql базу данных "log" "net" "net/smtp" "strings" "time" ) var DB *sql.DB var i_debug int = 0 var cacheDebug string var i_info int = 0 var cacheInfo string var i_warn int =0 var cacheWarn string var i_error int = 0 var cacheError string func init() { db, err := sql.Open("mysql", "db_user:db_pass@/logs_service") if err != nil { log.Fatal(err) } DB = db } func main() { l, err := net.Listen("tcp", ":2000") if err != nil { log.Fatal(err) } defer l.Close() for { conn, err := l.Accept() if err != nil { log.Fatal(err) } go func(c net.Conn) { buf := make([]byte, 1024) for { c.Read(buf) result := strings.Split(string(buf), "|][|") switch result[0] { case "Debug": if i_debug <= 300 { cacheDebug = cacheDebug + "('" + time.Now().String() + "','" + result[1] + "')" go DebugDB(cacheDebug) i_debug = 0 cacheDebug = " " } else { cacheDebug = cacheDebug + "('" + time.Now().String() + "','" + result[1] + "')," } i_debug++ case "Info": if i_info <= 150 { cacheInfo = cacheInfo + "('" + time.Now().String() + "','" + result[1] + "')" go InfoDB(cacheInfo) i_info = 0 cacheInfo = " " } else { cacheInfo = cacheInfo + "('" + time.Now().String() + "','" + result[1] + "')," } i_info++ case "Warn": if i_warn <= 50 { cacheWarn = cacheWarn + "('" + time.Now().String() + "','" + result[1] + "')" go WarnDB(cacheWarn) i_warn = 0 cacheWarn = " " } else { cacheWarn = cacheWarn + "('" + time.Now().String() + "','" + result[1] + "')," } i_warn++ case "Error": if i_error == 25 { cacheError = cacheError + "('" + time.Now().String() + "','" + result[1] + "')" go ErrorDB(cacheError) i_error = 0 cacheError = " " cacheError = cacheError + "('" + time.Now().String() + "','" + result[1] + "')," } i_error++ case "Fatal": go FatalDB(result[1]) case "UnloadTheCacheDB": go DebugDB(cacheDebug) go InfoDB(cacheInfo) go WarnDB(cacheWarn) go ErrorDB(cacheError) cacheDebug = " " cacheInfo = " " cacheWarn = " " cacheError = " " i_debug = 0 i_info = 0 i_warn = 0 i_error = 0 log.Print("Бд успешно обновленна, а кеш очищен") case "ClearCache": cacheDebug = " " cacheInfo = " " cacheWarn = " " cacheError = " " i_debug = 0 i_info = 0 i_warn = 0 i_error = 0 log.Print("Кеш успешно очистили") default: log.Print("case Default\n") c.Close() return } } }(conn) } } //просто пише в таблицы. func DebugDB(cache string) { DB.Exec("INSERT INTO debug (date,message) VALUES " + cache) return } func InfoDB(cache string) { DB.Exec("INSERT INTO info (date,message) VALUES " + cache) return } func WarnDB(cache string) { DB.Exec("INSERT INTO warn (date,message) VALUES " + cache) return } func ErrorDB(cache string) { DB.Exec("INSERT INTO error (date,message) VALUES " + cache) return } //А тут пишем в бд и отправляем email уведомление func FatalDB(message string) { DB.Exec("INSERT INTO fatal (date,message) VALUES (?,?)", time.Now().String(), message) conf := map[string]string{ "username": "example@gmail.com", //логин от любой почты на gamail "password": "example", //ну и пароль "host": "smtp.gmail.com", "port": "587", } to := []string{ "example99@gmail.com", "id324237193-6fce7d7ef@vkmessenger.com", } SendMail(conf, to, "Fatal Errors", message) return } func SendMail(conf map[string]string, to []string, subject string, msg string) { auth := smtp.PlainAuth( "", conf["username"], conf["password"], conf["host"], ) address := fmt.Sprintf("%v:%v", conf["host"], conf["port"]) body := []byte("Subject: " + subject + "\r\n\r\n" + msg) err := smtp.SendMail( address, auth, conf["username"], to, body, ) if err != nil { log.Fatal(err) } }
ссылка на оригинал статьи http://habrahabr.ru/post/270035/
Добавить комментарий