Это моя первая статья на Хабре, пишу её по ходу своего обучения. За подсказки буду очень благодарен.
Здесь автор говорит о том, какими должны быть логи. В своем цикле статей я покажу вам как можно сделать подобное логирование своими руками на GO.
Итак начнём. Для начала нам необходимо сделать простейший tcp сервер:
Теперь запускаем наш сервер и в новом окошке терминала делаем как-то так:
Теперь нам надо распознавать команды. Сделаем мини api.
//типы лог сообщений
Debug|][|что писать в лог буфер->150 записей
Info|][|что писать в лог буфер->100 записей
Warn|][|что писать в лог буфер->50 записей
Error|][|что писать в лог буфер->25 записей
Fatal|][|что писать в лог буфер->0 записей
//данные с буфера переместить в бд
UnloadTheCacheDB|][|null
//очистить буфер не перемещая данные в бд
ClearCache|][|null
Теперь код:
Команда == лог сообщения различаем.
Теперь у вас два пути. Прикрутить сюда мемкеш и писать в бд пачками из него, или сидеть и ждать следующей статьи, где будет исправлен конфликт между go рутинами.
Вот полный код. Работает всё отлично, правда, если в 1 поток. Как только разберусь с блокировкой данных, обновлю статью.
Здесь автор говорит о том, какими должны быть логи. В своем цикле статей я покажу вам как можно сделать подобное логирование своими руками на 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)
}
}
Теперь запускаем наш сервер и в новом окошке терминала делаем как-то так:
Посмотреть
Теперь нам надо распознавать команды. Сделаем мини 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)
}
}
gurinderu
Я просто оставлю это здесь
https://github.com/alecthomas/log4go
vGrabko99
Если всё уже есть то как мне попасть на хабр ?))