github.com/Cloud-Foundations/Dominator@v0.3.4/lib/logbuf/api.go (about) 1 /* 2 Package logbuf provides a circular buffer for writing logs to. 3 4 Package logbuf provides an io.Writer which can be passed to the log.New 5 function to serve as a destination for logs. Logs can be viewed via a HTTP 6 interface and may also be directed to the standard error output. 7 */ 8 package logbuf 9 10 import ( 11 "container/ring" 12 "flag" 13 "io" 14 "net/http" 15 "os" 16 "path" 17 "sync" 18 "time" 19 20 "github.com/Cloud-Foundations/Dominator/lib/bufwriter" 21 "github.com/Cloud-Foundations/Dominator/lib/flagutil" 22 ) 23 24 var ( 25 stdOptions = Options{ 26 HttpServeMux: http.DefaultServeMux, 27 MaxFileSize: 10 << 20, 28 Quota: 100 << 20, 29 } 30 kSoleLogBuffer *LogBuffer 31 kOnce sync.Once 32 ) 33 34 // LogBuffer is a circular buffer suitable for holding logs. It satisfies the 35 // io.Writer interface. It is usually passed to the log.New function. 36 type LogBuffer struct { 37 options Options 38 rwMutex sync.RWMutex 39 buffer *ring.Ring // Always points to next insert position. 40 file *os.File 41 fileSize flagutil.Size 42 firstFile string // Since process startup. Leaf name. 43 lastStackTrace time.Time 44 noLogsEver bool // true if no logs ever written (fresh directory). 45 panicLogfile *string // Name of last invocation logfile if it has a panic. 46 usage flagutil.Size 47 writeNotifier chan<- struct{} 48 writer *bufwriter.Writer 49 } 50 51 type Options struct { 52 AlsoLogToStderr bool 53 Directory string 54 HttpServeMux *http.ServeMux 55 IdleMarkTimeout time.Duration 56 MaxBufferLines uint // Minimum: 100. 57 MaxFileSize flagutil.Size // Minimum: 16 KiB 58 Quota flagutil.Size // Minimum: 64 KiB. 59 RedirectStderr bool // Only one LogBuffer should set this. 60 } 61 62 // UseFlagSet instructs this package to read its command-line flags from the 63 // given flag set instead of from the command line. Caller must pass the 64 // flag set to this method before calling Parse on it. 65 func UseFlagSet(set *flag.FlagSet) { 66 set.BoolVar(&stdOptions.AlsoLogToStderr, "alsoLogToStderr", false, 67 "If true, also write logs to stderr") 68 set.DurationVar(&stdOptions.IdleMarkTimeout, "idleMarkTimeout", 0, 69 "time after last log before a 'MARK' message is written to logfile") 70 set.UintVar(&stdOptions.MaxBufferLines, "logbufLines", 1024, 71 "Number of lines to store in the log buffer") 72 set.StringVar(&stdOptions.Directory, "logDir", path.Join("/var/log", 73 path.Base(os.Args[0])), 74 "Directory to write log data to. If empty, no logs are written") 75 set.Var(&stdOptions.MaxFileSize, "logFileMaxSize", 76 "Maximum size for a log file. If exceeded, new file is created") 77 set.Var(&stdOptions.Quota, "logQuota", 78 "Log quota. If exceeded, old logs are deleted") 79 } 80 81 // GetStandardOptions will return the standard options. 82 // Only one *LogBuffer should be created per application with these options. 83 // The following command-line flags are registered and used: 84 // 85 // -alsoLogToStderr: If true, also write logs to stderr 86 // -logbufLines: Number of lines to store in the log buffer 87 // -logDir: Directory to write log data to. If empty, no logs are 88 // written 89 // -logFileMaxSize: Maximum size for each log file. If exceeded, the logfile 90 // is closed and a new one opened. 91 // If zero, the limit will be 16 KiB 92 // -logQuota: Log quota. If exceeded, old logs are deleted. 93 // If zero, the quota will be 64 KiB 94 func GetStandardOptions() Options { return stdOptions } 95 96 // New returns a new *LogBuffer with the standard options. Note that 97 // RedirectStderr will be set to true if AlsoLogToStderr is false. 98 // Only one should be created per application. 99 func New() *LogBuffer { 100 options := stdOptions 101 if !options.AlsoLogToStderr { 102 options.RedirectStderr = true 103 } 104 return newLogBuffer(options) 105 } 106 107 // NewWithOptions will create a new *LogBuffer with the specified options. 108 // Each *LogBuffer must use a different Directory and HttpServeMux. 109 func NewWithOptions(options Options) *LogBuffer { 110 return newLogBuffer(options) 111 } 112 113 // Get works like New except that successive calls to Get return the same 114 // instance. 115 func Get() *LogBuffer { 116 kOnce.Do(func() { 117 kSoleLogBuffer = New() 118 }) 119 return kSoleLogBuffer 120 121 } 122 123 // CheckNeverLogged returns true if this LogBuffer never had any logs written 124 // to the log directory. 125 func (lb *LogBuffer) CheckNeverLogged() bool { 126 return lb.checkNeverLogged() 127 } 128 129 // Dump will write the contents of the log buffer to w, with a prefix and 130 // postfix string written before and after each line. If recentFirst is true, 131 // the most recently written contents are dumped first. 132 func (lb *LogBuffer) Dump(writer io.Writer, prefix, postfix string, 133 recentFirst bool) error { 134 return lb.dump(writer, prefix, postfix, recentFirst, false) 135 } 136 137 // Flush flushes the open log file (if one is open). This should only be called 138 // just prior to process termination. The log file is automatically flushed 139 // after short periods of inactivity. 140 func (lb *LogBuffer) Flush() error { 141 return lb.flush() 142 } 143 144 // Write will write len(p) bytes from p to the log buffer. It always returns 145 // len(p), nil. 146 func (lb *LogBuffer) Write(p []byte) (n int, err error) { 147 return lb.write(p) 148 } 149 150 // WriteHtml will write the contents of the log buffer to writer, with 151 // appropriate HTML markups. 152 func (lb *LogBuffer) WriteHtml(writer io.Writer) { 153 lb.writeHtml(writer) 154 }