Browse Source

[rev] restruct code

main v0.1.12
loveckiy.ivan 6 months ago
parent
commit
dc7966ce67
  1. 321
      dep_impl.go
  2. 391
      file.go
  3. 1
      go.mod
  4. 13
      go.sum
  5. 34
      kafka.go
  6. 50
      logbox.go
  7. 88
      logger.go
  8. 7
      output.go
  9. 39
      vendor/git.lowcodeplatform.net/fabric/logbox-client/client.go
  10. 4
      vendor/modules.txt
  11. 193
      vfs.go

321
dep_impl.go

@ -1,321 +0,0 @@
// обертка для логирования, которая дополняем аттрибутами логируемого процесса logrus
// дополняем значениями, идентифицирующими запущенный сервис UID,Name,Service
package logger
import (
"context"
"fmt"
"io"
"os"
"strings"
"sync"
"time"
"git.lowcodeplatform.net/fabric/lib"
"github.com/sirupsen/logrus"
)
var logrusB = logrus.New()
type log struct {
// куда логируем? stdout/;*os.File на файл, в который будем писать логи
Output io.Writer `json:"output"`
//Debug:
// сообщения отладки, профилирования.
// В production системе обычно сообщения этого уровня включаются при первоначальном
// запуске системы или для поиска узких мест (bottleneck-ов).
//Info: - логировать процесс выполнения
// обычные сообщения, информирующие о действиях системы.
// Реагировать на такие сообщения вообще не надо, но они могут помочь, например,
// при поиске багов, расследовании интересных ситуаций итд.
//Warning: - логировать странные операции
// записывая такое сообщение, система пытается привлечь внимание обслуживающего персонала.
// Произошло что-то странное. Возможно, это новый тип ситуации, ещё не известный системе.
// Следует разобраться в том, что произошло, что это означает, и отнести ситуацию либо к
// инфо-сообщению, либо к ошибке. Соответственно, придётся доработать код обработки таких ситуаций.
//Error: - логировать ошибки
// ошибка в работе системы, требующая вмешательства. Что-то не сохранилось, что-то отвалилось.
// Необходимо принимать меры довольно быстро! Ошибки этого уровня и выше требуют немедленной записи в лог,
// чтобы ускорить реакцию на них. Нужно понимать, что ошибка пользователя – это не ошибка системы.
// Если пользователь ввёл в поле -1, где это не предполагалось – не надо писать об этом в лог ошибок.
//Panic: - логировать критические ошибки
// это особый класс ошибок. Такие ошибки приводят к неработоспособности системы в целом, или
// неработоспособности одной из подсистем. Чаще всего случаются фатальные ошибки из-за неверной конфигурации
// или отказов оборудования. Требуют срочной, немедленной реакции. Возможно, следует предусмотреть уведомление о таких ошибках по SMS.
// указываем уровни логирования Error/Warning/Debug/Info/Panic
//Trace: - логировать обработки запросов
// можно указывать через | разные уровени логирования, например Error|Warning
// можно указать All - логирование всех уровней
Levels string `json:"levels"`
// uid процесса (сервиса), который логируется (случайная величина)
UID string `json:"uid"`
// имя процесса (сервиса), который логируется
Name string `json:"name"`
// название сервиса (app/gui...)
Service string `json:"service"`
// директория сохранения логов
Dir string `json:"dir"`
// uid-конфигурации с которой был запущен процесс
Config string `json:"config"`
// интервал между проверками актуального файла логирования (для текущего дня)
IntervalReload time.Duration `json:"delay_reload"`
// интервал проверками на наличие файлов на удаление
IntervalClearFiles time.Duration `json:"interval_clear_files"`
// период хранения файлов лет-месяцев-дней (например: 0-1-0 - хранить 1 месяц)
PeriodSaveFiles string `json:"period_save_files"`
// путь к сервису отправки логов в хранилище (Logbox)
LogboxURL string
// интервал отправки (в промежутках сохраняем в буфер)
LogboxSendInterval time.Duration
File *os.File
mux *sync.Mutex
}
// ConfigLogger общий конфигуратор логирования
type ConfigLogger struct {
Level, Uid, Name, Srv, Config string
File ConfigFileLogger
Vfs ConfigVfsLogger
//Logbox ConfigLogboxLogger
Priority []string
}
type Log interface {
Trace(args ...interface{})
Debug(args ...interface{})
Info(args ...interface{})
Warning(args ...interface{})
Error(err error, args ...interface{})
Panic(err error, args ...interface{})
Exit(err error, args ...interface{})
Close()
}
func (l *log) Trace(args ...interface{}) {
if strings.Contains(l.Levels, "Trace") {
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
logrusB.SetLevel(logrus.TraceLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Trace(args...)
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Trace: %+v\n", args)
}
}
}
func (l *log) Debug(args ...interface{}) {
if strings.Contains(l.Levels, "Debug") {
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
// Only log the warning severity or above.
logrusB.SetLevel(logrus.DebugLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Debug(args...)
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Debug: %+v\n", args)
}
}
}
func (l *log) Info(args ...interface{}) {
if strings.Contains(l.Levels, "Info") {
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
logrusB.SetLevel(logrus.InfoLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Info(args...)
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Info: %+v\n", args)
}
}
}
func (l *log) Warning(args ...interface{}) {
if strings.Contains(l.Levels, "Warning") {
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
logrusB.SetLevel(logrus.WarnLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Warn(args...)
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Warn: %+v\n", args)
}
}
}
func (l *log) Error(err error, args ...interface{}) {
if err != nil {
if args != nil {
args = append(args, "; error:", err)
} else {
args = append(args, "error:", err)
}
}
if strings.Contains(l.Levels, "Error") {
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
logrusB.SetLevel(logrus.ErrorLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Error(args...)
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Error: %+v\n", args)
}
}
}
func (l *log) Panic(err error, args ...interface{}) {
if err != nil {
if args != nil {
args = append(args, "; error:", err)
} else {
args = append(args, "error:", err)
}
}
if strings.Contains(l.Levels, "Panic") {
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Panic: %+v\n", args)
}
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
logrusB.SetLevel(logrus.PanicLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Panic(args...)
}
}
// Exit внутренняя ф-ция логирования и прекращения работы программы
func (l *log) Exit(err error, args ...interface{}) {
if err != nil {
if args != nil {
args = append(args, "; error:", err)
} else {
args = append(args, "error:", err)
}
}
if strings.Contains(l.Levels, "Fatal") {
if strings.Contains(l.Levels, "Stdout") {
fmt.Printf("Exit: %+v\n", args)
}
logrusB.SetOutput(l.Output)
logrusB.SetFormatter(&logrus.JSONFormatter{})
logrusB.SetLevel(logrus.FatalLevel)
logrusB.WithFields(logrus.Fields{
"name": l.Name,
"uid": l.UID,
"srv": l.Service,
"config": l.Config,
}).Fatal(args...)
}
}
func (l *log) Close() {
l.File.Close()
}
func NewLogger(ctx context.Context, cfg ConfigLogger) (logger Log, initType string, err error) {
var errI error
err = fmt.Errorf("logger init")
for _, v := range cfg.Priority {
if v == "file" && err != nil {
// если путь указан относительно / значит задан абсолютный путь, иначе в директории
if cfg.File.Dir[:1] != sep {
rootDir, _ := lib.RootDir()
cfg.File.Dir = rootDir + sep + "logs" + sep + cfg.File.Dir
}
// инициализировать лог и его ротацию
logger, errI = NewFileLogger(ctx, cfg)
if errI != nil {
err = fmt.Errorf("%s %s failed init files-logger, (err: %s)", err, "→", errI)
fmt.Println(err, cfg)
} else {
initType = v
err = nil
}
}
if v == "vfs" && err != nil {
// инициализировать лог и его ротацию
vs := strings.Split(cfg.Vfs.Dir, sep) // берем только последнее значение в пути для vfs-логера
vs = vs[len(vs)-1:]
if len(vs) != 0 {
cfg.Vfs.Dir = "logs"
}
// инициализировать лог и его ротацию
logger, errI = NewVfsLogger(ctx, cfg)
fmt.Println(logger, errI)
if errI != nil {
err = fmt.Errorf("%s %s failed init files-vfs, (err: %s)", err, "→", errI)
fmt.Println(err, cfg)
} else {
initType = v
err = nil
}
}
//if v == "logbox" && err != nil {
// // инициализировать лог и его ротацию
// logger, errI = NewLogboxLogger(ctx, cfg)
// if errI != nil {
// err = fmt.Errorf("%s %s failed init files-logbox, (err: %s)", err, "→", errI)
// } else {
// initType = v
// err = nil
// }
//}
}
return logger, initType, err
}

