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