|
|
- package autofile
-
- import (
- "os"
- "sync"
- "time"
-
- cmn "github.com/tendermint/tendermint/libs/common"
- )
-
- /* AutoFile usage
-
- // Create/Append to ./autofile_test
- af, err := OpenAutoFile("autofile_test")
- if err != nil {
- panic(err)
- }
-
- // Stream of writes.
- // During this time, the file may be moved e.g. by logRotate.
- for i := 0; i < 60; i++ {
- af.Write([]byte(Fmt("LOOP(%v)", i)))
- time.Sleep(time.Second)
- }
-
- // Close the AutoFile
- err = af.Close()
- if err != nil {
- panic(err)
- }
- */
-
- const autoFileOpenDuration = 1000 * time.Millisecond
-
- // Automatically closes and re-opens file for writing.
- // This is useful for using a log file with the logrotate tool.
- type AutoFile struct {
- ID string
- Path string
- ticker *time.Ticker
- tickerStopped chan struct{} // closed when ticker is stopped
- mtx sync.Mutex
- file *os.File
- }
-
- func OpenAutoFile(path string) (af *AutoFile, err error) {
- af = &AutoFile{
- ID: cmn.RandStr(12) + ":" + path,
- Path: path,
- ticker: time.NewTicker(autoFileOpenDuration),
- tickerStopped: make(chan struct{}),
- }
- if err = af.openFile(); err != nil {
- return
- }
- go af.processTicks()
- sighupWatchers.addAutoFile(af)
- return
- }
-
- func (af *AutoFile) Close() error {
- af.ticker.Stop()
- close(af.tickerStopped)
- err := af.closeFile()
- sighupWatchers.removeAutoFile(af)
- return err
- }
-
- func (af *AutoFile) processTicks() {
- select {
- case <-af.ticker.C:
- af.closeFile()
- case <-af.tickerStopped:
- return
- }
- }
-
- func (af *AutoFile) closeFile() (err error) {
- af.mtx.Lock()
- defer af.mtx.Unlock()
-
- file := af.file
- if file == nil {
- return nil
- }
- af.file = nil
- return file.Close()
- }
-
- func (af *AutoFile) Write(b []byte) (n int, err error) {
- af.mtx.Lock()
- defer af.mtx.Unlock()
-
- if af.file == nil {
- if err = af.openFile(); err != nil {
- return
- }
- }
-
- n, err = af.file.Write(b)
- return
- }
-
- func (af *AutoFile) Sync() error {
- af.mtx.Lock()
- defer af.mtx.Unlock()
-
- if af.file == nil {
- if err := af.openFile(); err != nil {
- return err
- }
- }
- return af.file.Sync()
- }
-
- func (af *AutoFile) openFile() error {
- file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
- if err != nil {
- return err
- }
- af.file = file
- return nil
- }
-
- func (af *AutoFile) Size() (int64, error) {
- af.mtx.Lock()
- defer af.mtx.Unlock()
-
- if af.file == nil {
- err := af.openFile()
- if err != nil {
- if err == os.ErrNotExist {
- return 0, nil
- }
- return -1, err
- }
- }
- stat, err := af.file.Stat()
- if err != nil {
- return -1, err
- }
- return stat.Size(), nil
-
- }
|