391
file.go

@ -1,196 +1,199 @@
package logger
import (
"context"
"fmt"
"io"
"os"
"runtime/debug"
"strconv"
"strings"
"sync"
"time"
"git.lowcodeplatform.net/fabric/lib"
"github.com/sirupsen/logrus"
)
type ConfigFileLogger struct {
Dir string
IntervalReload, IntervalClearFiles time.Duration
PeriodSaveFiles string
}
// вспомогательная фукнция очистки старых файлов для файлового логера
func (l *log) fileLoggerClearing(ctx context.Context) {
// попытка очистки старых файлов (каждые пол часа)
go func() {
ticker := time.NewTicker(l.IntervalClearFiles)
defer ticker.Stop()
// получаем период, через который мы будем удалять файлы
period := l.PeriodSaveFiles
if period == "" {
l.Error(fmt.Errorf("%s", "Fail perion save log files. (expected format: year-month-day; eg: 0-1-0)"))
return
}
slPeriod := strings.Split(period, "-")
if len(slPeriod) < 3 {
l.Error(fmt.Errorf("%s", "Fail perion save log files. (expected format: year-month-day; eg: 0-1-0)"))
return
}
// получаем числовые значения года месяца и дня для расчета даты удаления файлов
year, err := strconv.Atoi(slPeriod[0])
if err != nil {
l.Error(err, "Fail converted Year from period saved log files. (expected format: year-month-day; eg: 0-1-0)")
}
month, err := strconv.Atoi(slPeriod[1])
if err != nil {
l.Error(err, "Fail converted Month from period saved log files. (expected format: year-month-day; eg: 0-1-0)")
}
day, err := strconv.Atoi(slPeriod[2])
if err != nil {
l.Error(err, "Fail converted Day from period saved log files. (expected format: year-month-day; eg: 0-1-0)")
}
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
oneMonthAgo := time.Now().AddDate(-year, -month, -day) // minus 1 месяц
fileMonthAgoDate := oneMonthAgo.Format("2006.01.02")
// пробегаем директорию и читаем все файлы, если имя меньше текущее время - месяц = удаляем
directory, _ := os.Open(l.Dir)
objects, err := directory.Readdir(-1)
if err != nil {
l.Error(err, "Error read directory: ", directory)
return
}
for _, obj := range objects {
filename := obj.Name()
filenameMonthAgoDate := fileMonthAgoDate + "_" + l.Service
if filenameMonthAgoDate > filename {
pathFile := l.Dir + sep + filename
err = os.Remove(pathFile)
if err != nil {
l.Error(err, "Error deleted file: ", pathFile)
return
}
}
}
ticker = time.NewTicker(l.IntervalClearFiles)
}
}
}()
}
// NewFileLogger инициируем логер, которых хранит логи в файлах по указанному пути
func NewFileLogger(ctx context.Context, cfg ConfigLogger) (Log, error) {
var output io.Writer
var file *os.File
var err error
var mode os.FileMode
m := sync.Mutex{}
l := &log{
Output: output,
Levels: cfg.Level,
UID: cfg.Uid,
Name: cfg.Name,
Service: cfg.Srv,
Config: cfg.Config,
Dir: cfg.File.Dir,
IntervalReload: cfg.File.IntervalReload,
IntervalClearFiles: cfg.File.IntervalClearFiles,
PeriodSaveFiles: cfg.File.PeriodSaveFiles,
mux: &m,
File: file,
}
datefile := time.Now().Format("2006.01.02")
logName := datefile + "_" + cfg.Srv + "_" + cfg.Uid + ".log"
fmt.Println(logName)
// создаем/открываем файл логирования и назначаем его логеру
mode = 0711
err = lib.CreateDir(cfg.File.Dir, mode)
if err != nil {
logrus.Error(err, "Error creating directory")
return nil, err
}
pathFile := cfg.File.Dir + "/" + logName
if !lib.IsExist(pathFile) {
err = lib.CreateFile(pathFile)
if err != nil {
logrus.Error(err, "Error creating file")
return nil, err
}
}
file, err = os.OpenFile(pathFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
defer file.Close()
l.File = file
l.Output = file
if err != nil {
logrus.Panic(err, "error opening file")
return nil, err
}
defer func() {
rec := recover()
if rec != nil {
b := string(debug.Stack())
fmt.Printf("panic in loggier (RotateInit). stack: %+v", b)
//cancel()
//os.Exit(1)
}
}()
// попытка обновить файл (раз в 10 минут)
go func() {
ticker := time.NewTicker(l.IntervalReload)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
l.File.Close() // закрыл старый файл
datefile = time.Now().Format("2006.01.02")
logName = datefile + "_" + cfg.Srv + "_" + cfg.Uid + ".log"
pathFile = cfg.File.Dir + "/" + logName
if !lib.IsExist(pathFile) {
err := lib.CreateFile(pathFile)
if err != nil {
logrus.Error(err, "Error creating file")
return
}
}
file, err = os.OpenFile(pathFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
logrus.Panic(err, "error opening file")
return
}
output = file
l.Output = output
l.File = file
ticker = time.NewTicker(l.IntervalReload)
}
}
}()
l.fileLoggerClearing(ctx)
return l, err
}
//
//import (
// "context"
// "fmt"
// "io"
// "os"
// "runtime/debug"
// "strconv"
// "strings"
// "sync"
// "time"
//
// "git.lowcodeplatform.net/fabric/lib"
// "github.com/sirupsen/logrus"
//)
//
//const sep = string(os.PathSeparator)
//
//type ConfigFileLogger struct {
// Dir string
// IntervalReload, IntervalClearFiles time.Duration
// PeriodSaveFiles string
//}
//
//// вспомогательная фукнция очистки старых файлов для файлового логера
//func (l *log) fileLoggerClearing(ctx context.Context) {
//
// // попытка очистки старых файлов (каждые пол часа)
// go func() {
// ticker := time.NewTicker(l.IntervalClearFiles)
// defer ticker.Stop()
//
// // получаем период, через который мы будем удалять файлы
// period := l.PeriodSaveFiles
// if period == "" {
// l.Error(fmt.Errorf("%s", "Fail perion save log files. (expected format: year-month-day; eg: 0-1-0)"))
// return
// }
// slPeriod := strings.Split(period, "-")
// if len(slPeriod) < 3 {
// l.Error(fmt.Errorf("%s", "Fail perion save log files. (expected format: year-month-day; eg: 0-1-0)"))
// return
// }
//
// // получаем числовые значения года месяца и дня для расчета даты удаления файлов
// year, err := strconv.Atoi(slPeriod[0])
// if err != nil {
// l.Error(err, "Fail converted Year from period saved log files. (expected format: year-month-day; eg: 0-1-0)")
// }
// month, err := strconv.Atoi(slPeriod[1])
// if err != nil {
// l.Error(err, "Fail converted Month from period saved log files. (expected format: year-month-day; eg: 0-1-0)")
// }
// day, err := strconv.Atoi(slPeriod[2])
// if err != nil {
// l.Error(err, "Fail converted Day from period saved log files. (expected format: year-month-day; eg: 0-1-0)")
// }
//
// for {
// select {
// case <-ctx.Done():
// return
// case <-ticker.C:
// oneMonthAgo := time.Now().AddDate(-year, -month, -day) // minus 1 месяц
// fileMonthAgoDate := oneMonthAgo.Format("2006.01.02")
//
// // пробегаем директорию и читаем все файлы, если имя меньше текущее время - месяц = удаляем
// directory, _ := os.Open(l.Dir)
// objects, err := directory.Readdir(-1)
// if err != nil {
// l.Error(err, "Error read directory: ", directory)
// return
// }
//
// for _, obj := range objects {
// filename := obj.Name()
// filenameMonthAgoDate := fileMonthAgoDate + "_" + l.Service
//
// if filenameMonthAgoDate > filename {
// pathFile := l.Dir + sep + filename
// err = os.Remove(pathFile)
// if err != nil {
// l.Error(err, "Error deleted file: ", pathFile)
// return
// }
// }
// }
// ticker = time.NewTicker(l.IntervalClearFiles)
// }
// }
// }()
//}
//
//// NewFileLogger инициируем логер, которых хранит логи в файлах по указанному пути
//func NewFileLogger(ctx context.Context, cfg ConfigLogger) (Log, error) {
// var output io.Writer
// var file *os.File
// var err error
// var mode os.FileMode
// m := sync.Mutex{}
//
// l := &log{
// Output: output,
// Levels: cfg.Level,
// UID: cfg.Uid,
// Name: cfg.Name,
// Service: cfg.Srv,
// Config: cfg.Config,
// Dir: cfg.File.Dir,
// IntervalReload: cfg.File.IntervalReload,
// IntervalClearFiles: cfg.File.IntervalClearFiles,
// PeriodSaveFiles: cfg.File.PeriodSaveFiles,
// mux: &m,
// File: file,
// }
//
// datefile := time.Now().Format("2006.01.02")
// logName := datefile + "_" + cfg.Srv + "_" + cfg.Uid + ".log"
//
// fmt.Println(logName)
//
// // создаем/открываем файл логирования и назначаем его логеру
// mode = 0711
// err = lib.CreateDir(cfg.File.Dir, mode)
// if err != nil {
// logrus.Error(err, "Error creating directory")
// return nil, err
// }
//
// pathFile := cfg.File.Dir + "/" + logName
// if !lib.IsExist(pathFile) {
// err = lib.CreateFile(pathFile)
// if err != nil {
// logrus.Error(err, "Error creating file")
// return nil, err
// }
// }
//
// file, err = os.OpenFile(pathFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
// defer file.Close()
//
// l.File = file
// l.Output = file
// if err != nil {
// logrus.Panic(err, "error opening file")
// return nil, err
// }
//
// defer func() {
// rec := recover()
// if rec != nil {
// b := string(debug.Stack())
// fmt.Printf("panic in loggier (RotateInit). stack: %+v", b)
// //cancel()
// //os.Exit(1)
// }
// }()
//
// // попытка обновить файл (раз в 10 минут)
// go func() {
// ticker := time.NewTicker(l.IntervalReload)
// defer ticker.Stop()
//
// for {
// select {
// case <-ctx.Done():
// return
// case <-ticker.C:
// l.File.Close() // закрыл старый файл
// datefile = time.Now().Format("2006.01.02")
// logName = datefile + "_" + cfg.Srv + "_" + cfg.Uid + ".log"
// pathFile = cfg.File.Dir + "/" + logName
// if !lib.IsExist(pathFile) {
// err := lib.CreateFile(pathFile)
// if err != nil {
// logrus.Error(err, "Error creating file")
// return
// }
// }
//
// file, err = os.OpenFile(pathFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
// if err != nil {
// logrus.Panic(err, "error opening file")
// return
// }
//
// output = file
// l.Output = output
// l.File = file
// ticker = time.NewTicker(l.IntervalReload)
// }
// }
// }()
// l.fileLoggerClearing(ctx)
//
// return l, err
//}

