Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added go tests and benchmarks #1

Merged
merged 1 commit into from
Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<h4>Glog glugs the log files in a concurrent and thread-safe way.</h4>
<h4>Simple and easy to implement interfaces to log fast and efficiently</h4>

[![Go](https://github.com/ric-v/glog/actions/workflows/go.yml/badge.svg)](https://github.com/ric-v/glog/actions/workflows/go.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/ric-v/glog)](https://goreportcard.com/report/github.com/ric-v/glog)
[![CodeFactor](https://www.codefactor.io/repository/github/ric-v/glog/badge)](https://www.codefactor.io/repository/github/ric-v/glog)
[![Maintained](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://img.shields.io/badge/Maintained%3F-yes-green.svg)
Expand Down
2 changes: 1 addition & 1 deletion examples/concurrent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func main() {

logger := glog.UnstructureGlogger("glogger.log")
logger := glog.NewUnstructureGlogger("glogger.log")
defer logger.Cleanup()

var wg sync.WaitGroup
Expand Down
2 changes: 1 addition & 1 deletion examples/json-log/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import "github.com/ric-v/glog"

func main() {

logger := glog.JSONGlogger("glogger.json")
logger := glog.NewJSONGlogger("glogger.json")
defer logger.Cleanup()

logger.Info("", "Hello", "World")
Expand Down
171 changes: 73 additions & 98 deletions glogger.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@ type LogLevel string

// Glogger is the interface for controlling logging
type Glogger interface {
Error(string, ...interface{})
Warn(string, ...interface{})
Info(string, ...interface{})
Debug(string, ...interface{})
log(string, LogLevel, ...interface{})
Cleanup()
Error(...interface{}) // error logger without format
Warn(...interface{}) // warning logger without format
Info(...interface{}) // info logger without format
Debug(...interface{}) // debug logger without format
log(LogLevel, ...interface{}) // logger without format

Errorf(string, ...interface{}) // error logger with format
Warnf(string, ...interface{}) // warning logger with format
Infof(string, ...interface{}) // info logger with format
Debugf(string, ...interface{}) // debug logger with format
logf(string, LogLevel, ...interface{}) // logger with format

Cleanup() // safely close the glogger
}

// Options is a struct for setting the format of the log messages
Expand All @@ -31,8 +38,8 @@ type Options struct {
Position string
}

// Glog type is the logger data for logging concurrently to file
type Glog struct {
// glog type is the logger data for logging concurrently to file
type glog struct {
out io.Writer // writer for logging to file / cmd line
queue chan interface{} // queue for logging
wg *sync.WaitGroup // wait group for logging
Expand All @@ -45,12 +52,17 @@ var defaultGlogger *UnstructureGlog

// initialize a default logger when user doesnot want a custom logger
func init() {
NewDefaultGlogger()
}

// NewDefaultGlogger creates a new Glog object for stdout and options for formatting
func NewDefaultGlogger() Glogger {

var wg sync.WaitGroup

// set std out as the default glogger
defaultGlogger = &UnstructureGlog{
Glog: Glog{
glog: glog{
out: os.Stderr,
queue: make(chan interface{}, 1000),
wg: &wg,
Expand All @@ -59,28 +71,9 @@ func init() {
},
}

wg.Add(1)
// start a goroutine to write to the file
// and close the file when the glogger is closed
// this will block until the queue is empty
// and all the messages have been written
// to the file
// the is the only log writter for glogger
go func() {
defer wg.Done()

for {

// dequeue new messages to be logged,
// if chan is closed, break from the loop and close logger
msg, ok := <-defaultGlogger.queue
if ok {
defaultGlogger.out.Write([]byte(msg.(string) + "\n"))
} else {
break
}
}
}()
sink(&defaultGlogger.glog)
return defaultGlogger
}

// safely close the default logger
Expand All @@ -89,92 +82,55 @@ func Cleanup() {
defaultGlogger.wg.Wait()
}

// UnstructureGlogger creates a new Glog object with the given file name and options for formatting
// NewUnstructureGlogger creates a new Glog object with the given file name and options for formatting
// the log messages. The file is created if it does not exist.
// The file is opened in append mode.
// The log messages are queued and written to the file in a separate goroutine.
// The queue is unbuffered.
func UnstructureGlogger(filePath string, options ...Options) Glogger {
func NewUnstructureGlogger(filePath string, options ...Options) Glogger {

var wg sync.WaitGroup
// create the file for logging
f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
// create new unstructured glogger
glogger, err := newUnstructuredGlogger(filePath, options...)
if err != nil {
panic(err)
}

// create a new glogger
glogger := UnstructureGlog{
Glog: Glog{
out: f,
queue: make(chan interface{}, 1000),
wg: &wg,
options: options,
depth: 1,
},
return nil
}

wg.Add(1)
// start a goroutine to write to the file
// and close the file when the glogger is closed
// this will block until the queue is empty
// and all the messages have been written
// to the file
// the is the only log writter for glogger
go func() {
defer wg.Done()
defer f.Close()

for {

// dequeue new messages to be logged,
// if chan is closed, break from the loop and close logger
msg, ok := <-glogger.queue
if ok {
glogger.out.Write([]byte(msg.(string) + "\n"))
} else {
break
}
}
}()
return &glogger
sink(&glogger.glog)
return glogger
}

// JSONGlogger creates a new Glog object with the given file name and options for formatting
// NewJSONGlogger creates a new Glog object with the given file name and options for formatting
// the log messages. The file is created if it does not exist.
// The file is opened in append mode.
// The log messages are queued and written to the file in a separate goroutine.
// The queue is unbuffered.
func JSONGlogger(filePath string, options ...Options) Glogger {
func NewJSONGlogger(filePath string, options ...Options) Glogger {

var wg sync.WaitGroup
// create the file for logging
f, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
// create new unstructured glogger
glogger, err := newJSONGlogger(filePath, options...)
if err != nil {
panic(err)
return nil
}

// create a new glogger
glogger := JSONGlog{
Glog: Glog{
out: f,
queue: make(chan interface{}, 1000),
wg: &wg,
options: options,
depth: 1,
},
}
// start a goroutine to write to the file
sink(&glogger.glog)
return glogger
}

wg.Add(1)
// sink for logging asynchronously
func sink(glogger *glog) {

glogger.wg.Add(1)
// start a goroutine to write to the file
// and close the file when the glogger is closed
// this will block until the queue is empty
// and all the messages have been written
// to the file
// the is the only log writter for glogger
go func() {
defer wg.Done()
defer f.Close()
defer glogger.wg.Done()
// defer glogger.out.Close()

for {

Expand All @@ -188,27 +144,46 @@ func JSONGlogger(filePath string, options ...Options) Glogger {
}
}
}()
return &glogger
}

// Error logs the error message to the file
func Error(format string, msg ...interface{}) {
defaultGlogger.log(format, ERROR, msg...)
func Error(msg ...interface{}) {
defaultGlogger.log(ERROR, msg...)
}

// Warn logs the warning message to the file
func Warn(msg ...interface{}) {
defaultGlogger.log(WARN, msg...)
}

// Info logs the warning message to the file
func Info(msg ...interface{}) {
defaultGlogger.log(INFO, msg...)
}

// Debug logs the warning message to the file
func Debug(msg ...interface{}) {
defaultGlogger.log(DEBUG, msg...)
}

// Error logs the error message to the file
func Errorf(format string, msg ...interface{}) {
defaultGlogger.logf(format, ERROR, msg...)
}

// Warn logs the warning message to the file
func Warn(format string, msg ...interface{}) {
defaultGlogger.log(format, WARN, msg...)
func Warnf(format string, msg ...interface{}) {
defaultGlogger.logf(format, WARN, msg...)
}

// Info logs the warning message to the file
func Info(format string, msg ...interface{}) {
defaultGlogger.log(format, INFO, msg...)
func Infof(format string, msg ...interface{}) {
defaultGlogger.logf(format, INFO, msg...)
}

// Debug logs the warning message to the file
func Debug(format string, msg ...interface{}) {
defaultGlogger.log(format, DEBUG, msg...)
func Debugf(format string, msg ...interface{}) {
defaultGlogger.logf(format, DEBUG, msg...)
}

// returns the string representation of the log level
Expand Down
Loading