Skip to content

Commit

Permalink
Add WithSymlink
Browse files Browse the repository at this point in the history
improve debug log
  • Loading branch information
utahta committed Feb 8, 2017
1 parent c9076f3 commit fd79ee5
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 16 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ w.Write([]byte("test"))
// /path/to/example.log.UTC
```

with Symlink
```go
w := writer.MustNew("/path/to/example.log.%Y%m%d", writer.WithSymlink("/path/to/example.log"))
w.Write([]byte("test"))

// output file
// /path/to/example.log.20170204
// /path/to/example.log -> /path/to/example.log.20170204
```

with Mutex
```go
w := writer.MustNew("/path/to/example.log.%Y%m%d", writer.WithMutex())
Expand Down
55 changes: 55 additions & 0 deletions log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package writer

import (
"fmt"
"io"
"os"
)

type logger interface {
Write(b []byte)
Println(args ...interface{})
Printf(format string, args ...interface{})
Error(args ...interface{})
Errorf(format string, args ...interface{})
}

type noopLogger struct{}

type debugLogger struct {
stdout io.Writer
stderr io.Writer
}

func newDebugLogger() *debugLogger {
return &debugLogger{
stdout: os.Stdout,
stderr: os.Stderr,
}
}

func (l *noopLogger) Write(b []byte) {}
func (l *noopLogger) Println(args ...interface{}) {}
func (l *noopLogger) Printf(format string, args ...interface{}) {}
func (l *noopLogger) Error(args ...interface{}) {}
func (l *noopLogger) Errorf(format string, args ...interface{}) {}

func (l *debugLogger) Write(b []byte) {
fmt.Fprintf(l.stdout, "%s", b)
}

func (l *debugLogger) Println(args ...interface{}) {
fmt.Fprintln(l.stdout, args...)
}

func (l *debugLogger) Printf(format string, args ...interface{}) {
fmt.Fprintf(l.stdout, format, args...)
}

func (l *debugLogger) Error(args ...interface{}) {
fmt.Fprintln(l.stderr, args...)
}

func (l *debugLogger) Errorf(format string, args ...interface{}) {
fmt.Fprintf(l.stderr, format, args...)
}
5 changes: 0 additions & 5 deletions noop.go → mutex.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package writer

type noopMutex struct{}
type noopWriter struct{}

func (*noopMutex) Lock() {}
func (*noopMutex) Unlock() {}

func (*noopWriter) Write([]byte) (int, error) {
return 0, nil // no-op
}
52 changes: 43 additions & 9 deletions writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
type CronoWriter struct {
pattern *strftime.Strftime // given pattern
path string // current file path
symlink *strftime.Strftime // symbolic link to current file path
fp *os.File // current file pointer
loc *time.Location
mux sync.Locker
stdout io.Writer
stderr io.Writer
debug logger
init bool // if true, open the file when New() method is called
}

Expand All @@ -38,11 +38,11 @@ func New(pattern string, options ...Option) (*CronoWriter, error) {
c := &CronoWriter{
pattern: p,
path: "",
symlink: nil,
fp: nil,
loc: time.Local,
mux: new(noopMutex), // default mutex off
stdout: &noopWriter{},
stderr: &noopWriter{},
debug: &noopLogger{},
init: false,
}

Expand Down Expand Up @@ -74,6 +74,16 @@ func WithLocation(loc *time.Location) Option {
}
}

func WithSymlink(pattern string) Option {
return func(c *CronoWriter) {
p, err := strftime.New(pattern)
if err != nil {
panic(err)
}
c.symlink = p
}
}

func WithMutex() Option {
return func(c *CronoWriter) {
c.mux = new(sync.Mutex)
Expand All @@ -82,8 +92,7 @@ func WithMutex() Option {

func WithDebug() Option {
return func(c *CronoWriter) {
c.stdout = os.Stdout
c.stderr = os.Stderr
c.debug = newDebugLogger()
}
}

Expand All @@ -97,7 +106,8 @@ func (c *CronoWriter) Write(b []byte) (int, error) {
c.mux.Lock()
defer c.mux.Unlock()

path := c.pattern.FormatString(now().In(c.loc))
t := now().In(c.loc)
path := c.pattern.FormatString(t)

if c.path != path {
// close file
Expand All @@ -117,13 +127,37 @@ func (c *CronoWriter) Write(b []byte) (int, error) {
if err != nil {
return c.write(nil, err)
}
c.createSymlink(t, path)

c.path = path
c.fp = fp
}

return c.write(b, nil)
}

func (c *CronoWriter) createSymlink(t time.Time, path string) {
if c.symlink == nil {
return
}

symlink := c.symlink.FormatString(t)
if symlink == path {
c.debug.Error("Can't create symlink. same path is specified.")
return
}

if err := os.Remove(symlink); err != nil {
c.debug.Error(err)
return
}

if err := os.Symlink(path, symlink); err != nil {
c.debug.Error(err)
// ignore error
}
}

func (c *CronoWriter) Close() error {
c.mux.Lock()
defer c.mux.Unlock()
Expand All @@ -133,10 +167,10 @@ func (c *CronoWriter) Close() error {

func (c *CronoWriter) write(b []byte, err error) (int, error) {
if err != nil {
c.stderr.Write([]byte(err.Error()))
c.debug.Error(err)
return 0, err
}

c.stdout.Write(b)
c.debug.Write(b)
return c.fp.Write(b)
}
4 changes: 2 additions & 2 deletions writer_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func BenchmarkCronoWriter_WriteWithDebug(b *testing.B) {
}

c := MustNew(filepath.Join(tmpDir, "benchmark.log.%Y%m%d"), WithDebug())
c.stdout = ioutil.Discard
c.stderr = ioutil.Discard
c.debug.(*debugLogger).stdout = ioutil.Discard
c.debug.(*debugLogger).stderr = ioutil.Discard
for i := 0; i < b.N; i++ {
c.Write([]byte("abcdefg"))
}
Expand Down

0 comments on commit fd79ee5

Please sign in to comment.