slog_file.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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. // SlogFile -- бэкенд для вывода в файл
  17. type SlogFile struct {
  18. kern types.IKernel
  19. file *os.File
  20. fileName string
  21. isWork *safe_bool.БезопБул
  22. chMsg chan []byte // канал входящих сообщений
  23. block sync.Mutex
  24. }
  25. // NewSlogFile -- возвращает новый бэкенд логгера для вывода в файл
  26. func NewSlogFile(kern types.IKernel, build string) (*SlogFile, error) {
  27. { // Предусловия
  28. if kern == nil {
  29. return nil, fmt.Errorf("NewSlogFile(): IKernel is nil")
  30. }
  31. if build == "" {
  32. return nil, fmt.Errorf("NewSlogFile(): strBuild is empty")
  33. }
  34. }
  35. сам := &SlogFile{
  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("NewSlogFile(): in open log-file, err=%w", err)
  46. }
  47. сам.kern.Wg().Add(threadName)
  48. go сам.run()
  49. return сам, nil
  50. }
  51. // Открывает файл на запись
  52. func (сам *SlogFile) open() error {
  53. file, err := os.OpenFile(сам.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
  54. if err != nil {
  55. сам.kern.CancelApp()
  56. return fmt.Errorf("NewSlogFile.open(): in open %q, err=%w", сам.fileName, err)
  57. }
  58. сам.file = file
  59. return nil
  60. }
  61. // Запускает работу в отдельном потоке
  62. func (сам *SlogFile) run() {
  63. defer func() {
  64. сам.isWork.Сброс()
  65. сам.block.Lock()
  66. defer сам.block.Unlock()
  67. _ = сам.file.Close()
  68. close(сам.chMsg)
  69. сам.kern.Wg().Done(threadName)
  70. // log._rintf("SlogFile.run(): end work\n")
  71. сам.kern.CancelApp()
  72. }()
  73. for {
  74. select {
  75. case <-сам.kern.Done(): // Ожидание отмены контекста приложения
  76. return
  77. case msg := <-сам.chMsg:
  78. if err := сам.write(msg); err != nil {
  79. сам.kern.Slog().Errorf("SlogFile.run(): in write msg, err=\n\t%v", err)
  80. return
  81. }
  82. }
  83. }
  84. }
  85. // Внцтренни вызов записи
  86. func (сам *SlogFile) write(msg []byte) error {
  87. _, err := сам.file.Write(msg)
  88. if err != nil {
  89. return fmt.Errorf("SlogFile.run(): in write file %q, err=\n\t%w", сам.fileName, err)
  90. }
  91. return nil
  92. }
  93. // Write -- записывает данные в файл
  94. func (сам *SlogFile) Write(msg string) {
  95. if !сам.isWork.Получ() {
  96. return
  97. }
  98. сам.block.Lock()
  99. defer сам.block.Unlock()
  100. сам.chMsg <- []byte(msg)
  101. }