Своя система логгирования на GO в 5 уровней

от автора

Это моя первая статья на Хабре, пишу её по ходу своего обучения. За подсказки буду очень благодарен.

Здесь автор говорит о том, какими должны быть логи. В своем цикле статей я покажу вам как можно сделать подобное логирование своими руками на GO.

Итак начнём. Для начала нам необходимо сделать простейший tcp сервер:

tcp сервер на golang

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) 	} } 

Теперь запускаем наш сервер и в новом окошке терминала делаем как-то так:

Посмотреть

image

Теперь нам надо распознавать команды. Сделаем мини 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) 	} } 

Команда == лог сообщения различаем.

Посмотреть

image

Теперь у вас два пути. Прикрутить сюда мемкеш и писать в бд пачками из него, или сидеть и ждать следующей статьи, где будет исправлен конфликт между 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *