filehandler.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package log
  2. import (
  3. "fmt"
  4. "os"
  5. "path"
  6. "time"
  7. )
  8. // FileHandler writes log to a file.
  9. type FileHandler struct {
  10. fd *os.File
  11. }
  12. // NewFileHandler creates a FileHander
  13. func NewFileHandler(fileName string, flag int) (*FileHandler, error) {
  14. dir := path.Dir(fileName)
  15. os.Mkdir(dir, 0777)
  16. f, err := os.OpenFile(fileName, flag, 0755)
  17. if err != nil {
  18. return nil, err
  19. }
  20. h := new(FileHandler)
  21. h.fd = f
  22. return h, nil
  23. }
  24. // Write implements Handler interface
  25. func (h *FileHandler) Write(b []byte) (n int, err error) {
  26. return h.fd.Write(b)
  27. }
  28. // Close implements Handler interface
  29. func (h *FileHandler) Close() error {
  30. return h.fd.Close()
  31. }
  32. // RotatingFileHandler writes log a file, if file size exceeds maxBytes,
  33. // it will backup current file and open a new one.
  34. //
  35. // max backup file number is set by backupCount, it will delete oldest if backups too many.
  36. type RotatingFileHandler struct {
  37. fd *os.File
  38. fileName string
  39. maxBytes int
  40. curBytes int
  41. backupCount int
  42. }
  43. // NewRotatingFileHandler creates a RotatingFileHandler
  44. func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) {
  45. dir := path.Dir(fileName)
  46. os.MkdirAll(dir, 0777)
  47. h := new(RotatingFileHandler)
  48. if maxBytes <= 0 {
  49. return nil, fmt.Errorf("invalid max bytes")
  50. }
  51. h.fileName = fileName
  52. h.maxBytes = maxBytes
  53. h.backupCount = backupCount
  54. var err error
  55. h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  56. if err != nil {
  57. return nil, err
  58. }
  59. f, err := h.fd.Stat()
  60. if err != nil {
  61. return nil, err
  62. }
  63. h.curBytes = int(f.Size())
  64. return h, nil
  65. }
  66. // Write implements Handler interface
  67. func (h *RotatingFileHandler) Write(p []byte) (n int, err error) {
  68. h.doRollover()
  69. n, err = h.fd.Write(p)
  70. h.curBytes += n
  71. return
  72. }
  73. // Close implements Handler interface
  74. func (h *RotatingFileHandler) Close() error {
  75. if h.fd != nil {
  76. return h.fd.Close()
  77. }
  78. return nil
  79. }
  80. func (h *RotatingFileHandler) doRollover() {
  81. if h.curBytes < h.maxBytes {
  82. return
  83. }
  84. f, err := h.fd.Stat()
  85. if err != nil {
  86. return
  87. }
  88. if h.maxBytes <= 0 {
  89. return
  90. } else if f.Size() < int64(h.maxBytes) {
  91. h.curBytes = int(f.Size())
  92. return
  93. }
  94. if h.backupCount > 0 {
  95. h.fd.Close()
  96. for i := h.backupCount - 1; i > 0; i-- {
  97. sfn := fmt.Sprintf("%s.%d", h.fileName, i)
  98. dfn := fmt.Sprintf("%s.%d", h.fileName, i+1)
  99. os.Rename(sfn, dfn)
  100. }
  101. dfn := fmt.Sprintf("%s.1", h.fileName)
  102. os.Rename(h.fileName, dfn)
  103. h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  104. h.curBytes = 0
  105. f, err := h.fd.Stat()
  106. if err != nil {
  107. return
  108. }
  109. h.curBytes = int(f.Size())
  110. }
  111. }
  112. // TimeRotatingFileHandler writes log to a file,
  113. // it will backup current and open a new one, with a period time you sepecified.
  114. //
  115. // refer: http://docs.python.org/2/library/logging.handlers.html.
  116. // same like python TimedRotatingFileHandler.
  117. type TimeRotatingFileHandler struct {
  118. fd *os.File
  119. baseName string
  120. interval int64
  121. suffix string
  122. rolloverAt int64
  123. }
  124. // TimeRotating way
  125. const (
  126. WhenSecond = iota
  127. WhenMinute
  128. WhenHour
  129. WhenDay
  130. )
  131. // NewTimeRotatingFileHandler creates a TimeRotatingFileHandler
  132. func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
  133. dir := path.Dir(baseName)
  134. os.MkdirAll(dir, 0777)
  135. h := new(TimeRotatingFileHandler)
  136. h.baseName = baseName
  137. switch when {
  138. case WhenSecond:
  139. h.interval = 1
  140. h.suffix = "2006-01-02_15-04-05"
  141. case WhenMinute:
  142. h.interval = 60
  143. h.suffix = "2006-01-02_15-04"
  144. case WhenHour:
  145. h.interval = 3600
  146. h.suffix = "2006-01-02_15"
  147. case WhenDay:
  148. h.interval = 3600 * 24
  149. h.suffix = "2006-01-02"
  150. default:
  151. return nil, fmt.Errorf("invalid when_rotate: %d", when)
  152. }
  153. h.interval = h.interval * int64(interval)
  154. var err error
  155. h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  156. if err != nil {
  157. return nil, err
  158. }
  159. fInfo, _ := h.fd.Stat()
  160. h.rolloverAt = fInfo.ModTime().Unix() + h.interval
  161. return h, nil
  162. }
  163. func (h *TimeRotatingFileHandler) doRollover() {
  164. //refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
  165. now := time.Now()
  166. if h.rolloverAt <= now.Unix() {
  167. fName := h.baseName + now.Format(h.suffix)
  168. h.fd.Close()
  169. e := os.Rename(h.baseName, fName)
  170. if e != nil {
  171. panic(e)
  172. }
  173. h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  174. h.rolloverAt = time.Now().Unix() + h.interval
  175. }
  176. }
  177. // Write implements Handler interface
  178. func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
  179. h.doRollover()
  180. return h.fd.Write(b)
  181. }
  182. // Close implements Handler interface
  183. func (h *TimeRotatingFileHandler) Close() error {
  184. return h.fd.Close()
  185. }