Skip to content

Taruti/update upstream+hilyjiang repo #5

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

Merged
merged 19 commits into from
Mar 9, 2016
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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

## 2.0.0-rc1 (2016-02-11)

Time flies and it has been three years since this package was first released.
There have been a couple of API changes I have wanted to do for some time but
I've tried to maintain backwards compatibility. Some inconsistencies in the
API have started to show, proper vendor support in Go out of the box and
the fact that `go vet` will give warnings -- I have decided to bump the major
version.

* Make eg. `Info` and `Infof` do different things. You want to change all calls
to `Info` with a string format go to `Infof` etc. In many cases, `go vet` will
guide you.
* `Id` in `Record` is now called `ID`

## 1.0.0 (2013-02-21)

Initial release
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ is customizable and supports different logging backends like syslog, file and
memory. Multiple backends can be utilized with different log levels per backend
and logger.

**_NOTE:_** backwards compatibility promise have been dropped for master. Please
vendor this package or use `gopkg.in/op/go-logging.v1` for previous version. See
[changelog](CHANGELOG.md) for details.

## Example

Let's have a look at an [example](examples/example.go) which demonstrates most
Expand Down Expand Up @@ -74,7 +78,7 @@ func main() {

After this command *go-logging* is ready to use. Its source will be in:

$GOROOT/src/pkg/github.com/op/go-logging
$GOPATH/src/pkg/github.com/op/go-logging

You can use `go get -u` to update the package.

Expand Down
11 changes: 11 additions & 0 deletions backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@

package logging

import (
"sync"
)

// defaultBackend is the backend used for all logging calls.
var defaultBackend LeveledBackend
var defaultBackendMutex sync.Mutex

func init() {
defaultBackendMutex = sync.Mutex{}
}

// Backend is the interface which a log backend need to implement to be able to
// be used as a logging backend.
Expand All @@ -23,7 +32,9 @@ func SetBackend(backends ...Backend) LeveledBackend {
backend = MultiLogger(backends...)
}

defaultBackendMutex.Lock()
defaultBackend = AddModuleLevel(backend)
defaultBackendMutex.Unlock()
return defaultBackend
}

