log.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package applog
  2. import (
  3. "log"
  4. "os"
  5. "time"
  6. )
  7. var Enabled bool
  8. type logToFile struct {
  9. fn string
  10. file *os.File
  11. closing chan chan error // channel to close the file. Pass a 'chan error' which returns the error
  12. }
  13. var ltf *logToFile
  14. func newlogToFile(fn string) *logToFile {
  15. return &logToFile{
  16. fn: fn,
  17. file: nil,
  18. closing: make(chan chan error),
  19. }
  20. }
  21. func Printf(format string, a ...interface{}) {
  22. if Enabled {
  23. log.Printf(format, a...)
  24. }
  25. }
  26. func Println(a ...interface{}) {
  27. if Enabled {
  28. log.Println(a...)
  29. }
  30. }
  31. func logToFileMonitor() {
  32. for {
  33. select {
  34. case errc := <-ltf.closing: // a close has been requested
  35. if ltf.file != nil {
  36. log.SetOutput(os.Stderr)
  37. ltf.file.Close()
  38. ltf.file = nil
  39. }
  40. errc <- nil // pass a 'nil' error back, as everything worked fine
  41. return
  42. case <-time.After(time.Duration(5 * time.Second)):
  43. if fi, err := os.Stat(ltf.fn); err != nil || fi.Size() == 0 {
  44. // it has rotated - first check we can open the new file
  45. if f, err := os.OpenFile(ltf.fn, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
  46. // Send the error to the current log file - not ideal
  47. log.Printf("Could not open new log file: %v", err)
  48. } else {
  49. log.SetOutput(f)
  50. log.Printf("Rotating log file")
  51. ltf.file.Close()
  52. ltf.file = f
  53. }
  54. }
  55. }
  56. }
  57. }
  58. func FileOpen(fn string) {
  59. ltf = newlogToFile(fn)
  60. var err error
  61. ltf.file, err = os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  62. if err != nil {
  63. log.Fatalf("Error writing log file: %v", err)
  64. }
  65. // we deliberately do not close logFile here, because we keep it open pretty much for ever
  66. log.SetOutput(ltf.file)
  67. log.Printf("Opening log file")
  68. go logToFileMonitor()
  69. }
  70. func FileClose() {
  71. if ltf != nil {
  72. log.Printf("Closing log file")
  73. errc := make(chan error) // pass a 'chan error' through the closing channel
  74. ltf.closing <- errc
  75. _ = <-errc // wait until the monitor has closed the log file and exited
  76. close(ltf.closing) // close our 'chan error' channel
  77. ltf = nil
  78. }
  79. }