slog_file.go 2.7 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/safebool"
  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 *safebool.SafeBool
  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. sf := &SlogFile{
  36. kern: kern,
  37. fileName: cons.SelfName + "_" + build + time.Now().UTC().Format("_2006-01-02 15:04:05.000") + ".log",
  38. isWork: safebool.NewSafeBool(),
  39. chMsg: make(chan []byte, 10),
  40. }
  41. sf.isWork.Set()
  42. _ = os.MkdirAll("./log", 0700)
  43. sf.fileName = "./log/" + sf.fileName
  44. if err := sf.open(); err != nil {
  45. return nil, fmt.Errorf("NewSlogFile(): in open log-file, err=%w", err)
  46. }
  47. sf.kern.Wg().Add(threadName)
  48. go sf.run()
  49. return sf, nil
  50. }
  51. // Открывает файл на запись
  52. func (sf *SlogFile) open() error {
  53. file, err := os.OpenFile(sf.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
  54. if err != nil {
  55. sf.kern.CancelApp()
  56. return fmt.Errorf("NewSlogFile.open(): in open %q, err=%w", sf.fileName, err)
  57. }
  58. sf.file = file
  59. return nil
  60. }
  61. // Запускает работу в отдельном потоке
  62. func (sf *SlogFile) run() {
  63. defer func() {
  64. sf.isWork.Reset()
  65. sf.block.Lock()
  66. defer sf.block.Unlock()
  67. _ = sf.file.Close()
  68. close(sf.chMsg)
  69. sf.kern.Wg().Done(threadName)
  70. // log._rintf("SlogFile.run(): end work\n")
  71. sf.kern.CancelApp()
  72. }()
  73. for {
  74. select {
  75. case <-sf.kern.Done(): // Ожидание отмены контекста приложения
  76. return
  77. case msg := <-sf.chMsg:
  78. if err := sf.write(msg); err != nil {
  79. sf.kern.Slog().Errorf("SlogFile.run(): in write msg, err=\n\t%v", err)
  80. return
  81. }
  82. }
  83. }
  84. }
  85. // Внцтренни вызов записи
  86. func (sf *SlogFile) write(msg []byte) error {
  87. _, err := sf.file.Write(msg)
  88. if err != nil {
  89. return fmt.Errorf("SlogFile.run(): in write file %q, err=\n\t%w", sf.fileName, err)
  90. }
  91. return nil
  92. }
  93. // Write -- записывает данные в файл
  94. func (sf *SlogFile) Write(msg string) {
  95. if !sf.isWork.Get() {
  96. return
  97. }
  98. sf.block.Lock()
  99. defer sf.block.Unlock()
  100. sf.chMsg <- []byte(msg)
  101. }