Expand Down
61 changes: 55 additions & 6 deletions format.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"sync"
"time"
Expand All @@ -39,6 +40,7 @@ const (
fmtVerbShortpkg
fmtVerbLongfunc
fmtVerbShortfunc
fmtVerbCallpath
fmtVerbLevelColor

// Keep last, there are no match for these below.
Expand All @@ -60,6 +62,7 @@ var fmtVerbs = []string{
"shortpkg",
"longfunc",
"shortfunc",
"callpath",
"color",
}

Expand All @@ -79,6 +82,7 @@ var defaultVerbsLayout = []string{
"s",
"s",
"s",
"0",
"",
}

Expand Down Expand Up @@ -159,6 +163,7 @@ type stringFormatter struct {
// %{message} Message (string)
// %{longfile} Full file name and line number: /a/b/c/d.go:23
// %{shortfile} Final file name element and line number: d.go:23
// %{callpath} Callpath like main.a.b.c...c "..." meaning recursive call ~. meaning truncated path
// %{color} ANSI color based on log level
//
// For normal types, the output can be customized by using the 'verbs' defined
Expand All @@ -175,6 +180,9 @@ type stringFormatter struct {
// "%{color:bold}%{time:15:04:05} %{level:-8s}%{color:reset} %{message}" will
// just colorize the time and level, leaving the message uncolored.
//
// For the 'callpath' verb, the output can be adjusted to limit the printing
// the stack depth. i.e. '%{callpath:3}' will print '~.a.b.c'
//
// Colors on Windows is unfortunately not supported right now and is currently
// a no-op.
//
Expand All @@ -187,6 +195,7 @@ type stringFormatter struct {
// %{shortpkg} Base package path, eg. go-logging
// %{longfunc} Full function name, eg. littleEndian.PutUint32
// %{shortfunc} Base function name, eg. PutUint32
// %{callpath} Call function path, eg. main.a.b.c
func NewStringFormatter(format string) (Formatter, error) {
var fmter = &stringFormatter{}

Expand All @@ -211,12 +220,12 @@ func NewStringFormatter(format string) (Formatter, error) {
}

// Handle layout customizations or use the default. If this is not for the
// time or color formatting, we need to prefix with %.
// time, color formatting or callpath, we need to prefix with %.
layout := defaultVerbsLayout[verb]
if m[4] != -1 {
layout = format[m[4]:m[5]]
}
if verb != fmtVerbTime && verb != fmtVerbLevelColor {
if verb != fmtVerbTime && verb != fmtVerbLevelColor && verb != fmtVerbCallpath {
layout = "%" + layout
}

Expand All @@ -233,12 +242,13 @@ func NewStringFormatter(format string) (Formatter, error) {
if err != nil {
panic(err)
}
testFmt := "hello %s"
r := &Record{
Id: 12345,
ID: 12345,
Time: t,
Module: "logger",
fmt: "hello %s",
args: []interface{}{"go"},
Args: []interface{}{"go"},
fmt: &testFmt,
}
if err := fmter.Format(0, r, &bytes.Buffer{}); err != nil {
return nil, err
Expand Down Expand Up @@ -269,14 +279,20 @@ func (f *stringFormatter) Format(calldepth int, r *Record, output io.Writer) err
output.Write([]byte(r.Time.Format(part.layout)))
} else if part.verb == fmtVerbLevelColor {
doFmtVerbLevelColor(part.layout, r.Level, output)
} else if part.verb == fmtVerbCallpath {
depth, err := strconv.Atoi(part.layout)
if err != nil {
depth = 0
}
output.Write([]byte(formatCallpath(calldepth+1, depth)))
} else {
var v interface{}
switch part.verb {
case fmtVerbLevel:
v = r.Level
break
case fmtVerbID:
v = r.Id
v = r.ID
break
case fmtVerbPid:
v = pid
Expand Down Expand Up @@ -343,6 +359,39 @@ func formatFuncName(v fmtVerb, f string) string {
panic("unexpected func formatter")
}

func formatCallpath(calldepth int, depth int) string {
v := ""
callers := make([]uintptr, 64)
n := runtime.Callers(calldepth+2, callers)
oldPc := callers[n-1]

start := n - 3
if depth > 0 && start >= depth {
start = depth - 1
v += "~."
}
recursiveCall := false
for i := start; i >= 0; i-- {
pc := callers[i]
if oldPc == pc {
recursiveCall = true
continue
}
oldPc = pc
if recursiveCall {
recursiveCall = false
v += ".."
}
if i < start {
v += "."
}
if f := runtime.FuncForPC(pc); f != nil {
v += formatFuncName(fmtVerbShortfunc, f.Name())
}
}
return v
}

// backendFormatter combines a backend with a specific formatter making it
// possible to have different log formats for different backends.
type backendFormatter struct {
Expand Down
6 changes: 6 additions & 0 deletions level.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type moduleLeveled struct {
backend Backend
formatter Formatter
once sync.Once
mutex sync.Mutex
}

// AddModuleLevel wraps a log backend with knobs to have different log levels
Expand All @@ -81,13 +82,15 @@ func AddModuleLevel(backend Backend) LeveledBackend {
leveled = &moduleLeveled{
levels: make(map[string]Level),
backend: backend,
mutex: sync.Mutex{},
}
}
return leveled
}

// GetLevel returns the log level for the given module.
func (l *moduleLeveled) GetLevel(module string) Level {
l.mutex.Lock()
level, exists := l.levels[module]
if exists == false {
level, exists = l.levels[""]
Expand All @@ -96,12 +99,15 @@ func (l *moduleLeveled) GetLevel(module string) Level {
level = DEBUG
}
}
l.mutex.Unlock()
return level
}

// SetLevel sets the log level for the given module.
func (l *moduleLeveled) SetLevel(level Level, module string) {
l.mutex.Lock()
l.levels[module] = level
l.mutex.Unlock()
}

// IsEnabledFor will return true if logging is enabled for the given module.
Expand Down
13 changes: 10 additions & 3 deletions log_nix.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import (

// LogBackend utilizes the standard log module.
type LogBackend struct {
Logger *log.Logger
Color bool
Logger *log.Logger
Color bool
ColorConfig []string
}

// NewLogBackend creates a new LogBackend.
Expand All @@ -26,8 +27,13 @@ func NewLogBackend(out io.Writer, prefix string, flag int) *LogBackend {
// Log implements the Backend interface.
func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error {
if b.Color {
col := colors[level]
if len(b.ColorConfig) > int(level) && b.ColorConfig[level] != "" {
col = b.ColorConfig[level]
}

buf := &bytes.Buffer{}
buf.Write([]byte(colors[level]))
buf.Write([]byte(col))
buf.Write([]byte(rec.Formatted(calldepth + 1)))
buf.Write([]byte("\033[0m"))
// For some reason, the Go logger arbitrarily decided "2" was the correct
Expand All @@ -37,3 +43,4 @@ func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error {

return b.Logger.Output(calldepth+2, rec.Formatted(calldepth+1))
}

45 changes: 45 additions & 0 deletions log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,51 @@ func TestLogCalldepth(t *testing.T) {
}
}

func c(log *Logger) { log.Info("test callpath") }
func b(log *Logger) { c(log) }
func a(log *Logger) { b(log) }

func rec(log *Logger, r int) {
if r == 0 {
a(log)
return
}
rec(log, r-1)
}

func testCallpath(t *testing.T, format string, expect string) {
buf := &bytes.Buffer{}
SetBackend(NewLogBackend(buf, "", log.Lshortfile))
SetFormatter(MustStringFormatter(format))

logger := MustGetLogger("test")
rec(logger, 6)

parts := strings.SplitN(buf.String(), " ", 3)

// Verify that the correct filename is registered by the stdlib logger
if !strings.HasPrefix(parts[0], "log_test.go:") {
t.Errorf("incorrect filename: %s", parts[0])
}
// Verify that the correct callpath is registered by go-logging
if !strings.HasPrefix(parts[1], expect) {
t.Errorf("incorrect callpath: %s", parts[1])
}
// Verify that the correct message is registered by go-logging
if !strings.HasPrefix(parts[2], "test callpath") {
t.Errorf("incorrect message: %s", parts[2])
}
}

func TestLogCallpath(t *testing.T) {
testCallpath(t, "%{callpath} %{message}", "TestLogCallpath.testCallpath.rec...rec.a.b.c")
testCallpath(t, "%{callpath:-1} %{message}", "TestLogCallpath.testCallpath.rec...rec.a.b.c")
testCallpath(t, "%{callpath:0} %{message}", "TestLogCallpath.testCallpath.rec...rec.a.b.c")
testCallpath(t, "%{callpath:1} %{message}", "~.c")
testCallpath(t, "%{callpath:2} %{message}", "~.b.c")
testCallpath(t, "%{callpath:3} %{message}", "~.a.b.c")
}

func BenchmarkLogMemoryBackendIgnored(b *testing.B) {
backend := SetBackend(NewMemoryBackend(1024))
backend.SetLevel(INFO, "")
Expand Down
Loading