1
go.mod

@ -62,6 +62,7 @@ require (
github.com/satori/go.uuid v1.2.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/urfave/cli v1.22.10 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect

13
go.sum

@ -42,23 +42,12 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI=
cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.lowcodeplatform.net/fabric/lib v0.1.52 h1:qTlv9p9jq9VGCNhuwRIwr3bzsYgdvFUT+sV1rUnKVGA=
git.lowcodeplatform.net/fabric/lib v0.1.52/go.mod h1:l+MnEjJvSbMX/g20BH5Wqh42cpj3xc2dORHSI1Mqra0=
git.lowcodeplatform.net/fabric/lib v0.1.59 h1:qKU5Drk58Vz8tm7rEYyDaviVEGV14vGL522GUDxh0BU=
git.lowcodeplatform.net/fabric/lib v0.1.59/go.mod h1:l+MnEjJvSbMX/g20BH5Wqh42cpj3xc2dORHSI1Mqra0=
git.lowcodeplatform.net/fabric/logbox v0.1.3 h1:2dcC3OSO+g9cTPWSNcXVPOmPw0FaQotzz/xz9imkdD0=
git.lowcodeplatform.net/fabric/logbox v0.1.3/go.mod h1:krjPWdYdwm0D9BqFy67FDJH9/j54UiJTKr8pmVuz938=
git.lowcodeplatform.net/fabric/logbox-client v0.1.5 h1:CLP7n4s7UUClAQ/ZfXGaWq3romCN5odoNHatNY88itA=
git.lowcodeplatform.net/fabric/logbox-client v0.1.5/go.mod h1:z6vzie+FDEeOLJQFhHtNeTDUv7UvDmZW4U+3lT5Et0w=
git.lowcodeplatform.net/fabric/logbox-client v0.1.6 h1:xSf6DcvT8tOi+vPD0zbIwwAKVF4ayfpRmm2mtEgLFjs=
git.lowcodeplatform.net/fabric/logbox-client v0.1.6/go.mod h1:z6vzie+FDEeOLJQFhHtNeTDUv7UvDmZW4U+3lT5Et0w=
<<<<<<< HEAD
git.lowcodeplatform.net/fabric/logbox-client v0.1.9 h1:x/E6srcdZ410TYHwmivyIm3wdJ9KctfKyym3sDeB5rs=
git.lowcodeplatform.net/fabric/logbox-client v0.1.9/go.mod h1:4Z0QYhBgEH3eD6WEui5QtHAR+sGZA5NO+aQIDR4FGHc=
=======
git.lowcodeplatform.net/fabric/logbox-client v0.1.7 h1:toGc1cfZTCrGmFBrnMQQbFhtCxVt77c2Cgt7iJZzqL0=
git.lowcodeplatform.net/fabric/logbox-client v0.1.7/go.mod h1:z6vzie+FDEeOLJQFhHtNeTDUv7UvDmZW4U+3lT5Et0w=
>>>>>>> 344c8fda82f2e61c6cde58cfa1b4ea7e3f61d4de
git.lowcodeplatform.net/fabric/models v0.1.14 h1:8vdkKEnyh6jm8Iw3eB6t3vrMKcTU9L668eedLu93EXk=
git.lowcodeplatform.net/fabric/models v0.1.14/go.mod h1:RSR+ysusHS7bhYOCDuWbkuGQkFL0Mum4r/FXPzStUQQ=
git.lowcodeplatform.net/packages/grpcbalancer v0.0.0-20230625153511-db2331a573d5 h1:bQ4r7z77sROu4I4Ra/ja30AQeAINL7YQdcynOPBxA0s=
@ -322,6 +311,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=

34
kafka.go

@ -9,6 +9,7 @@ import (
"github.com/pkg/errors"
"github.com/segmentio/kafka-go"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type KafkaConfig struct {
@ -111,3 +112,36 @@ type errorLogger struct {
func (l *errorLogger) Printf(msg string, args ...interface{}) {
l.Error(fmt.Sprintf(msg, args...))
}
func SetupDefaultKafkaLogger(namespace string, cfg KafkaConfig) error {
if len(cfg.Addr) == 0 {
return errors.New("kafka address must be specified")
}
if err := cfg.createTopic(); err != nil {
return errors.Wrapf(err, "cannot create topic: %s", cfg.Topic)
}
errorLogger := initLogger(WithStringCasting())
ws := &writerSyncer{
kwr: cfg.writer(errorLogger),
topic: cfg.Topic,
errorLogger: errorLogger,
}
enc := newStringCastingEncoder(zap.NewProductionEncoderConfig())
core := zapcore.NewCore(enc, ws, zap.NewAtomicLevelAt(zap.InfoLevel))
errOut, _, err := zap.Open("stderr")
if err != nil {
return err
}
opts := []zap.Option{zap.ErrorOutput(errOut), zap.AddCaller()}
logger := zap.New(core, opts...)
defaultLogger = New(logger.Named(namespace))
return nil
}

50
logbox.go

@ -7,9 +7,28 @@ import (
"fmt"
"time"
"github.com/pkg/errors"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
logboxclient "git.lowcodeplatform.net/fabric/logbox-client"
)
// LogLine структура строк лог-файла. нужна для анмаршалинга
type LogLine struct {
Uid string `json:"uid"`
Level string `json:"level"`
Name string `json:"logger"`
Type string `json:"service-type"`
Time string `json:"ts"`
Timing string `json:"timing"`
ConfigID string `json:"config-id"`
RequestID string `json:"request-id"`
ServiceID string `json:"service-id"`
Msg interface{} `json:"msg"`
}
type LogboxConfig struct {
Endpoint, AccessKeyID, SecretKey string
RequestTimeout time.Duration
@ -68,3 +87,34 @@ func (v *logboxSender) Write(p []byte) (n int, err error) {
func (v *logboxSender) Sync() error {
return v.logboxClient.Close()
}
// SetupDefaultLogboxLogger инициируем логирование в сервис Logbox
func SetupDefaultLogboxLogger(namespace string, cfg LogboxConfig, options map[string]string) error {
if len(cfg.Endpoint) == 0 {
return errors.New("logbox address must be specified")
}
// инициализировать лог и его ротацию
ws := &logboxSender{
requestTimeout: cfg.RequestTimeout,
logboxClient: cfg.client(context.Background()),
}
enc := newStringCastingEncoder(zap.NewProductionEncoderConfig())
core := zapcore.NewCore(enc, ws, zap.NewAtomicLevelAt(zap.InfoLevel))
errOut, _, err := zap.Open("stderr")
if err != nil {
return err
}
opts := []zap.Option{zap.ErrorOutput(errOut), zap.AddCaller()}
for k, v := range options {
opts = append(opts, zap.Fields(zap.String(k, v)))
}
logger := zap.New(core, opts...)
defaultLogger = New(logger.Named(namespace))
return nil
}

88
logger.go

@ -2,11 +2,9 @@ package logger
import (
"context"
"os"
"strings"
"sync"
"github.com/pkg/errors"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
@ -17,96 +15,10 @@ var (
onceLevelObserver sync.Once
)
const sep = string(os.PathSeparator)
// LogLine структура строк лог-файла. нужна для анмаршалинга
type LogLine struct {
Uid string `json:"uid"`
Level string `json:"level"`
Name string `json:"logger"`
Type string `json:"service-type"`
Time string `json:"ts"`
Timing string `json:"timing"`
ConfigID string `json:"config-id"`
RequestID string `json:"request-id"`
ServiceID string `json:"service-id"`
Msg interface{} `json:"msg"`
}
type Engine struct {
*zap.Logger
}
//goland:noinspection GoUnusedExportedFunction
func SetupDefaultLogger(namespace string, options ...ConfigOption) {
logger := initLogger(options...)
defaultLogger = New(logger.Named(namespace))
}
func SetupDefaultKafkaLogger(namespace string, cfg KafkaConfig) error {
if len(cfg.Addr) == 0 {
return errors.New("kafka address must be specified")
}
if err := cfg.createTopic(); err != nil {
return errors.Wrapf(err, "cannot create topic: %s", cfg.Topic)
}
errorLogger := initLogger(WithStringCasting())
ws := &writerSyncer{
kwr: cfg.writer(errorLogger),
topic: cfg.Topic,
errorLogger: errorLogger,
}
enc := newStringCastingEncoder(zap.NewProductionEncoderConfig())
core := zapcore.NewCore(enc, ws, zap.NewAtomicLevelAt(zap.InfoLevel))
errOut, _, err := zap.Open("stderr")
if err != nil {
return err
}
opts := []zap.Option{zap.ErrorOutput(errOut), zap.AddCaller()}
logger := zap.New(core, opts...)
defaultLogger = New(logger.Named(namespace))
return nil
}
// SetupDefaultLogboxLogger инициируем логирование в сервис Logbox
func SetupDefaultLogboxLogger(namespace string, cfg LogboxConfig, options map[string]string) error {
if len(cfg.Endpoint) == 0 {
return errors.New("logbox address must be specified")
}
// инициализировать лог и его ротацию
ws := &logboxSender{
requestTimeout: cfg.RequestTimeout,
logboxClient: cfg.client(context.Background()),
}
enc := newStringCastingEncoder(zap.NewProductionEncoderConfig())
core := zapcore.NewCore(enc, ws, zap.NewAtomicLevelAt(zap.InfoLevel))
errOut, _, err := zap.Open("stderr")
if err != nil {
return err
}
opts := []zap.Option{zap.ErrorOutput(errOut), zap.AddCaller()}
for k, v := range options {
opts = append(opts, zap.Fields(zap.String(k, v)))
}
logger := zap.New(core, opts...)
defaultLogger = New(logger.Named(namespace))
return nil
}
func Logger(ctx context.Context) *Engine {
if defaultLogger == nil {
panic("logger has not been initialized, call SetupDefaultLogger() before use")

7
output.go

@ -0,0 +1,7 @@
package logger
//goland:noinspection GoUnusedExportedFunction
func SetupDefaultLogger(namespace string, options ...ConfigOption) {
logger := initLogger(options...)
defaultLogger = New(logger.Named(namespace))
}

39
vendor/git.lowcodeplatform.net/fabric/logbox-client/client.go

@ -6,6 +6,13 @@ import (
"time"
"git.lowcodeplatform.net/packages/grpcbalancer"
"github.com/google/uuid"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
const (
requestIDField string = "request-id"
)
var timeoutDefault = 1 * time.Second
@ -40,6 +47,7 @@ func New(ctx context.Context, url string, reqTimeout time.Duration) (Client, err
grpcbalancer.WithUrls(url),
grpcbalancer.WithInsecure(),
grpcbalancer.WithTimeout(reqTimeout),
grpcbalancer.WithChainUnaryInterceptors(GRPCUnaryClientInterceptor),
)
if err != nil {
fmt.Printf("failed init grpcbalancer, err: %s", err)
@ -58,3 +66,34 @@ func New(ctx context.Context, url string, reqTimeout time.Duration) (Client, err
client: b,
}, err
}
func GRPCUnaryClientInterceptor(
ctx context.Context,
method string,
req interface{},
reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
var requestID string
requestID = GetRequestIDCtx(ctx, requestIDField)
if requestID == "" {
requestID = uuid.New().String()
}
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs("x-request-id", requestID))
err := invoker(ctx, method, req, reply, cc, opts...)
return err
}
func GetRequestIDCtx(ctx context.Context, name string) string {
nameKey := "logger." + name
requestID, _ := ctx.Value(nameKey).(string)
return requestID
}

4
vendor/modules.txt

@ -27,7 +27,7 @@ git.lowcodeplatform.net/fabric/lib/pkg/s3
# git.lowcodeplatform.net/fabric/logbox v0.1.3
## explicit; go 1.18
git.lowcodeplatform.net/fabric/logbox/pkg/model/sdk
# git.lowcodeplatform.net/fabric/logbox-client v0.1.7
# git.lowcodeplatform.net/fabric/logbox-client v0.1.9
## explicit; go 1.18
git.lowcodeplatform.net/fabric/logbox-client
# git.lowcodeplatform.net/fabric/models v0.1.14
@ -307,6 +307,8 @@ github.com/shurcooL/sanitized_anchor_name
# github.com/sirupsen/logrus v1.9.3
## explicit; go 1.13
github.com/sirupsen/logrus
# github.com/sony/gobreaker v0.5.0
## explicit; go 1.12
# github.com/urfave/cli v1.22.10
## explicit; go 1.11
github.com/urfave/cli

193
vfs.go

@ -1,98 +1,99 @@
package logger
import (
"bytes"
"context"
"io"
"sync"
"time"
"git.lowcodeplatform.net/fabric/lib"
)
type ConfigVfsLogger struct {
Kind, Endpoint, AccessKeyID, SecretKey, Region, Bucket, Comma, CACert string
Dir string
IntervalReload time.Duration
}
// NewVfsLogger инициализация отправки логов на сервер сбора
// ВНИМАНИЕ! крайне неэффективно
// при добавлении лога выкачивется весь файл лога, добавляется строка и перезаписывается
func NewVfsLogger(ctx context.Context, cfg ConfigLogger) (logger Log, err error) {
var output io.Writer
m := sync.Mutex{}
vfs := lib.NewVfs(cfg.Vfs.Kind, cfg.Vfs.Endpoint, cfg.Vfs.AccessKeyID, cfg.Vfs.SecretKey, cfg.Vfs.Region, cfg.Vfs.Bucket, cfg.Vfs.Comma, cfg.Vfs.CACert)
err = vfs.Connect()
if err != nil {
return nil, err
}
sender := newVfsSender(ctx, vfs, cfg.Vfs.Dir, cfg.Srv, cfg.Uid, cfg.Vfs.IntervalReload)
output = sender
l := &log{
Output: output,
Levels: cfg.Level,
UID: cfg.Uid,
Name: cfg.Name,
Service: cfg.Srv,
IntervalReload: cfg.Vfs.IntervalReload,
mux: &m,
}
return l, nil
}
type vfsSender struct {
vfsStorage lib.Vfs
file string
}
func (v *vfsSender) Write(p []byte) (n int, err error) {
dataFile, _, err := v.vfsStorage.Read(v.file)
concatSlices := [][]byte{
dataFile,
p,
}
resultSlice := bytes.Join(concatSlices, []byte(""))
err = v.vfsStorage.Write(v.file, resultSlice)
if err != nil {
return 0, err
}
return len(p), nil
}
func newVfsSender(ctx context.Context, vfsStorage lib.Vfs, dir, srv, uid string, intervalReload time.Duration) io.Writer {
sender := &vfsSender{
vfsStorage,
"",
}
//datefile := time.Now().Format("2006.01.02")
datefile := time.Now().Format("2006.01.02")
sender.file = "/" + dir + "/" + datefile + "_" + srv + "_" + uid + ".log"
// попытка обновить файл (раз в 10 минут)
go func() {
ticker := time.NewTicker(intervalReload)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
datefile = time.Now().Format("2006.01.02")
sender.file = "/" + dir + "/" + datefile + "_" + srv + "_" + uid + ".log"
ticker = time.NewTicker(intervalReload)
}
}
}()
return sender
}
//
//import (
// "bytes"
// "context"
// "io"
// "sync"
// "time"
//
// "git.lowcodeplatform.net/fabric/lib"
//)
//
//type ConfigVfsLogger struct {
// Kind, Endpoint, AccessKeyID, SecretKey, Region, Bucket, Comma, CACert string
// Dir string
// IntervalReload time.Duration
//}
//
//// NewVfsLogger инициализация отправки логов на сервер сбора
//// ВНИМАНИЕ! крайне неэффективно
//// при добавлении лога выкачивется весь файл лога, добавляется строка и перезаписывается
//func NewVfsLogger(ctx context.Context, cfg ConfigVfsLogger) (logger Log, err error) {
// var output io.Writer
// m := sync.Mutex{}
//
// vfs := lib.NewVfs(cfg.Vfs.Kind, cfg.Vfs.Endpoint, cfg.Vfs.AccessKeyID, cfg.Vfs.SecretKey, cfg.Vfs.Region, cfg.Vfs.Bucket, cfg.Vfs.Comma, cfg.Vfs.CACert)
// err = vfs.Connect()
// if err != nil {
// return nil, err
// }
//
// sender := newVfsSender(ctx, vfs, cfg.Vfs.Dir, cfg.Srv, cfg.Uid, cfg.Vfs.IntervalReload)
// output = sender
//
// l := &log{
// Output: output,
// Levels: cfg.Level,
// UID: cfg.Uid,
// Name: cfg.Name,
// Service: cfg.Srv,
// IntervalReload: cfg.Vfs.IntervalReload,
// mux: &m,
// }
//
// return l, nil
//}
//
//type vfsSender struct {
// vfsStorage lib.Vfs
// file string
//}
//
//func (v *vfsSender) Write(p []byte) (n int, err error) {
// dataFile, _, err := v.vfsStorage.Read(v.file)
// concatSlices := [][]byte{
// dataFile,
// p,
// }
// resultSlice := bytes.Join(concatSlices, []byte(""))
//
// err = v.vfsStorage.Write(v.file, resultSlice)
// if err != nil {
// return 0, err
// }
// return len(p), nil
//}
//
//func newVfsSender(ctx context.Context, vfsStorage lib.Vfs, dir, srv, uid string, intervalReload time.Duration) io.Writer {
//
// sender := &vfsSender{
// vfsStorage,
// "",
// }
//
// //datefile := time.Now().Format("2006.01.02")
// datefile := time.Now().Format("2006.01.02")
// sender.file = "/" + dir + "/" + datefile + "_" + srv + "_" + uid + ".log"
//
// // попытка обновить файл (раз в 10 минут)
// go func() {
// ticker := time.NewTicker(intervalReload)
// defer ticker.Stop()
//
// for {
// select {
// case <-ctx.Done():
// return
// case <-ticker.C:
// datefile = time.Now().Format("2006.01.02")
//
// sender.file = "/" + dir + "/" + datefile + "_" + srv + "_" + uid + ".log"
// ticker = time.NewTicker(intervalReload)
// }
// }
// }()
//
// return sender
//}

Loading…
Cancel
Save