// package slog_file -- бекенд для вывода в файл package slog_file import ( "fmt" // "log" "os" "sync" "time" "wartank/pkg/components/safebool" "wartank/pkg/cons" "wartank/pkg/types" ) const ( threadName = "slog_file" ) // SlogFile -- бэкенд для вывода в файл type SlogFile struct { kern types.IKernel file *os.File fileName string isWork *safebool.SafeBool chMsg chan []byte // канал входящих сообщений block sync.Mutex } // NewSlogFile -- возвращает новый бэкенд логгера для вывода в файл func NewSlogFile(kern types.IKernel, build string) (*SlogFile, error) { { // Предусловия if kern == nil { return nil, fmt.Errorf("NewSlogFile(): IKernel is nil") } if build == "" { return nil, fmt.Errorf("NewSlogFile(): strBuild is empty") } } sf := &SlogFile{ kern: kern, fileName: cons.SelfName + "_" + build + time.Now().UTC().Format("_2006-01-02 15:04:05.000") + ".log", isWork: safebool.NewSafeBool(), chMsg: make(chan []byte, 10), } sf.isWork.Set() _ = os.MkdirAll("./log", 0700) sf.fileName = "./log/" + sf.fileName if err := sf.open(); err != nil { return nil, fmt.Errorf("NewSlogFile(): in open log-file, err=%w", err) } sf.kern.Wg().Add(threadName) go sf.run() return sf, nil } // Открывает файл на запись func (sf *SlogFile) open() error { file, err := os.OpenFile(sf.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if err != nil { sf.kern.CancelApp() return fmt.Errorf("NewSlogFile.open(): in open %q, err=%w", sf.fileName, err) } sf.file = file return nil } // Запускает работу в отдельном потоке func (sf *SlogFile) run() { defer func() { sf.isWork.Reset() sf.block.Lock() defer sf.block.Unlock() _ = sf.file.Close() close(sf.chMsg) sf.kern.Wg().Done(threadName) // log._rintf("SlogFile.run(): end work\n") sf.kern.CancelApp() }() for { select { case <-sf.kern.Done(): // Ожидание отмены контекста приложения return case msg := <-sf.chMsg: if err := sf.write(msg); err != nil { sf.kern.Slog().Errorf("SlogFile.run(): in write msg, err=\n\t%v", err) return } } } } // Внцтренни вызов записи func (sf *SlogFile) write(msg []byte) error { _, err := sf.file.Write(msg) if err != nil { return fmt.Errorf("SlogFile.run(): in write file %q, err=\n\t%w", sf.fileName, err) } return nil } // Write -- записывает данные в файл func (sf *SlogFile) Write(msg string) { if !sf.isWork.Get() { return } sf.block.Lock() defer sf.block.Unlock() sf.chMsg <- []byte(msg) }