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  }