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.

126 lines
2.1 KiB

8 years ago
8 years ago
  1. package autofile
  2. import (
  3. . "github.com/tendermint/go-common"
  4. "os"
  5. "sync"
  6. "time"
  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. mtx sync.Mutex
  34. file *os.File
  35. }
  36. func OpenAutoFile(path string) (af *AutoFile, err error) {
  37. af = &AutoFile{
  38. ID: RandStr(12) + ":" + path,
  39. Path: path,
  40. ticker: time.NewTicker(autoFileOpenDuration),
  41. }
  42. if err = af.openFile(); err != nil {
  43. return
  44. }
  45. go af.processTicks()
  46. sighupWatchers.addAutoFile(af)
  47. return
  48. }
  49. func (af *AutoFile) Close() error {
  50. af.ticker.Stop()
  51. err := af.closeFile()
  52. sighupWatchers.removeAutoFile(af)
  53. return err
  54. }
  55. func (af *AutoFile) processTicks() {
  56. for {
  57. _, ok := <-af.ticker.C
  58. if !ok {
  59. return // Done.
  60. }
  61. af.closeFile()
  62. }
  63. }
  64. func (af *AutoFile) closeFile() (err error) {
  65. af.mtx.Lock()
  66. defer af.mtx.Unlock()
  67. file := af.file
  68. if file == nil {
  69. return nil
  70. }
  71. af.file = nil
  72. return file.Close()
  73. }
  74. func (af *AutoFile) Write(b []byte) (n int, err error) {
  75. af.mtx.Lock()
  76. defer af.mtx.Unlock()
  77. if af.file == nil {
  78. if err = af.openFile(); err != nil {
  79. return
  80. }
  81. }
  82. return af.file.Write(b)
  83. }
  84. func (af *AutoFile) openFile() error {
  85. file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
  86. if err != nil {
  87. return err
  88. }
  89. af.file = file
  90. return nil
  91. }
  92. func (af *AutoFile) Size() (int64, error) {
  93. af.mtx.Lock()
  94. defer af.mtx.Unlock()
  95. if af.file == nil {
  96. err := af.openFile()
  97. if err != nil {
  98. if err == os.ErrNotExist {
  99. return 0, nil
  100. } else {
  101. return -1, err
  102. }
  103. }
  104. }
  105. stat, err := af.file.Stat()
  106. if err != nil {
  107. return -1, err
  108. }
  109. return stat.Size(), nil
  110. }