You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
2.5 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package autofile
  2. import (
  3. "os"
  4. "sync"
  5. "time"
  6. cmn "github.com/tendermint/tendermint/libs/common"
  7. )
  8. /* AutoFile usage
  9. // Create/Append to ./autofile_test
  10. af, err := OpenAutoFile("autofile_test")
  11. if err != nil {
  12. panic(err)
  13. }
  14. // Stream of writes.
  15. // During this time, the file may be moved e.g. by logRotate.
  16. for i := 0; i < 60; i++ {
  17. af.Write([]byte(Fmt("LOOP(%v)", i)))
  18. time.Sleep(time.Second)
  19. }
  20. // Close the AutoFile
  21. err = af.Close()
  22. if err != nil {
  23. panic(err)
  24. }
  25. */
  26. const autoFileOpenDuration = 1000 * time.Millisecond
  27. // Automatically closes and re-opens file for writing.
  28. // This is useful for using a log file with the logrotate tool.
  29. type AutoFile struct {
  30. ID string
  31. Path string
  32. ticker *time.Ticker
  33. tickerStopped chan struct{} // closed when ticker is stopped
  34. mtx sync.Mutex
  35. file *os.File
  36. }
  37. func OpenAutoFile(path string) (af *AutoFile, err error) {
  38. af = &AutoFile{
  39. ID: cmn.RandStr(12) + ":" + path,
  40. Path: path,
  41. ticker: time.NewTicker(autoFileOpenDuration),
  42. tickerStopped: make(chan struct{}),
  43. }
  44. if err = af.openFile(); err != nil {
  45. return
  46. }
  47. go af.processTicks()
  48. sighupWatchers.addAutoFile(af)
  49. return
  50. }
  51. func (af *AutoFile) Close() error {
  52. af.ticker.Stop()
  53. close(af.tickerStopped)
  54. err := af.closeFile()
  55. sighupWatchers.removeAutoFile(af)
  56. return err
  57. }
  58. func (af *AutoFile) processTicks() {
  59. for {
  60. select {
  61. case <-af.ticker.C:
  62. af.closeFile()
  63. case <-af.tickerStopped:
  64. return
  65. }
  66. }
  67. }
  68. func (af *AutoFile) closeFile() (err error) {
  69. af.mtx.Lock()
  70. defer af.mtx.Unlock()
  71. file := af.file
  72. if file == nil {
  73. return nil
  74. }
  75. af.file = nil
  76. return file.Close()
  77. }
  78. func (af *AutoFile) Write(b []byte) (n int, err error) {
  79. af.mtx.Lock()
  80. defer af.mtx.Unlock()
  81. if af.file == nil {
  82. if err = af.openFile(); err != nil {
  83. return
  84. }
  85. }
  86. n, err = af.file.Write(b)
  87. return
  88. }
  89. func (af *AutoFile) Sync() error {
  90. af.mtx.Lock()
  91. defer af.mtx.Unlock()
  92. if af.file == nil {
  93. if err := af.openFile(); err != nil {
  94. return err
  95. }
  96. }
  97. return af.file.Sync()
  98. }
  99. func (af *AutoFile) openFile() error {
  100. file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
  101. if err != nil {
  102. return err
  103. }
  104. af.file = file
  105. return nil
  106. }
  107. func (af *AutoFile) Size() (int64, error) {
  108. af.mtx.Lock()
  109. defer af.mtx.Unlock()
  110. if af.file == nil {
  111. err := af.openFile()
  112. if err != nil {
  113. if err == os.ErrNotExist {
  114. return 0, nil
  115. }
  116. return -1, err
  117. }
  118. }
  119. stat, err := af.file.Stat()
  120. if err != nil {
  121. return -1, err
  122. }
  123. return stat.Size(), nil
  124. }