This repository has been archived by the owner on Jan 9, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add writer.File and its tests and benchmarks closes #10
- Loading branch information
Showing
9 changed files
with
528 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
# Binaries for programs and plugins | ||
logpipe | ||
*.exe | ||
*.dll | ||
*.so | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// Copyright 2016 Arsham Shirvani <arshamshirvani@gmail.com>. All rights reserved. | ||
// Use of this source code is governed by the Apache 2.0 license | ||
// License that can be found in the LICENSE file. | ||
|
||
// Package internal contains some internal functionalities needed for piplog. | ||
// Other commonly used logic are places in the internal package itself. There | ||
// is logging set up. | ||
package internal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright 2017 Arsham Shirvani <arshamshirvani@gmail.com>. All rights reserved. | ||
// Use of this source code is governed by the Apache 2.0 license | ||
// License that can be found in the LICENSE file. | ||
|
||
package internal | ||
|
||
import ( | ||
"io/ioutil" | ||
"strings" | ||
|
||
"github.com/Sirupsen/logrus" | ||
) | ||
|
||
// FieldLogger interface set by logrus | ||
type FieldLogger logrus.FieldLogger | ||
|
||
// Level type set by logrus | ||
type Level logrus.Level | ||
|
||
// Logger embeds logrus.Logger | ||
type Logger struct{ *logrus.Logger } | ||
|
||
// Entry embeds logrus.Entry | ||
type Entry struct{ *logrus.Entry } | ||
|
||
// StandardLogger returns an instance of Logger | ||
func StandardLogger() *Logger { return &Logger{logrus.StandardLogger()} } | ||
|
||
const ( | ||
// InfoLevel for Info level | ||
InfoLevel = logrus.InfoLevel | ||
// WarnLevel for Warn level | ||
WarnLevel = logrus.WarnLevel | ||
// DebugLevel for Debug level | ||
DebugLevel = logrus.DebugLevel | ||
// ErrorLevel for Error level | ||
ErrorLevel = logrus.ErrorLevel | ||
) | ||
|
||
// Get returns the default logger with the given log level. | ||
func Get(level string) *Logger { | ||
logrus.SetLevel(ErrorLevel) | ||
customFormatter := new(logrus.TextFormatter) | ||
customFormatter.TimestampFormat = "2006-01-02 15:04:05" | ||
logrus.SetFormatter(customFormatter) | ||
customFormatter.FullTimestamp = true | ||
switch strings.ToLower(level) { | ||
case "debug": | ||
logrus.SetLevel(DebugLevel) | ||
case "info": | ||
logrus.SetLevel(InfoLevel) | ||
case "warn": | ||
logrus.SetLevel(WarnLevel) | ||
case "error": | ||
logrus.SetLevel(ErrorLevel) | ||
default: | ||
logrus.SetLevel(ErrorLevel) | ||
} | ||
|
||
return StandardLogger() | ||
} | ||
|
||
// DiscardLogger returns a dummy logger. | ||
// This is useful for tests when you don't want to actually write to the Stdout. | ||
func DiscardLogger() *Logger { | ||
log := logrus.New() | ||
log.Out = ioutil.Discard | ||
return &Logger{log} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright 2016 Arsham Shirvani <arshamshirvani@gmail.com>. All rights reserved. | ||
// Use of this source code is governed by the Apache 2.0 license | ||
// License that can be found in the LICENSE file. | ||
|
||
package internal_test | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"testing" | ||
|
||
"github.com/arsham/logpipe/internal" | ||
) | ||
|
||
func TestGetLoggerLevels(t *testing.T) { | ||
t.Parallel() | ||
tcs := []struct { | ||
level string | ||
expected internal.Level | ||
}{ | ||
{"debug", internal.Level(internal.DebugLevel)}, | ||
{"info", internal.Level(internal.InfoLevel)}, | ||
{"warn", internal.Level(internal.WarnLevel)}, | ||
{"error", internal.Level(internal.ErrorLevel)}, | ||
{"DEBUG", internal.Level(internal.DebugLevel)}, | ||
{"INFO", internal.Level(internal.InfoLevel)}, | ||
{"WARN", internal.Level(internal.WarnLevel)}, | ||
{"ERROR", internal.Level(internal.ErrorLevel)}, | ||
{"dEbUG", internal.Level(internal.DebugLevel)}, | ||
{"iNfO", internal.Level(internal.InfoLevel)}, | ||
{"wArN", internal.Level(internal.WarnLevel)}, | ||
{"eRrOR", internal.Level(internal.ErrorLevel)}, | ||
{"", internal.Level(internal.ErrorLevel)}, | ||
{"sdfsdf", internal.Level(internal.ErrorLevel)}, | ||
} | ||
|
||
for i, tc := range tcs { | ||
name := fmt.Sprintf("case_%d", i) | ||
t.Run(name, func(t *testing.T) { | ||
logger := internal.Get(tc.level) | ||
if internal.Level(logger.Level) != tc.expected { | ||
t.Errorf("want (%v), got (%v)", tc.expected, logger.Level) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestGetDiscardLogger(t *testing.T) { | ||
logger := internal.DiscardLogger() | ||
if logger.Out != ioutil.Discard { | ||
t.Errorf("want (ioutil.Discard), got (%v)", logger.Out) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package main_test | ||
|
||
import ( | ||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
"testing" | ||
) | ||
|
||
func TestLogpipe(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Logpipe Suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2017 Arsham Shirvani <arshamshirvani@gmail.com>. All rights reserved. | ||
// Use of this source code is governed by the Apache 2.0 license | ||
// License that can be found in the LICENSE file. | ||
|
||
package writer | ||
|
||
import ( | ||
"bufio" | ||
"os" | ||
"sync" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
// File writs records log entries to a file. It buffers the writes to obtain | ||
// better performance. It flushes the buffer every 1 seconds. | ||
// It implements io.WriteCloser interface. | ||
type File struct { | ||
name string | ||
file *os.File | ||
sync.Mutex // guards against the buffer | ||
buf *bufio.Writer | ||
} | ||
|
||
// NewFile returns error if the file can not be created. | ||
func NewFile(location string) (*File, error) { | ||
var ( | ||
f *os.File | ||
err error | ||
) | ||
|
||
if f, err = os.OpenFile(location, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil { | ||
if os.IsPermission(err) { | ||
return nil, errors.Wrap(err, "opening file") | ||
} | ||
} | ||
buf := bufio.NewWriter(f) | ||
|
||
fl := &File{ | ||
file: f, | ||
name: location, | ||
buf: buf, | ||
} | ||
|
||
// this goroutine will flush the logs onto the file | ||
go func(buf *bufio.Writer) { | ||
ticker := time.NewTicker(time.Second) | ||
for range ticker.C { | ||
fl.Lock() | ||
buf.Flush() | ||
fl.Unlock() | ||
} | ||
}(buf) | ||
|
||
return fl, nil | ||
} | ||
|
||
// Close closes the File. | ||
func (f *File) Close() error { | ||
if err := f.Flush(); err != nil { | ||
return errors.Wrap(err, "flushing on close") | ||
} | ||
return f.file.Close() | ||
} | ||
|
||
// Name returns the file location on disk. | ||
func (f *File) Name() string { | ||
return f.name | ||
} | ||
|
||
// Write writes the input bytes to the file. | ||
// The write will not appear in the file unless the buffer is flushed. (see Flush()) | ||
func (f *File) Write(p []byte) (int, error) { | ||
f.Lock() | ||
defer f.Unlock() | ||
|
||
n1, err := f.buf.Write(p) | ||
if err != nil { | ||
return n1, errors.Wrap(err, "writing the bytes") | ||
} | ||
|
||
n2, err := f.buf.Write([]byte("\n")) // required for creating a new line | ||
if err != nil { | ||
return n2, errors.Wrap(err, "writing new line") | ||
} | ||
return n1, nil | ||
} | ||
|
||
// Flush flushes the underlying buffer. | ||
func (f *File) Flush() error { | ||
f.Lock() | ||
defer f.Unlock() | ||
return f.buf.Flush() | ||
} |
Oops, something went wrong.