Skip to content

Commit

Permalink
Merge pull request apsdehal#9 from gjvnq/master
Browse files Browse the repository at this point in the history
Added line number, function name and printf-like methods
  • Loading branch information
apsdehal committed Jan 28, 2017
2 parents db2e3f4 + 41bcc36 commit 15baca6
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 59 deletions.
11 changes: 10 additions & 1 deletion README.md
Expand Up @@ -15,7 +15,8 @@ Example [program](examples/example.go) demonstrates how to use the logger.
package main

import (
"github.com/apsdehal/go-logger"
"github.com/gjvnq/go-logger"
"os"
)

func main () {
Expand All @@ -29,16 +30,24 @@ func main () {

// Critically log critical
log.Critical("This is Critical!")
log.CriticalF("%+v", err)
// Debug
log.Debug("This is Debug!")
log.DebugF("Here are some numbers: %d %d %f", 10, -3, 3.14)
// Give the Warning
log.Warning("This is Warning!")
log.WarningF("This is Warning!")
// Show the error
log.Error("This is Error!")
log.ErrorF("This is Error!")
// Notice
log.Notice("This is Notice!")
log.NoticeF("%s %s", "This", "is Notice!")
// Show the info
log.Info("This is Info!")
log.InfoF("This is %s!", "Info")

log.StackAsError("Message before printing stack");
}
```

Expand Down
172 changes: 126 additions & 46 deletions logger.go
Expand Up @@ -3,22 +3,25 @@ package logger

// Import packages
import (
"bytes"
"fmt"
"log"
"time"
"os"
"io"
"sync/atomic"
"bytes"
"fmt"
"io"
"log"
"os"
"path"
"runtime"
"sync/atomic"
"time"
)

var (
// Map for te various codes of colors
colors map[string]string

// Contains color strings for stdout
logNo uint64
)

// Color numbers for stdout
const (
Black = (iota + 30)
Expand All @@ -35,19 +38,21 @@ const (
// if colored output is to be produced
type Worker struct {
Minion *log.Logger
Color int
Color int
}

// Info class, Contains all the info on what has to logged, time is the current time, Module is the specific module
// For which we are logging, level is the state, importance and type of message logged,
// Message contains the string to be logged, format is the format of string to be passed to sprintf
type Info struct {
Id uint64
Time string
Module string
Level string
Message string
format string
Id uint64
Time string
Module string
Level string
Line int
Filename string
Message string
format string
}

// Logger class that is an interface to user to log messages, Module is the module for which we are testing
Expand All @@ -59,13 +64,13 @@ type Logger struct {

// Returns a proper string to be outputted for a particular info
func (r *Info) Output() string {
msg := fmt.Sprintf(r.format, r.Id, r.Time, r.Level, r.Message )
msg := fmt.Sprintf(r.format, r.Id, r.Time, r.Filename, r.Line, r.Level, r.Message)
return msg
}

// Returns an instance of worker class, prefix is the string attached to every log,
// Returns an instance of worker class, prefix is the string attached to every log,
// flag determine the log params, color parameters verifies whether we need colored outputs or not
func NewWorker(prefix string, flag int, color int, out io.Writer) *Worker{
func NewWorker(prefix string, flag int, color int, out io.Writer) *Worker {
return &Worker{Minion: log.New(out, prefix, flag), Color: color}
}

Expand Down Expand Up @@ -95,7 +100,7 @@ func initColors() {
"WARNING": colorString(Yellow),
"NOTICE": colorString(Green),
"DEBUG": colorString(Cyan),
"INFO" : colorString(White),
"INFO": colorString(White),
}
}

Expand All @@ -109,75 +114,150 @@ func New(args ...interface{}) (*Logger, error) {
var color int = 1
var out io.Writer = os.Stderr

for _, arg := range(args) {
for _, arg := range args {
switch t := arg.(type) {
case string:
module = t
case int:
color = t
case io.Writer:
out = t
default:
panic("logger: Unknown argument")
case string:
module = t
case int:
color = t
case io.Writer:
out = t
default:
panic("logger: Unknown argument")
}
}
newWorker := NewWorker("", 0, color, out)
return &Logger{Module: module, worker: newWorker}, nil
return &Logger{Module: module, worker: newWorker}, nil
}

// The log commnand is the function available to user to log message, lvl specifies
// the degree of the messagethe user wants to log, message is the info user wants to log
func (l *Logger) Log(lvl string, message string) {
var formatString string = "#%d %s β–Ά %.3s %s"
l.log_internal(lvl, message, 2)
}

func (l *Logger) log_internal(lvl string, message string, pos int) {
var formatString string = "#%d %s %s:%d β–Ά %.3s %s"
_, filename, line, _ := runtime.Caller(pos)
filename = path.Base(filename)
info := &Info{
Id: atomic.AddUint64(&logNo, 1),
Time: time.Now().Format("2006-01-02 15:04:05") ,
Module: l.Module,
Level: lvl,
Message: message,
format: formatString,
Id: atomic.AddUint64(&logNo, 1),
Time: time.Now().Format("2006-01-02 15:04:05"),
Module: l.Module,
Level: lvl,
Message: message,
Filename: filename,
Line: line,
format: formatString,
}
l.worker.Log(lvl, 2, info)
}

// Fatal is just like func l,Cr.tical logger except that it is followed by exit to program
// Fatal is just like func l.Critical logger except that it is followed by exit to program
func (l *Logger) Fatal(message string) {
l.Log("CRITICAL", message)
l.log_internal("CRITICAL", message, 2)
os.Exit(1)
}

// FatalF is just like func l.CriticalF logger except that it is followed by exit to program
func (l *Logger) FatalF(format string, a ...interface{}) {
l.log_internal("CRITICAL", fmt.Sprintf(format, a...), 2)
os.Exit(1)
}

// Panic is just like func l.Critical except that it is followed by a call to panic
func (l *Logger) Panic(message string) {
l.Log("CRITICAL", message)
l.log_internal("CRITICAL", message, 2)
panic(message)
}

// PanicF is just like func l.CriticalF except that it is followed by a call to panic
func (l *Logger) PanicF(format string, a ...interface{}) {
l.log_internal("CRITICAL", fmt.Sprintf(format, a...), 2)
panic(fmt.Sprintf(format, a...))
}

// Critical logs a message at a Critical Level
func (l *Logger) Critical(message string) {
l.Log("CRITICAL", message)
l.log_internal("CRITICAL", message, 2)
}

// CriticalF logs a message at Critical level using the same syntax and options as fmt.Printf
func (l *Logger) CriticalF(format string, a ...interface{}) {
l.log_internal("CRITICAL", fmt.Sprintf(format, a...), 2)
}

// Error logs a message at Error level
func (l *Logger) Error(message string) {
l.Log("ERROR", message)
l.log_internal("ERROR", message, 2)
}

// ErrorF logs a message at Error level using the same syntax and options as fmt.Printf
func (l *Logger) ErrorF(format string, a ...interface{}) {
l.log_internal("ERROR", fmt.Sprintf(format, a...), 2)
}

// Warning logs a message at Warning level
func (l *Logger) Warning(message string) {
l.Log("WARNING", message)
l.log_internal("WARNING", message, 2)
}

// WarningF logs a message at Warning level using the same syntax and options as fmt.Printf
func (l *Logger) WarningF(format string, a ...interface{}) {
l.log_internal("WARNING", fmt.Sprintf(format, a...), 2)
}

// Notice logs a message at Notice level
func (l *Logger) Notice(message string) {
l.Log("NOTICE", message)
l.log_internal("NOTICE", message, 2)
}

// NoticeF logs a message at Notice level using the same syntax and options as fmt.Printf
func (l *Logger) NoticeF(format string, a ...interface{}) {
l.log_internal("NOTICE", fmt.Sprintf(format, a...), 2)
}

// Info logs a message at Info level
func (l *Logger) Info(message string) {
l.Log("INFO", message)
l.log_internal("INFO", message, 2)
}

// InfoF logs a message at Info level using the same syntax and options as fmt.Printf
func (l *Logger) InfoF(format string, a ...interface{}) {
l.log_internal("INFO", fmt.Sprintf(format, a...), 2)
}

// Debug logs a message at Debug level
func (l *Logger) Debug(message string) {
l.Log("DEBUG", message)
}
l.log_internal("DEBUG", message, 2)
}

// DebugF logs a message at Debug level using the same syntax and options as fmt.Printf
func (l *Logger) DebugF(format string, a ...interface{}) {
l.log_internal("DEBUG", fmt.Sprintf(format, a...), 2)
}

// Prints this goroutine's execution stack as an error with an optional message at the begining
func (l *Logger) StackAsError(message string) {
if message == "" {
message = "Stack info"
}
message += "\n"
l.log_internal("ERROR", message+Stack(), 2)
}

// Prints this goroutine's execution stack as critical with an optional message at the begining
func (l *Logger) StackAsCritical(message string) {
if message == "" {
message = "Stack info"
}
message += "\n"
l.log_internal("CRITICAL", message+Stack(), 2)
}

// Returns a string with the execution stack for this goroutine
func Stack() string {
buf := make([]byte, 1000000)
runtime.Stack(buf, false)
return string(buf)
}
24 changes: 12 additions & 12 deletions logger_test.go
@@ -1,8 +1,8 @@
package logger

import (
"testing"
"os"
"testing"
)

func BenchmarkLoggerLog(b *testing.B) {
Expand All @@ -13,7 +13,7 @@ func BenchmarkLoggerLog(b *testing.B) {
}

var tests = []struct {
level string
level string
message string
}{
{
Expand Down Expand Up @@ -78,39 +78,39 @@ func TestColorString(t *testing.T) {

func TestInitColors(t *testing.T) {
initColors()
var tests = []struct{
level string
color int
var tests = []struct {
level string
color int
colorString string
}{
{
"CRITICAL",
Magenta,
Magenta,
"\033[35m",
},
{
"ERROR",
Red,
Red,
"\033[31m",
},
{
"WARNING",
Yellow,
Yellow,
"\033[33m",
},
{
"NOTICE",
Green,
Green,
"\033[32m",
},
{
"DEBUG",
Cyan,
Cyan,
"\033[36m",
},
{
"INFO",
White,
White,
"\033[37m",
},
}
Expand All @@ -136,4 +136,4 @@ func BenchmarkNewWorker(b *testing.B) {
panic("Failed to initiate worker")
}
}
}
}

0 comments on commit 15baca6

Please sign in to comment.