slog_file.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // package slog_file -- бекенд для вывода в файл
  2. package slog_file
  3. import (
  4. "fmt"
  5. "log"
  6. "os"
  7. "sync"
  8. "time"
  9. "wartank/pkg/components/safe_bool"
  10. "wartank/pkg/cons"
  11. "wartank/pkg/types"
  12. )
  13. const (
  14. threadName = "slog_file"
  15. )
  16. // СлогФайл -- бэкенд для вывода в файл
  17. type СлогФайл struct {
  18. kern types.ИЯдро
  19. file *os.File
  20. fileName string
  21. isWork *safe_bool.БезопБул
  22. chMsg chan []byte // канал входящих сообщений
  23. block sync.Mutex
  24. }
  25. // НовСлогФайл -- возвращает новый бэкенд логгера для вывода в файл
  26. func НовСлогФайл(kern types.ИЯдро, build string) (*СлогФайл, error) {
  27. { // Предусловия
  28. if kern == nil {
  29. return nil, fmt.Errorf("НовСлогФайл(): ИЯдро is nil")
  30. }
  31. if build == "" {
  32. return nil, fmt.Errorf("НовСлогФайл(): strBuild is empty")
  33. }
  34. }
  35. сам := &СлогФайл{
  36. kern: kern,
  37. fileName: cons.СамИмя + "_" + build + time.Now().UTC().Format("_2006-01-02 15:04:05.000") + ".log",
  38. isWork: safe_bool.НовБезопБул(),
  39. chMsg: make(chan []byte, 10),
  40. }
  41. сам.isWork.Уст()
  42. _ = os.MkdirAll("./log", 0700)
  43. сам.fileName = "./log/" + сам.fileName
  44. if err := сам.open(); err != nil {
  45. return nil, fmt.Errorf("НовСлогФайл(): in open log-file, err=%w", err)
  46. }
  47. ош := сам.kern.Wg().Add(threadName)
  48. if ош != nil {
  49. return nil, fmt.Errorf("НовСлогФайл(): in Add %q, err=%w", threadName, ош)
  50. }
  51. go сам.run()
  52. return сам, nil
  53. }
  54. // Открывает файл на запись
  55. func (сам *СлогФайл) open() error {
  56. file, err := os.OpenFile(сам.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
  57. if err != nil {
  58. сам.kern.Отменить()
  59. return fmt.Errorf("СлогФайл.open(): in open %q, err=%w", сам.fileName, err)
  60. }
  61. сам.file = file
  62. return nil
  63. }
  64. // Запускает работу в отдельном потоке
  65. func (сам *СлогФайл) run() {
  66. defer func() {
  67. сам.isWork.Сброс()
  68. сам.block.Lock()
  69. defer сам.block.Unlock()
  70. _ = сам.file.Close()
  71. close(сам.chMsg)
  72. ош := сам.kern.Wg().Done(threadName)
  73. if ош != nil {
  74. log.Printf("СлогФайл.run(): при удалении группы ожидания, ош=\n\t%v", ош)
  75. }
  76. // log._rintf("SlogFile.run(): end work\n")
  77. сам.kern.Отменить()
  78. }()
  79. for {
  80. select {
  81. case <-сам.kern.Done(): // Ожидание отмены контекста приложения
  82. return
  83. case msg := <-сам.chMsg:
  84. if err := сам.write(msg); err != nil {
  85. сам.kern.Слог().Ошибка("СлогФайл.run(): in write msg, err=\n\t%v", err)
  86. return
  87. }
  88. }
  89. }
  90. }
  91. // Внцтренни вызов записи
  92. func (сам *СлогФайл) write(msg []byte) error {
  93. _, err := сам.file.Write(msg)
  94. if err != nil {
  95. return fmt.Errorf("СлогФайл.run(): in write file %q, err=\n\t%w", сам.fileName, err)
  96. }
  97. return nil
  98. }
  99. // Write -- записывает данные в файл
  100. func (сам *СлогФайл) Write(msg string) {
  101. if !сам.isWork.Получ() {
  102. return
  103. }
  104. сам.block.Lock()
  105. defer сам.block.Unlock()
  106. сам.chMsg <- []byte(msg)
  107. }