1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-23 13:44:27 +08:00

Merge pull request #1359 from rht/cleanup-logging

Cleanup logging 1
This commit is contained in:
Juan Batiz-Benet
2015-06-18 04:47:34 -07:00
47 changed files with 95 additions and 2297 deletions

4
Godeps/Godeps.json generated
View File

@ -231,10 +231,6 @@
"ImportPath": "github.com/syndtr/gosnappy/snappy",
"Rev": "156a073208e131d7d2e212cb749feae7c339e846"
},
{
"ImportPath": "github.com/whyrusleeping/go-logging",
"Rev": "128b9855511a4ea3ccbcf712695baf2bab72e134"
},
{
"ImportPath": "github.com/whyrusleeping/go-metrics",
"Rev": "1cd8009604ec2238b5a71305a0ecd974066e0e16"

View File

@ -1,6 +0,0 @@
language: go
go:
- 1.0
- 1.1
- tip

View File

@ -1,5 +0,0 @@
Alec Thomas <alec@swapoff.org>
Guilhem Lettron <guilhem.lettron@optiflows.com>
Ivan Daniluk <ivan.daniluk@gmail.com>
Nimi Wariboko Jr <nimi@channelmeter.com>
Róbert Selvek <robert.selvek@gmail.com>

View File

@ -1,27 +0,0 @@
Copyright (c) 2013 Örjan Persson. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,89 +0,0 @@
## Golang logging library
[![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/op/go-logging) [![build](https://img.shields.io/travis/op/go-logging.svg?style=flat)](https://travis-ci.org/op/go-logging)
Package logging implements a logging infrastructure for Go. Its output format
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.
## Example
Let's have a look at an [example](examples/example.go) which demonstrates most
of the features found in this library.
[![Example Output](examples/example.png)](examples/example.go)
```go
package main
import (
"os"
"github.com/op/go-logging"
)
var log = logging.MustGetLogger("example")
// Example format string. Everything except the message has a custom color
// which is dependent on the log level. Many fields have a custom output
// formatting too, eg. the time returns the hour down to the milli second.
var format = logging.MustStringFormatter(
"%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}",
)
// Password is just an example type implementing the Redactor interface. Any
// time this is logged, the Redacted() function will be called.
type Password string
func (p Password) Redacted() interface{} {
return logging.Redact(string(p))
}
func main() {
// For demo purposes, create two backend for os.Stderr.
backend1 := logging.NewLogBackend(os.Stderr, "", 0)
backend2 := logging.NewLogBackend(os.Stderr, "", 0)
// For messages written to backend2 we want to add some additional
// information to the output, including the used log level and the name of
// the function.
backend2Formatter := logging.NewBackendFormatter(backend2, format)
// Only errors and more severe messages should be sent to backend1
backend1Leveled := logging.AddModuleLevel(backend1)
backend1Leveled.SetLevel(logging.ERROR, "")
// Set the backends to be used.
logging.SetBackend(backend1Leveled, backend2Formatter)
log.Debug("debug %s", Password("secret"))
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("err")
log.Critical("crit")
}
```
## Installing
### Using *go get*
$ go get github.com/op/go-logging
After this command *go-logging* is ready to use. Its source will be in:
$GOROOT/src/pkg/github.com/op/go-logging
You can use `go get -u` to update the package.
## Documentation
For docs, see http://godoc.org/github.com/op/go-logging or run:
$ godoc github.com/op/go-logging
## Additional resources
* [wslog](https://godoc.org/github.com/cryptix/go/logging/wslog) -- exposes log messages through a WebSocket.

View File

@ -1,39 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
// defaultBackend is the backend used for all logging calls.
var defaultBackend LeveledBackend
// Backend is the interface which a log backend need to implement to be able to
// be used as a logging backend.
type Backend interface {
Log(Level, int, *Record) error
}
// Set backend replaces the backend currently set with the given new logging
// backend.
func SetBackend(backends ...Backend) LeveledBackend {
var backend Backend
if len(backends) == 1 {
backend = backends[0]
} else {
backend = MultiLogger(backends...)
}
defaultBackend = AddModuleLevel(backend)
return defaultBackend
}
// SetLevel sets the logging level for the specified module. The module
// corresponds to the string specified in GetLogger.
func SetLevel(level Level, module string) {
defaultBackend.SetLevel(level, module)
}
// GetLevel returns the logging level for the specified module.
func GetLevel(module string) Level {
return defaultBackend.GetLevel(module)
}

View File

@ -1,40 +0,0 @@
package logging
import "os"
func Example() {
// This call is for testing purposes and will set the time to unix epoch.
InitForTesting(DEBUG)
var log = MustGetLogger("example")
// For demo purposes, create two backend for os.Stdout.
//
// os.Stderr should most likely be used in the real world but then the
// "Output:" check in this example would not work.
backend1 := NewLogBackend(os.Stdout, "", 0)
backend2 := NewLogBackend(os.Stdout, "", 0)
// For messages written to backend2 we want to add some additional
// information to the output, including the used log level and the name of
// the function.
var format = MustStringFormatter(
"%{time:15:04:05.000} %{shortfunc} %{level:.1s} %{message}",
)
backend2Formatter := NewBackendFormatter(backend2, format)
// Only errors and more severe messages should be sent to backend2
backend2Leveled := AddModuleLevel(backend2Formatter)
backend2Leveled.SetLevel(ERROR, "")
// Set the backends to be used and the default level.
SetBackend(backend1, backend2Leveled)
log.Debug("debug %s", "arg")
log.Error("error")
// Output:
// debug arg
// error
// 00:00:00.000 Example E error
}

View File

@ -1,49 +0,0 @@
package main
import (
"os"
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging"
)
var log = logging.MustGetLogger("example")
// Example format string. Everything except the message has a custom color
// which is dependent on the log level. Many fields have a custom output
// formatting too, eg. the time returns the hour down to the milli second.
var format = logging.MustStringFormatter(
"%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}",
)
// Password is just an example type implementing the Redactor interface. Any
// time this is logged, the Redacted() function will be called.
type Password string
func (p Password) Redacted() interface{} {
return logging.Redact(string(p))
}
func main() {
// For demo purposes, create two backend for os.Stderr.
backend1 := logging.NewLogBackend(os.Stderr, "", 0)
backend2 := logging.NewLogBackend(os.Stderr, "", 0)
// For messages written to backend2 we want to add some additional
// information to the output, including the used log level and the name of
// the function.
backend2Formatter := logging.NewBackendFormatter(backend2, format)
// Only errors and more severe messages should be sent to backend1
backend1Leveled := logging.AddModuleLevel(backend1)
backend1Leveled.SetLevel(logging.ERROR, "")
// Set the backends to be used.
logging.SetBackend(backend1Leveled, backend2Formatter)
log.Debug("debug %s", Password("secret"))
log.Info("info")
log.Notice("notice")
log.Warning("warning")
log.Error("err")
log.Critical("crit")
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,368 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
"time"
)
// TODO see Formatter interface in fmt/print.go
// TODO try text/template, maybe it have enough performance
// TODO other template systems?
// TODO make it possible to specify formats per backend?
type fmtVerb int
const (
fmtVerbTime fmtVerb = iota
fmtVerbLevel
fmtVerbId
fmtVerbPid
fmtVerbProgram
fmtVerbModule
fmtVerbMessage
fmtVerbLongfile
fmtVerbShortfile
fmtVerbLongpkg
fmtVerbShortpkg
fmtVerbLongfunc
fmtVerbShortfunc
fmtVerbLevelColor
// Keep last, there are no match for these below.
fmtVerbUnknown
fmtVerbStatic
)
var fmtVerbs = []string{
"time",
"level",
"id",
"pid",
"program",
"module",
"message",
"longfile",
"shortfile",
"longpkg",
"shortpkg",
"longfunc",
"shortfunc",
"color",
}
const rfc3339Milli = "2006-01-02T15:04:05.999Z07:00"
var defaultVerbsLayout = []string{
rfc3339Milli,
"s",
"d",
"d",
"s",
"s",
"s",
"s",
"s",
"s",
"s",
"s",
"s",
"",
}
var (
pid = os.Getpid()
program = filepath.Base(os.Args[0])
)
func getFmtVerbByName(name string) fmtVerb {
for i, verb := range fmtVerbs {
if name == verb {
return fmtVerb(i)
}
}
return fmtVerbUnknown
}
// Formatter is the required interface for a custom log record formatter.
type Formatter interface {
Format(calldepth int, r *Record, w io.Writer) error
}
// formatter is used by all backends unless otherwise overriden.
var formatter struct {
sync.RWMutex
def Formatter
}
func getFormatter() Formatter {
formatter.RLock()
defer formatter.RUnlock()
return formatter.def
}
var (
// DefaultFormatter is the default formatter used and is only the message.
DefaultFormatter Formatter = MustStringFormatter("%{message}")
// Glog format
GlogFormatter Formatter = MustStringFormatter("%{level:.1s}%{time:0102 15:04:05.999999} %{pid} %{shortfile}] %{message}")
)
// SetFormatter sets the default formatter for all new backends. A backend will
// fetch this value once it is needed to format a record. Note that backends
// will cache the formatter after the first point. For now, make sure to set
// the formatter before logging.
func SetFormatter(f Formatter) {
formatter.Lock()
defer formatter.Unlock()
formatter.def = f
}
var formatRe *regexp.Regexp = regexp.MustCompile(`%{([a-z]+)(?::(.*?[^\\]))?}`)
type part struct {
verb fmtVerb
layout string
}
// stringFormatter contains a list of parts which explains how to build the
// formatted string passed on to the logging backend.
type stringFormatter struct {
parts []part
}
// NewStringFormatter returns a new Formatter which outputs the log record as a
// string based on the 'verbs' specified in the format string.
//
// The verbs:
//
// General:
// %{id} Sequence number for log message (uint64).
// %{pid} Process id (int)
// %{time} Time when log occurred (time.Time)
// %{level} Log level (Level)
// %{module} Module (string)
// %{program} Basename of os.Args[0] (string)
// %{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
// %{color} ANSI color based on log level
//
// For normal types, the output can be customized by using the 'verbs' defined
// in the fmt package, eg. '%{id:04d}' to make the id output be '%04d' as the
// format string.
//
// For time.Time, use the same layout as time.Format to change the time format
// when output, eg "2006-01-02T15:04:05.999Z-07:00".
//
// For the 'color' verb, the output can be adjusted to either use bold colors,
// i.e., '%{color:bold}' or to reset the ANSI attributes, i.e.,
// '%{color:reset}' Note that if you use the color verb explicitly, be sure to
// reset it or else the color state will persist past your log message. e.g.,
// "%{color:bold}%{time:15:04:05} %{level:-8s}%{color:reset} %{message}" will
// just colorize the time and level, leaving the message uncolored.
//
// There's also a couple of experimental 'verbs'. These are exposed to get
// feedback and needs a bit of tinkering. Hence, they might change in the
// future.
//
// Experimental:
// %{longpkg} Full package path, eg. github.com/go-logging
// %{shortpkg} Base package path, eg. go-logging
// %{longfunc} Full function name, eg. littleEndian.PutUint32
// %{shortfunc} Base function name, eg. PutUint32
func NewStringFormatter(format string) (*stringFormatter, error) {
var fmter = &stringFormatter{}
// Find the boundaries of all %{vars}
matches := formatRe.FindAllStringSubmatchIndex(format, -1)
if matches == nil {
return nil, errors.New("logger: invalid log format: " + format)
}
// Collect all variables and static text for the format
prev := 0
for _, m := range matches {
start, end := m[0], m[1]
if start > prev {
fmter.add(fmtVerbStatic, format[prev:start])
}
name := format[m[2]:m[3]]
verb := getFmtVerbByName(name)
if verb == fmtVerbUnknown {
return nil, errors.New("logger: unknown variable: " + name)
}
// Handle layout customizations or use the default. If this is not for the
// time or color formatting, we need to prefix with %.
layout := defaultVerbsLayout[verb]
if m[4] != -1 {
layout = format[m[4]:m[5]]
}
if verb != fmtVerbTime && verb != fmtVerbLevelColor {
layout = "%" + layout
}
fmter.add(verb, layout)
prev = end
}
end := format[prev:]
if end != "" {
fmter.add(fmtVerbStatic, end)
}
// Make a test run to make sure we can format it correctly.
t, err := time.Parse(time.RFC3339, "2010-02-04T21:00:57-08:00")
if err != nil {
panic(err)
}
r := &Record{
Id: 12345,
Time: t,
Module: "logger",
fmt: "hello %s",
args: []interface{}{"go"},
}
if err := fmter.Format(0, r, &bytes.Buffer{}); err != nil {
return nil, err
}
return fmter, nil
}
// MustStringFormatter is equivalent to NewStringFormatter with a call to panic
// on error.
func MustStringFormatter(format string) *stringFormatter {
f, err := NewStringFormatter(format)
if err != nil {
panic("Failed to initialized string formatter: " + err.Error())
}
return f
}
func (f *stringFormatter) add(verb fmtVerb, layout string) {
f.parts = append(f.parts, part{verb, layout})
}
func (f *stringFormatter) Format(calldepth int, r *Record, output io.Writer) error {
for _, part := range f.parts {
if part.verb == fmtVerbStatic {
output.Write([]byte(part.layout))
} else if part.verb == fmtVerbTime {
output.Write([]byte(r.Time.Format(part.layout)))
} else if part.verb == fmtVerbLevelColor {
if part.layout == "bold" {
output.Write([]byte(boldcolors[r.Level]))
} else if part.layout == "reset" {
output.Write([]byte("\033[0m"))
} else {
output.Write([]byte(colors[r.Level]))
}
} else {
var v interface{}
switch part.verb {
case fmtVerbLevel:
v = r.Level
break
case fmtVerbId:
v = r.Id
break
case fmtVerbPid:
v = pid
break
case fmtVerbProgram:
v = program
break
case fmtVerbModule:
v = r.Module
break
case fmtVerbMessage:
v = r.Message()
break
case fmtVerbLongfile, fmtVerbShortfile:
_, file, line, ok := runtime.Caller(calldepth + 1)
if !ok {
file = "???"
line = 0
} else if part.verb == fmtVerbShortfile {
file = filepath.Base(file)
}
v = fmt.Sprintf("%s:%d", file, line)
case fmtVerbLongfunc, fmtVerbShortfunc,
fmtVerbLongpkg, fmtVerbShortpkg:
// TODO cache pc
v = "???"
if pc, _, _, ok := runtime.Caller(calldepth + 1); ok {
if f := runtime.FuncForPC(pc); f != nil {
v = formatFuncName(part.verb, f.Name())
}
}
default:
panic("unhandled format part")
}
fmt.Fprintf(output, part.layout, v)
}
}
return nil
}
// formatFuncName tries to extract certain part of the runtime formatted
// function name to some pre-defined variation.
//
// This function is known to not work properly if the package path or name
// contains a dot.
func formatFuncName(v fmtVerb, f string) string {
i := strings.LastIndex(f, "/")
j := strings.Index(f[i+1:], ".")
if j < 1 {
return "???"
}
pkg, fun := f[:i+j+1], f[i+j+2:]
switch v {
case fmtVerbLongpkg:
return pkg
case fmtVerbShortpkg:
return path.Base(pkg)
case fmtVerbLongfunc:
return fun
case fmtVerbShortfunc:
i = strings.LastIndex(fun, ".")
return fun[i+1:]
}
panic("unexpected func formatter")
}
// backendFormatter combines a backend with a specific formatter making it
// possible to have different log formats for different backends.
type backendFormatter struct {
b Backend
f Formatter
}
// NewBackendFormatter creates a new backend which makes all records that
// passes through it beeing formatted by the specific formatter.
func NewBackendFormatter(b Backend, f Formatter) *backendFormatter {
return &backendFormatter{b, f}
}
// Log implements the Log function required by the Backend interface.
func (bf *backendFormatter) Log(level Level, calldepth int, r *Record) error {
// Make a shallow copy of the record and replace any formatter
r2 := *r
r2.formatter = bf.f
return bf.b.Log(level, calldepth+1, &r2)
}

View File

@ -1,184 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"bytes"
"testing"
)
func TestFormat(t *testing.T) {
backend := InitForTesting(DEBUG)
f, err := NewStringFormatter("%{shortfile} %{time:2006-01-02T15:04:05} %{level:.1s} %{id:04d} %{module} %{message}")
if err != nil {
t.Fatalf("failed to set format: %s", err)
}
SetFormatter(f)
log := MustGetLogger("module")
log.Debug("hello")
line := MemoryRecordN(backend, 0).Formatted(0)
if "format_test.go:24 1970-01-01T00:00:00 D 0001 module hello" != line {
t.Errorf("Unexpected format: %s", line)
}
}
func logAndGetLine(backend *MemoryBackend) string {
MustGetLogger("foo").Debug("hello")
return MemoryRecordN(backend, 0).Formatted(1)
}
func getLastLine(backend *MemoryBackend) string {
return MemoryRecordN(backend, 0).Formatted(1)
}
func realFunc(backend *MemoryBackend) string {
return logAndGetLine(backend)
}
type structFunc struct{}
func (structFunc) Log(backend *MemoryBackend) string {
return logAndGetLine(backend)
}
func TestRealFuncFormat(t *testing.T) {
backend := InitForTesting(DEBUG)
SetFormatter(MustStringFormatter("%{shortfunc}"))
line := realFunc(backend)
if "realFunc" != line {
t.Errorf("Unexpected format: %s", line)
}
}
func TestStructFuncFormat(t *testing.T) {
backend := InitForTesting(DEBUG)
SetFormatter(MustStringFormatter("%{longfunc}"))
var x structFunc
line := x.Log(backend)
if "structFunc.Log" != line {
t.Errorf("Unexpected format: %s", line)
}
}
func TestVarFuncFormat(t *testing.T) {
backend := InitForTesting(DEBUG)
SetFormatter(MustStringFormatter("%{shortfunc}"))
var varFunc = func() string {
return logAndGetLine(backend)
}
line := varFunc()
if "???" == line || "TestVarFuncFormat" == line || "varFunc" == line {
t.Errorf("Unexpected format: %s", line)
}
}
func TestFormatFuncName(t *testing.T) {
var tests = []struct {
filename string
longpkg string
shortpkg string
longfunc string
shortfunc string
}{
{"",
"???",
"???",
"???",
"???"},
{"main",
"???",
"???",
"???",
"???"},
{"main.",
"main",
"main",
"",
""},
{"main.main",
"main",
"main",
"main",
"main"},
{"github.com/op/go-logging.func·001",
"github.com/op/go-logging",
"go-logging",
"func·001",
"func·001"},
{"github.com/op/go-logging.stringFormatter.Format",
"github.com/op/go-logging",
"go-logging",
"stringFormatter.Format",
"Format"},
}
var v string
for _, test := range tests {
v = formatFuncName(fmtVerbLongpkg, test.filename)
if test.longpkg != v {
t.Errorf("%s != %s", test.longpkg, v)
}
v = formatFuncName(fmtVerbShortpkg, test.filename)
if test.shortpkg != v {
t.Errorf("%s != %s", test.shortpkg, v)
}
v = formatFuncName(fmtVerbLongfunc, test.filename)
if test.longfunc != v {
t.Errorf("%s != %s", test.longfunc, v)
}
v = formatFuncName(fmtVerbShortfunc, test.filename)
if test.shortfunc != v {
t.Errorf("%s != %s", test.shortfunc, v)
}
}
}
func TestBackendFormatter(t *testing.T) {
InitForTesting(DEBUG)
// Create two backends and wrap one of the with a backend formatter
b1 := NewMemoryBackend(1)
b2 := NewMemoryBackend(1)
f := MustStringFormatter("%{level} %{message}")
bf := NewBackendFormatter(b2, f)
SetBackend(b1, bf)
log := MustGetLogger("module")
log.Info("foo")
if "foo" != getLastLine(b1) {
t.Errorf("Unexpected line: %s", getLastLine(b1))
}
if "INFO foo" != getLastLine(b2) {
t.Errorf("Unexpected line: %s", getLastLine(b2))
}
}
func BenchmarkStringFormatter(b *testing.B) {
fmt := "%{time:2006-01-02T15:04:05} %{level:.1s} %{id:04d} %{module} %{message}"
f := MustStringFormatter(fmt)
backend := InitForTesting(DEBUG)
buf := &bytes.Buffer{}
log := MustGetLogger("module")
log.Debug("")
record := MemoryRecordN(backend, 0)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := f.Format(1, record, buf); err != nil {
b.Fatal(err)
buf.Truncate(0)
}
}
}

View File

@ -1,124 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"errors"
"strings"
"sync"
)
var ErrInvalidLogLevel = errors.New("logger: invalid log level")
// Level defines all available log levels for log messages.
type Level int
const (
CRITICAL Level = iota
ERROR
WARNING
NOTICE
INFO
DEBUG
)
var levelNames = []string{
"CRITICAL",
"ERROR",
"WARNING",
"NOTICE",
"INFO",
"DEBUG",
}
// String returns the string representation of a logging level.
func (p Level) String() string {
return levelNames[p]
}
// LogLevel returns the log level from a string representation.
func LogLevel(level string) (Level, error) {
for i, name := range levelNames {
if strings.EqualFold(name, level) {
return Level(i), nil
}
}
return ERROR, ErrInvalidLogLevel
}
type Leveled interface {
GetLevel(string) Level
SetLevel(Level, string)
IsEnabledFor(Level, string) bool
}
// LeveledBackend is a log backend with additional knobs for setting levels on
// individual modules to different levels.
type LeveledBackend interface {
Backend
Leveled
}
type moduleLeveled struct {
levels map[string]Level
backend Backend
formatter Formatter
once sync.Once
}
// AddModuleLevel wraps a log backend with knobs to have different log levels
// for different modules.
func AddModuleLevel(backend Backend) LeveledBackend {
var leveled LeveledBackend
var ok bool
if leveled, ok = backend.(LeveledBackend); !ok {
leveled = &moduleLeveled{
levels: make(map[string]Level),
backend: backend,
}
}
return leveled
}
// GetLevel returns the log level for the given module.
func (l *moduleLeveled) GetLevel(module string) Level {
level, exists := l.levels[module]
if exists == false {
level, exists = l.levels[""]
// no configuration exists, default to debug
if exists == false {
level = DEBUG
}
}
return level
}
// SetLevel sets the log level for the given module.
func (l *moduleLeveled) SetLevel(level Level, module string) {
l.levels[module] = level
}
// IsEnabledFor will return true if logging is enabled for the given module.
func (l *moduleLeveled) IsEnabledFor(level Level, module string) bool {
return level <= l.GetLevel(module)
}
func (l *moduleLeveled) Log(level Level, calldepth int, rec *Record) (err error) {
if l.IsEnabledFor(level, rec.Module) {
// TODO get rid of traces of formatter here. BackendFormatter should be used.
rec.formatter = l.getFormatterAndCacheCurrent()
err = l.backend.Log(level, calldepth+1, rec)
}
return
}
func (l *moduleLeveled) getFormatterAndCacheCurrent() Formatter {
l.once.Do(func() {
if l.formatter == nil {
l.formatter = getFormatter()
}
})
return l.formatter
}

View File

@ -1,76 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import "testing"
func TestLevelString(t *testing.T) {
// Make sure all levels can be converted from string -> constant -> string
for _, name := range levelNames {
level, err := LogLevel(name)
if err != nil {
t.Errorf("failed to get level: %v", err)
continue
}
if level.String() != name {
t.Errorf("invalid level conversion: %v != %v", level, name)
}
}
}
func TestLevelLogLevel(t *testing.T) {
tests := []struct {
expected Level
level string
}{
{-1, "bla"},
{INFO, "iNfO"},
{ERROR, "error"},
{WARNING, "warninG"},
}
for _, test := range tests {
level, err := LogLevel(test.level)
if err != nil {
if test.expected == -1 {
continue
} else {
t.Errorf("failed to convert %s: %s", test.level, err)
}
}
if test.expected != level {
t.Errorf("failed to convert %s to level: %s != %s", test.level, test.expected, level)
}
}
}
func TestLevelModuleLevel(t *testing.T) {
backend := NewMemoryBackend(128)
leveled := AddModuleLevel(backend)
leveled.SetLevel(NOTICE, "")
leveled.SetLevel(ERROR, "foo")
leveled.SetLevel(INFO, "foo.bar")
leveled.SetLevel(WARNING, "bar")
expected := []struct {
level Level
module string
}{
{NOTICE, ""},
{NOTICE, "something"},
{ERROR, "foo"},
{INFO, "foo.bar"},
{WARNING, "bar"},
}
for _, e := range expected {
actual := leveled.GetLevel(e.module)
if e.level != actual {
t.Errorf("unexpected level in %s: %s != %s", e.module, e.level, actual)
}
}
}

View File

@ -1,80 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"bytes"
"fmt"
"io"
"log"
)
// TODO initialize here
var colors []string
var boldcolors []string
type color int
const (
colorBlack = (iota + 30)
colorRed
colorGreen
colorYellow
colorBlue
colorMagenta
colorCyan
colorWhite
)
// LogBackend utilizes the standard log module.
type LogBackend struct {
Logger *log.Logger
Color bool
}
// NewLogBackend creates a new LogBackend.
func NewLogBackend(out io.Writer, prefix string, flag int) *LogBackend {
return &LogBackend{Logger: log.New(out, prefix, flag)}
}
func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error {
if b.Color {
buf := &bytes.Buffer{}
buf.Write([]byte(colors[level]))
buf.Write([]byte(rec.Formatted(calldepth + 1)))
buf.Write([]byte("\033[0m"))
// For some reason, the Go logger arbitrarily decided "2" was the correct
// call depth...
return b.Logger.Output(calldepth+2, buf.String())
} else {
return b.Logger.Output(calldepth+2, rec.Formatted(calldepth+1))
}
panic("should not be reached")
}
func colorSeq(color color) string {
return fmt.Sprintf("\033[%dm", int(color))
}
func colorSeqBold(color color) string {
return fmt.Sprintf("\033[%d;1m", int(color))
}
func init() {
colors = []string{
CRITICAL: colorSeq(colorMagenta),
ERROR: colorSeq(colorRed),
WARNING: colorSeq(colorYellow),
NOTICE: colorSeq(colorGreen),
DEBUG: colorSeq(colorCyan),
}
boldcolors = []string{
CRITICAL: colorSeqBold(colorMagenta),
ERROR: colorSeqBold(colorRed),
WARNING: colorSeqBold(colorYellow),
NOTICE: colorSeqBold(colorGreen),
DEBUG: colorSeqBold(colorCyan),
}
}

View File

@ -1,118 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"bytes"
"io/ioutil"
"log"
"strings"
"testing"
)
func TestLogCalldepth(t *testing.T) {
buf := &bytes.Buffer{}
SetBackend(NewLogBackend(buf, "", log.Lshortfile))
SetFormatter(MustStringFormatter("%{shortfile} %{level} %{message}"))
log := MustGetLogger("test")
log.Info("test filename")
parts := strings.SplitN(buf.String(), " ", 2)
// 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 filename is registered by go-logging
if !strings.HasPrefix(parts[1], "log_test.go:") {
t.Errorf("incorrect filename: %s", parts[1])
}
}
func BenchmarkLogMemoryBackendIgnored(b *testing.B) {
backend := SetBackend(NewMemoryBackend(1024))
backend.SetLevel(INFO, "")
RunLogBenchmark(b)
}
func BenchmarkLogMemoryBackend(b *testing.B) {
backend := SetBackend(NewMemoryBackend(1024))
backend.SetLevel(DEBUG, "")
RunLogBenchmark(b)
}
func BenchmarkLogChannelMemoryBackend(b *testing.B) {
channelBackend := NewChannelMemoryBackend(1024)
backend := SetBackend(channelBackend)
backend.SetLevel(DEBUG, "")
RunLogBenchmark(b)
channelBackend.Flush()
}
func BenchmarkLogLeveled(b *testing.B) {
backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0))
backend.SetLevel(INFO, "")
RunLogBenchmark(b)
}
func BenchmarkLogLogBackend(b *testing.B) {
backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0))
backend.SetLevel(DEBUG, "")
RunLogBenchmark(b)
}
func BenchmarkLogLogBackendColor(b *testing.B) {
colorizer := NewLogBackend(ioutil.Discard, "", 0)
colorizer.Color = true
backend := SetBackend(colorizer)
backend.SetLevel(DEBUG, "")
RunLogBenchmark(b)
}
func BenchmarkLogLogBackendStdFlags(b *testing.B) {
backend := SetBackend(NewLogBackend(ioutil.Discard, "", log.LstdFlags))
backend.SetLevel(DEBUG, "")
RunLogBenchmark(b)
}
func BenchmarkLogLogBackendLongFileFlag(b *testing.B) {
backend := SetBackend(NewLogBackend(ioutil.Discard, "", log.Llongfile))
backend.SetLevel(DEBUG, "")
RunLogBenchmark(b)
}
func RunLogBenchmark(b *testing.B) {
password := Password("foo")
log := MustGetLogger("test")
b.ResetTimer()
for i := 0; i < b.N; i++ {
log.Debug("log line for %d and this is rectified: %s", i, password)
}
}
func BenchmarkLogFixed(b *testing.B) {
backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0))
backend.SetLevel(DEBUG, "")
RunLogBenchmarkFixedString(b)
}
func BenchmarkLogFixedIgnored(b *testing.B) {
backend := SetBackend(NewLogBackend(ioutil.Discard, "", 0))
backend.SetLevel(INFO, "")
RunLogBenchmarkFixedString(b)
}
func RunLogBenchmarkFixedString(b *testing.B) {
log := MustGetLogger("test")
b.ResetTimer()
for i := 0; i < b.N; i++ {
log.Debug("some random fixed text")
}
}

View File

@ -1,277 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package logging implements a logging infrastructure for Go. It supports
// different logging backends like syslog, file and memory. Multiple backends
// can be utilized with different log levels per backend and logger.
package logging
import (
"bytes"
"fmt"
"log"
"os"
"strings"
"sync/atomic"
"time"
)
// Redactor is an interface for types that may contain sensitive information
// (like passwords), which shouldn't be printed to the log. The idea was found
// in relog as part of the vitness project.
type Redactor interface {
Redacted() interface{}
}
// Redact returns a string of * having the same length as s.
func Redact(s string) string {
return strings.Repeat("*", len(s))
}
var (
// Sequence number is incremented and utilized for all log records created.
sequenceNo uint64
// timeNow is a customizable for testing purposes.
timeNow = time.Now
)
// Record represents a log record and contains the timestamp when the record
// was created, an increasing id, filename and line and finally the actual
// formatted log line.
type Record struct {
Id uint64
Time time.Time
Module string
Level Level
// message is kept as a pointer to have shallow copies update this once
// needed.
message *string
args []interface{}
fmt string
formatter Formatter
formatted string
}
// Formatted returns the string-formatted version of a record.
func (r *Record) Formatted(calldepth int) string {
if r.formatted == "" {
var buf bytes.Buffer
r.formatter.Format(calldepth+1, r, &buf)
r.formatted = buf.String()
}
return r.formatted
}
// Message returns a string message for outputting. Redacts any record args
// that implement the Redactor interface
func (r *Record) Message() string {
if r.message == nil {
// Redact the arguments that implements the Redactor interface
for i, arg := range r.args {
if redactor, ok := arg.(Redactor); ok == true {
r.args[i] = redactor.Redacted()
}
}
msg := fmt.Sprintf(r.fmt, r.args...)
r.message = &msg
}
return *r.message
}
// Logger is a logging unit. It controls the flow of messages to a given
// (swappable) backend.
type Logger struct {
Module string
backend LeveledBackend
haveBackend bool
// ExtraCallDepth can be used to add additional call depth when getting the
// calling function. This is normally used when wrapping a logger.
ExtraCalldepth int
}
// SetBackend changes the backend of the logger.
func (l *Logger) SetBackend(backend LeveledBackend) {
l.backend = backend
l.haveBackend = true
}
// GetLogger creates and returns a Logger object based on the module name.
// TODO call NewLogger and remove MustGetLogger?
func GetLogger(module string) (*Logger, error) {
return &Logger{Module: module}, nil
}
// MustGetLogger is like GetLogger but panics if the logger can't be created.
// It simplifies safe initialization of a global logger for eg. a package.
func MustGetLogger(module string) *Logger {
logger, err := GetLogger(module)
if err != nil {
panic("logger: " + module + ": " + err.Error())
}
return logger
}
// Reset restores the internal state of the logging library.
func Reset() {
// TODO make a global Init() method to be less magic? or make it such that
// if there's no backends at all configured, we could use some tricks to
// automatically setup backends based if we have a TTY or not.
sequenceNo = 0
b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags))
b.SetLevel(DEBUG, "")
SetFormatter(DefaultFormatter)
timeNow = time.Now
}
// InitForTesting is a convenient method when using logging in a test. Once
// called, the time will be frozen to January 1, 1970 UTC.
func InitForTesting(level Level) *MemoryBackend {
Reset()
memoryBackend := NewMemoryBackend(10240)
leveledBackend := AddModuleLevel(memoryBackend)
leveledBackend.SetLevel(level, "")
SetBackend(leveledBackend)
timeNow = func() time.Time {
return time.Unix(0, 0).UTC()
}
return memoryBackend
}
// IsEnabledFor returns true if the logger is enabled for the given level.
func (l *Logger) IsEnabledFor(level Level) bool {
return defaultBackend.IsEnabledFor(level, l.Module)
}
func (l *Logger) log(lvl Level, format string, args ...interface{}) {
if !l.IsEnabledFor(lvl) {
return
}
// Create the logging record and pass it in to the backend
record := &Record{
Id: atomic.AddUint64(&sequenceNo, 1),
Time: timeNow(),
Module: l.Module,
Level: lvl,
fmt: format,
args: args,
}
// TODO use channels to fan out the records to all backends?
// TODO in case of errors, do something (tricky)
// calldepth=2 brings the stack up to the caller of the level
// methods, Info(), Fatal(), etc.
// ExtraCallDepth allows this to be extended further up the stack in case we
// are wrapping these methods, eg. to expose them package level
if l.haveBackend {
l.backend.Log(lvl, 2+l.ExtraCalldepth, record)
return
}
defaultBackend.Log(lvl, 2+l.ExtraCalldepth, record)
}
// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1).
func (l *Logger) Fatal(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(CRITICAL, "%s", s)
os.Exit(1)
}
// Fatalf is equivalent to l.Critical followed by a call to os.Exit(1).
func (l *Logger) Fatalf(format string, args ...interface{}) {
l.log(CRITICAL, format, args...)
os.Exit(1)
}
// Panic is equivalent to l.Critical(fmt.Sprint()) followed by a call to panic().
func (l *Logger) Panic(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(CRITICAL, "%s", s)
panic(s)
}
// Panicf is equivalent to l.Critical followed by a call to panic().
func (l *Logger) Panicf(format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
l.log(CRITICAL, "%s", s)
panic(s)
}
// Critical logs a message using CRITICAL as log level. (fmt.Sprint())
func (l *Logger) Critical(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(CRITICAL, "%s", s)
}
// Criticalf logs a message using CRITICAL as log level.
func (l *Logger) Criticalf(format string, args ...interface{}) {
l.log(CRITICAL, format, args...)
}
// Error logs a message using ERROR as log level. (fmt.Sprint())
func (l *Logger) Error(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(ERROR, "%s", s)
}
// Errorf logs a message using ERROR as log level.
func (l *Logger) Errorf(format string, args ...interface{}) {
l.log(ERROR, format, args...)
}
// Warning logs a message using WARNING as log level.
func (l *Logger) Warning(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(WARNING, "%s", s)
}
// Warningf logs a message using WARNING as log level.
func (l *Logger) Warningf(format string, args ...interface{}) {
l.log(WARNING, format, args...)
}
// Notice logs a message using NOTICE as log level.
func (l *Logger) Notice(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(NOTICE, "%s", s)
}
// Noticef logs a message using NOTICE as log level.
func (l *Logger) Noticef(format string, args ...interface{}) {
l.log(NOTICE, format, args...)
}
// Info logs a message using INFO as log level.
func (l *Logger) Info(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(INFO, "%s", s)
}
// Infof logs a message using INFO as log level.
func (l *Logger) Infof(format string, args ...interface{}) {
l.log(INFO, format, args...)
}
// Debug logs a message using DEBUG as log level.
func (l *Logger) Debug(args ...interface{}) {
s := fmt.Sprint(args...)
l.log(DEBUG, "%s", s)
}
// Debugf logs a message using DEBUG as log level.
func (l *Logger) Debugf(format string, args ...interface{}) {
l.log(DEBUG, format, args...)
}
func init() {
Reset()
}

View File

@ -1,53 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import "testing"
type Password string
func (p Password) Redacted() interface{} {
return Redact(string(p))
}
func TestSequenceNoOverflow(t *testing.T) {
// Forcefully set the next sequence number to the maximum
backend := InitForTesting(DEBUG)
sequenceNo = ^uint64(0)
log := MustGetLogger("test")
log.Debug("test")
if MemoryRecordN(backend, 0).Id != 0 {
t.Errorf("Unexpected sequence no: %v", MemoryRecordN(backend, 0).Id)
}
}
func TestRedact(t *testing.T) {
backend := InitForTesting(DEBUG)
password := Password("123456")
log := MustGetLogger("test")
log.Debugf("foo %s", password)
if "foo ******" != MemoryRecordN(backend, 0).Formatted(0) {
t.Errorf("redacted line: %v", MemoryRecordN(backend, 0))
}
}
func TestPrivateBackend(t *testing.T) {
stdBackend := InitForTesting(DEBUG)
log := MustGetLogger("test")
privateBackend := NewMemoryBackend(10240)
lvlBackend := AddModuleLevel(privateBackend)
lvlBackend.SetLevel(DEBUG, "")
log.SetBackend(lvlBackend)
log.Debug("to private backend")
if stdBackend.size > 0 {
t.Errorf("something in stdBackend, size of backend: %d", stdBackend.size)
}
if "to private baсkend" == MemoryRecordN(privateBackend, 0).Formatted(0) {
t.Errorf("logged to defaultBackend: %s", MemoryRecordN(privateBackend, 0))
}
}

View File

@ -1,217 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"sync"
"sync/atomic"
"unsafe"
)
// TODO pick one of the memory backends and stick with it or share interface.
// Node is a record node pointing to an optional next node.
type node struct {
next *node
Record *Record
}
// Next returns the next record node. If there's no node available, it will
// return nil.
func (n *node) Next() *node {
return n.next
}
// MemoryBackend is a simple memory based logging backend that will not produce
// any output but merly keep records, up to the given size, in memory.
type MemoryBackend struct {
size int32
maxSize int32
head, tail unsafe.Pointer
}
// NewMemoryBackend creates a simple in-memory logging backend.
func NewMemoryBackend(size int) *MemoryBackend {
return &MemoryBackend{maxSize: int32(size)}
}
// Log implements the Log method required by Backend.
func (b *MemoryBackend) Log(level Level, calldepth int, rec *Record) error {
var size int32
n := &node{Record: rec}
np := unsafe.Pointer(n)
// Add the record to the tail. If there's no records available, tail and
// head will both be nil. When we successfully set the tail and the previous
// value was nil, it's safe to set the head to the current value too.
for {
tailp := b.tail
swapped := atomic.CompareAndSwapPointer(
&b.tail,
tailp,
np,
)
if swapped == true {
if tailp == nil {
b.head = np
} else {
(*node)(tailp).next = n
}
size = atomic.AddInt32(&b.size, 1)
break
}
}
// Since one record was added, we might have overflowed the list. Remove
// a record if that is the case. The size will fluctate a bit, but
// eventual consistent.
if b.maxSize > 0 && size > b.maxSize {
for {
headp := b.head
head := (*node)(b.head)
if head.next == nil {
break
}
swapped := atomic.CompareAndSwapPointer(
&b.head,
headp,
unsafe.Pointer(head.next),
)
if swapped == true {
atomic.AddInt32(&b.size, -1)
break
}
}
}
return nil
}
// Head returns the oldest record node kept in memory. It can be used to
// iterate over records, one by one, up to the last record.
//
// Note: new records can get added while iterating. Hence the number of records
// iterated over might be larger than the maximum size.
func (b *MemoryBackend) Head() *node {
return (*node)(b.head)
}
type event int
const (
eventFlush event = iota
eventStop
)
// ChannelMemoryBackend is very similar to the MemoryBackend, except that it
// internally utilizes a channel.
type ChannelMemoryBackend struct {
maxSize int
size int
incoming chan *Record
events chan event
mu sync.Mutex
running bool
flushWg sync.WaitGroup
stopWg sync.WaitGroup
head, tail *node
}
// NewChannelMemoryBackend creates a simple in-memory logging backend which
// utilizes a go channel for communication.
//
// Start will automatically be called by this function.
func NewChannelMemoryBackend(size int) *ChannelMemoryBackend {
backend := &ChannelMemoryBackend{
maxSize: size,
incoming: make(chan *Record, 1024),
events: make(chan event),
}
backend.Start()
return backend
}
// Start launches the internal goroutine which starts processing data from the
// input channel.
func (b *ChannelMemoryBackend) Start() {
b.mu.Lock()
defer b.mu.Unlock()
// Launch the goroutine unless it's already running.
if b.running != true {
b.running = true
b.stopWg.Add(1)
go b.process()
}
}
func (b *ChannelMemoryBackend) process() {
defer b.stopWg.Done()
for {
select {
case rec := <-b.incoming:
b.insertRecord(rec)
case e := <-b.events:
switch e {
case eventStop:
return
case eventFlush:
for len(b.incoming) > 0 {
b.insertRecord(<-b.incoming)
}
b.flushWg.Done()
}
}
}
}
func (b *ChannelMemoryBackend) insertRecord(rec *Record) {
prev := b.tail
b.tail = &node{Record: rec}
if prev == nil {
b.head = b.tail
} else {
prev.next = b.tail
}
if b.maxSize > 0 && b.size >= b.maxSize {
b.head = b.head.next
} else {
b.size += 1
}
}
// Flush waits until all records in the buffered channel have been processed.
func (b *ChannelMemoryBackend) Flush() {
b.flushWg.Add(1)
b.events <- eventFlush
b.flushWg.Wait()
}
// Stop signals the internal goroutine to exit and waits until it have.
func (b *ChannelMemoryBackend) Stop() {
b.mu.Lock()
if b.running == true {
b.running = false
b.events <- eventStop
}
b.mu.Unlock()
b.stopWg.Wait()
}
// Log implements the Log method required by Backend.
func (b *ChannelMemoryBackend) Log(level Level, calldepth int, rec *Record) error {
b.incoming <- rec
return nil
}
// Head returns the oldest record node kept in memory. It can be used to
// iterate over records, one by one, up to the last record.
//
// Note: new records can get added while iterating. Hence the number of records
// iterated over might be larger than the maximum size.
func (b *ChannelMemoryBackend) Head() *node {
return b.head
}

View File

@ -1,117 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import (
"strconv"
"testing"
)
// TODO share more code between these tests
func MemoryRecordN(b *MemoryBackend, n int) *Record {
node := b.Head()
for i := 0; i < n; i++ {
if node == nil {
break
}
node = node.Next()
}
if node == nil {
return nil
}
return node.Record
}
func ChannelMemoryRecordN(b *ChannelMemoryBackend, n int) *Record {
b.Flush()
node := b.Head()
for i := 0; i < n; i++ {
if node == nil {
break
}
node = node.Next()
}
if node == nil {
return nil
}
return node.Record
}
func TestMemoryBackend(t *testing.T) {
backend := NewMemoryBackend(8)
SetBackend(backend)
log := MustGetLogger("test")
if nil != MemoryRecordN(backend, 0) || 0 != backend.size {
t.Errorf("memory level: %d", backend.size)
}
// Run 13 times, the resulting vector should be [5..12]
for i := 0; i < 13; i++ {
log.Infof("%d", i)
}
if 8 != backend.size {
t.Errorf("record length: %d", backend.size)
}
record := MemoryRecordN(backend, 0)
if "5" != record.Formatted(0) {
t.Errorf("unexpected start: %s", record.Formatted(0))
}
for i := 0; i < 8; i++ {
record = MemoryRecordN(backend, i)
if strconv.Itoa(i+5) != record.Formatted(0) {
t.Errorf("unexpected record: %v", record.Formatted(0))
}
}
record = MemoryRecordN(backend, 7)
if "12" != record.Formatted(0) {
t.Errorf("unexpected end: %s", record.Formatted(0))
}
record = MemoryRecordN(backend, 8)
if nil != record {
t.Errorf("unexpected eof: %s", record.Formatted(0))
}
}
func TestChannelMemoryBackend(t *testing.T) {
backend := NewChannelMemoryBackend(8)
SetBackend(backend)
log := MustGetLogger("test")
if nil != ChannelMemoryRecordN(backend, 0) || 0 != backend.size {
t.Errorf("memory level: %d", backend.size)
}
// Run 13 times, the resulting vector should be [5..12]
for i := 0; i < 13; i++ {
log.Infof("%d", i)
}
backend.Flush()
if 8 != backend.size {
t.Errorf("record length: %d", backend.size)
}
record := ChannelMemoryRecordN(backend, 0)
if "5" != record.Formatted(0) {
t.Errorf("unexpected start: %s", record.Formatted(0))
}
for i := 0; i < 8; i++ {
record = ChannelMemoryRecordN(backend, i)
if strconv.Itoa(i+5) != record.Formatted(0) {
t.Errorf("unexpected record: %v", record.Formatted(0))
}
}
record = ChannelMemoryRecordN(backend, 7)
if "12" != record.Formatted(0) {
t.Errorf("unexpected end: %s", record.Formatted(0))
}
record = ChannelMemoryRecordN(backend, 8)
if nil != record {
t.Errorf("unexpected eof: %s", record.Formatted(0))
}
}

View File

@ -1,65 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
// TODO remove Level stuff from the multi logger. Do one thing.
// multiLogger is a log multiplexer which can be used to utilize multiple log
// backends at once.
type multiLogger struct {
backends []LeveledBackend
}
// MultiLogger creates a logger which contain multiple loggers.
func MultiLogger(backends ...Backend) LeveledBackend {
var leveledBackends []LeveledBackend
for _, backend := range backends {
leveledBackends = append(leveledBackends, AddModuleLevel(backend))
}
return &multiLogger{leveledBackends}
}
// Log passes the log record to all backends.
func (b *multiLogger) Log(level Level, calldepth int, rec *Record) (err error) {
for _, backend := range b.backends {
if backend.IsEnabledFor(level, rec.Module) {
// Shallow copy of the record for the formatted cache on Record and get the
// record formatter from the backend.
r2 := *rec
if e := backend.Log(level, calldepth+1, &r2); e != nil {
err = e
}
}
}
return
}
// GetLevel returns the highest level enabled by all backends.
func (b *multiLogger) GetLevel(module string) Level {
var level Level
for _, backend := range b.backends {
if backendLevel := backend.GetLevel(module); backendLevel > level {
level = backendLevel
}
}
return level
}
// SetLevel propagates the same level to all backends.
func (b *multiLogger) SetLevel(level Level, module string) {
for _, backend := range b.backends {
backend.SetLevel(level, module)
}
}
// IsEnabledFor returns true if any of the backends are enabled for it.
func (b *multiLogger) IsEnabledFor(level Level, module string) bool {
for _, backend := range b.backends {
if backend.IsEnabledFor(level, module) {
return true
}
}
return false
}

View File

@ -1,51 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package logging
import "testing"
func TestMultiLogger(t *testing.T) {
log1 := NewMemoryBackend(8)
log2 := NewMemoryBackend(8)
SetBackend(MultiLogger(log1, log2))
log := MustGetLogger("test")
log.Debug("log")
if "log" != MemoryRecordN(log1, 0).Formatted(0) {
t.Errorf("log1: %v", MemoryRecordN(log1, 0).Formatted(0))
}
if "log" != MemoryRecordN(log2, 0).Formatted(0) {
t.Errorf("log2: %v", MemoryRecordN(log2, 0).Formatted(0))
}
}
func TestMultiLoggerLevel(t *testing.T) {
log1 := NewMemoryBackend(8)
log2 := NewMemoryBackend(8)
leveled1 := AddModuleLevel(log1)
leveled2 := AddModuleLevel(log2)
multi := MultiLogger(leveled1, leveled2)
multi.SetLevel(ERROR, "test")
SetBackend(multi)
log := MustGetLogger("test")
log.Notice("log")
if nil != MemoryRecordN(log1, 0) || nil != MemoryRecordN(log2, 0) {
t.Errorf("unexpected log record")
}
leveled1.SetLevel(DEBUG, "test")
log.Notice("log")
if "log" != MemoryRecordN(log1, 0).Formatted(0) {
t.Errorf("log1 not received")
}
if nil != MemoryRecordN(log2, 0) {
t.Errorf("log2 received")
}
}

View File

@ -1,52 +0,0 @@
// Copyright 2013, Örjan Persson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//+build !windows,!plan9
package logging
import "log/syslog"
// SyslogBackend is a simple logger to syslog backend. It automatically maps
// the internal log levels to appropriate syslog log levels.
type SyslogBackend struct {
Writer *syslog.Writer
}
// NewSyslogBackend connects to the syslog daemon using UNIX sockets with the
// given prefix. If prefix is not given, the prefix will be derived from the
// launched command.
func NewSyslogBackend(prefix string) (b *SyslogBackend, err error) {
var w *syslog.Writer
w, err = syslog.New(syslog.LOG_CRIT, prefix)
return &SyslogBackend{w}, err
}
// NewSyslogBackendPriority is the same as NewSyslogBackend, but with custom
// syslog priority, like syslog.LOG_LOCAL3|syslog.LOG_DEBUG etc.
func NewSyslogBackendPriority(prefix string, priority syslog.Priority) (b *SyslogBackend, err error) {
var w *syslog.Writer
w, err = syslog.New(priority, prefix)
return &SyslogBackend{w}, err
}
func (b *SyslogBackend) Log(level Level, calldepth int, rec *Record) error {
line := rec.Formatted(calldepth + 1)
switch level {
case CRITICAL:
return b.Writer.Crit(line)
case ERROR:
return b.Writer.Err(line)
case WARNING:
return b.Writer.Warning(line)
case NOTICE:
return b.Writer.Notice(line)
case INFO:
return b.Writer.Info(line)
case DEBUG:
return b.Writer.Debug(line)
default:
}
panic("unhandled log level")
}

View File

@ -465,7 +465,7 @@ func startProfiling() (func(), error) {
for _ = range time.NewTicker(time.Second * 30).C {
err := writeHeapProfileToFile()
if err != nil {
log.Critical(err)
log.Error(err)
}
}
}()

View File

@ -45,7 +45,7 @@ output of a running daemon.
// TODO use a different keyword for 'all' because all can theoretically
// clash with a subsystem name
cmds.StringArg("subsystem", true, false, fmt.Sprintf("the subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
cmds.StringArg("level", true, false, "one of: debug, info, notice, warning, error, critical"),
cmds.StringArg("level", true, false, "one of: debug, info, warning, error, fatal, panic"),
},
Run: func(req cmds.Request, res cmds.Response) {

View File

@ -280,7 +280,7 @@ func (bs *Bitswap) ReceiveMessage(ctx context.Context, p peer.ID, incoming bsmsg
var keys []key.Key
for _, block := range iblocks {
if _, found := bs.wm.wl.Contains(block.Key()); !found {
log.Notice("received un-asked-for block: %s", block)
log.Info("received un-asked-for block: %s", block)
continue
}
keys = append(keys, block.Key())
@ -297,7 +297,7 @@ func (bs *Bitswap) ReceiveMessage(ctx context.Context, p peer.ID, incoming bsmsg
has, err := bs.blockstore.Has(b.Key())
if err != nil {
bs.counterLk.Unlock()
log.Noticef("blockstore.Has error: %s", err)
log.Infof("blockstore.Has error: %s", err)
return
}
if err == nil && has {

View File

@ -50,7 +50,7 @@ func (g *SessionGenerator) Next() Instance {
}
func (g *SessionGenerator) Instances(n int) []Instance {
instances := make([]Instance, 0)
var instances []Instance
for j := 0; j < n; j++ {
inst := g.Next()
instances = append(instances, inst)
@ -87,12 +87,12 @@ func (i *Instance) SetBlockstoreLatency(t time.Duration) time.Duration {
// just a much better idea.
func session(ctx context.Context, net tn.Network, p testutil.Identity) Instance {
bsdelay := delay.Fixed(0)
const kWriteCacheElems = 100
const writeCacheElems = 100
adapter := net.Adapter(p)
dstore := ds_sync.MutexWrap(datastore2.WithDelay(ds.NewMapDatastore(), bsdelay))
bstore, err := blockstore.WriteCached(blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)), kWriteCacheElems)
bstore, err := blockstore.WriteCached(blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)), writeCacheElems)
if err != nil {
panic(err.Error()) // FIXME perhaps change signature and return error.
}

View File

@ -96,7 +96,7 @@ func (pm *WantManager) SendBlock(ctx context.Context, env *engine.Envelope) {
log.Infof("Sending block %s to %s", env.Peer, env.Block)
err := pm.network.SendMessage(ctx, env.Peer, msg)
if err != nil {
log.Noticef("sendblock error: %s", err)
log.Infof("sendblock error: %s", err)
}
}
@ -153,7 +153,7 @@ func (mq *msgQueue) doWork(ctx context.Context) {
err := mq.network.ConnectTo(conctx, mq.p)
if err != nil {
log.Noticef("cant connect to peer %s: %s", mq.p, err)
log.Infof("cant connect to peer %s: %s", mq.p, err)
// TODO: cant connect, what now?
return
}
@ -174,7 +174,7 @@ func (mq *msgQueue) doWork(ctx context.Context) {
// send wantlist updates
err = mq.network.SendMessage(sendctx, mq.p, wlm)
if err != nil {
log.Noticef("bitswap send error: %s", err)
log.Infof("bitswap send error: %s", err)
// TODO: what do we do if this fails?
return
}

View File

@ -462,10 +462,10 @@ func (dir *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDi
return err
}
case *File:
log.Critical("Cannot move node into a file!")
log.Error("Cannot move node into a file!")
return fuse.EPERM
default:
log.Critical("Unknown node type for rename target dir!")
log.Error("Unknown node type for rename target dir!")
return errors.New("Unknown fs node type!")
}
return nil

View File

@ -80,7 +80,7 @@ func (fs *Filesystem) Close() error {
defer wg.Done()
err := r.Publish(context.TODO())
if err != nil {
log.Notice(err)
log.Info(err)
return
}
}(r)
@ -285,7 +285,7 @@ func (np *Republisher) Run(ctx context.Context) {
log.Info("Publishing Changes!")
err := np.root.Publish(ctx)
if err != nil {
log.Critical("republishRoot error: %s", err)
log.Error("republishRoot error: %s", err)
}
case <-ctx.Done():

View File

@ -24,7 +24,7 @@ type TestBogusPrivateKey []byte
type TestBogusPublicKey []byte
func (pk TestBogusPublicKey) Verify(data, sig []byte) (bool, error) {
log.Criticalf("TestBogusPublicKey.Verify -- this better be a test!")
log.Errorf("TestBogusPublicKey.Verify -- this better be a test!")
return bytes.Equal(data, reverse(sig)), nil
}
@ -33,7 +33,7 @@ func (pk TestBogusPublicKey) Bytes() ([]byte, error) {
}
func (pk TestBogusPublicKey) Encrypt(b []byte) ([]byte, error) {
log.Criticalf("TestBogusPublicKey.Encrypt -- this better be a test!")
log.Errorf("TestBogusPublicKey.Encrypt -- this better be a test!")
return reverse(b), nil
}
@ -51,7 +51,7 @@ func (sk TestBogusPrivateKey) GenSecret() []byte {
}
func (sk TestBogusPrivateKey) Sign(message []byte) ([]byte, error) {
log.Criticalf("TestBogusPrivateKey.Sign -- this better be a test!")
log.Errorf("TestBogusPrivateKey.Sign -- this better be a test!")
return reverse(message), nil
}
@ -60,7 +60,7 @@ func (sk TestBogusPrivateKey) GetPublic() ic.PubKey {
}
func (sk TestBogusPrivateKey) Decrypt(b []byte) ([]byte, error) {
log.Criticalf("TestBogusPrivateKey.Decrypt -- this better be a test!")
log.Errorf("TestBogusPrivateKey.Decrypt -- this better be a test!")
return reverse(b), nil
}

View File

@ -773,7 +773,7 @@ func TestConnectCollision(t *testing.T) {
runTimes := 10
for rtime := 0; rtime < runTimes; rtime++ {
log.Notice("Running Time: ", rtime)
log.Info("Running Time: ", rtime)
ctx := context.Background()

View File

@ -89,7 +89,7 @@ func (dht *IpfsDHT) handleGetValue(ctx context.Context, p peer.ID, pmes *pb.Mess
for _, pi := range closerinfos {
log.Debugf("handleGetValue returning closer peer: '%s'", pi.ID)
if len(pi.Addrs) < 1 {
log.Criticalf(`no addresses on peer being sent!
log.Errorf(`no addresses on peer being sent!
[local:%s]
[sending:%s]
[remote:%s]`, dht.self, pi.ID, p)

View File

@ -50,7 +50,7 @@ func (px *standard) Bootstrap(ctx context.Context) error {
cxns = append(cxns, info)
}
if len(cxns) == 0 {
log.Critical("unable to bootstrap to any supernode routers")
log.Error("unable to bootstrap to any supernode routers")
} else {
log.Infof("bootstrapped to %d supernode routers: %s", len(cxns), cxns)
}

View File

@ -61,7 +61,7 @@ func TestDegenerateSlowRouting(t *testing.T) {
func Test100MBMacbookCoastToCoast(t *testing.T) {
SkipUnlessEpic(t)
conf := testutil.LatencyConfig{}.Network_NYtoSF().Blockstore_SlowSSD2014().Routing_Slow()
conf := testutil.LatencyConfig{}.NetworkNYtoSF().BlockstoreSlowSSD2014().RoutingSlow()
if err := DirectAddCat(RandomBytes(100*1024*1024), conf); err != nil {
t.Fatal(err)
}

View File

@ -21,7 +21,7 @@ func benchmarkAddCat(numBytes int64, conf testutil.LatencyConfig, b *testing.B)
}
}
var instant = testutil.LatencyConfig{}.All_Instantaneous()
var instant = testutil.LatencyConfig{}.AllInstantaneous()
func BenchmarkInstantaneousAddCat1KB(b *testing.B) { benchmarkAddCat(1*unit.KB, instant, b) }
func BenchmarkInstantaneousAddCat1MB(b *testing.B) { benchmarkAddCat(1*unit.MB, instant, b) }
@ -34,7 +34,7 @@ func BenchmarkInstantaneousAddCat64MB(b *testing.B) { benchmarkAddCat(64*unit.M
func BenchmarkInstantaneousAddCat128MB(b *testing.B) { benchmarkAddCat(128*unit.MB, instant, b) }
func BenchmarkInstantaneousAddCat256MB(b *testing.B) { benchmarkAddCat(256*unit.MB, instant, b) }
var routing = testutil.LatencyConfig{}.Routing_Slow()
var routing = testutil.LatencyConfig{}.RoutingSlow()
func BenchmarkRoutingSlowAddCat1MB(b *testing.B) { benchmarkAddCat(1*unit.MB, routing, b) }
func BenchmarkRoutingSlowAddCat2MB(b *testing.B) { benchmarkAddCat(2*unit.MB, routing, b) }
@ -47,7 +47,7 @@ func BenchmarkRoutingSlowAddCat128MB(b *testing.B) { benchmarkAddCat(128*unit.MB
func BenchmarkRoutingSlowAddCat256MB(b *testing.B) { benchmarkAddCat(256*unit.MB, routing, b) }
func BenchmarkRoutingSlowAddCat512MB(b *testing.B) { benchmarkAddCat(512*unit.MB, routing, b) }
var network = testutil.LatencyConfig{}.Network_NYtoSF()
var network = testutil.LatencyConfig{}.NetworkNYtoSF()
func BenchmarkNetworkSlowAddCat1MB(b *testing.B) { benchmarkAddCat(1*unit.MB, network, b) }
func BenchmarkNetworkSlowAddCat2MB(b *testing.B) { benchmarkAddCat(2*unit.MB, network, b) }
@ -59,7 +59,7 @@ func BenchmarkNetworkSlowAddCat64MB(b *testing.B) { benchmarkAddCat(64*unit.MB,
func BenchmarkNetworkSlowAddCat128MB(b *testing.B) { benchmarkAddCat(128*unit.MB, network, b) }
func BenchmarkNetworkSlowAddCat256MB(b *testing.B) { benchmarkAddCat(256*unit.MB, network, b) }
var hdd = testutil.LatencyConfig{}.Blockstore_7200RPM()
var hdd = testutil.LatencyConfig{}.Blockstore7200RPM()
func BenchmarkBlockstoreSlowAddCat1MB(b *testing.B) { benchmarkAddCat(1*unit.MB, hdd, b) }
func BenchmarkBlockstoreSlowAddCat2MB(b *testing.B) { benchmarkAddCat(2*unit.MB, hdd, b) }
@ -71,7 +71,7 @@ func BenchmarkBlockstoreSlowAddCat64MB(b *testing.B) { benchmarkAddCat(64*unit.
func BenchmarkBlockstoreSlowAddCat128MB(b *testing.B) { benchmarkAddCat(128*unit.MB, hdd, b) }
func BenchmarkBlockstoreSlowAddCat256MB(b *testing.B) { benchmarkAddCat(256*unit.MB, hdd, b) }
var mixed = testutil.LatencyConfig{}.Network_NYtoSF().Blockstore_SlowSSD2014().Routing_Slow()
var mixed = testutil.LatencyConfig{}.NetworkNYtoSF().BlockstoreSlowSSD2014().RoutingSlow()
func BenchmarkMixedAddCat1MBXX(b *testing.B) { benchmarkAddCat(1*unit.MB, mixed, b) }
func BenchmarkMixedAddCat2MBXX(b *testing.B) { benchmarkAddCat(2*unit.MB, mixed, b) }

View File

@ -55,7 +55,7 @@ func TestThreeLeggedCatDegenerateSlowRouting(t *testing.T) {
func TestThreeLeggedCat100MBMacbookCoastToCoast(t *testing.T) {
SkipUnlessEpic(t)
conf := testutil.LatencyConfig{}.Network_NYtoSF().Blockstore_SlowSSD2014().Routing_Slow()
conf := testutil.LatencyConfig{}.NetworkNYtoSF().BlockstoreSlowSSD2014().RoutingSlow()
if err := RunThreeLeggedCat(RandomBytes(100*unit.MB), conf); err != nil {
t.Fatal(err)
}

View File

@ -11,8 +11,6 @@ import (
// StandardLogger provides API compatibility with standard printf loggers
// eg. go-logging
type StandardLogger interface {
Critical(args ...interface{})
Criticalf(format string, args ...interface{})
Debug(args ...interface{})
Debugf(format string, args ...interface{})
Error(args ...interface{})
@ -21,8 +19,6 @@ type StandardLogger interface {
Fatalf(format string, args ...interface{})
Info(args ...interface{})
Infof(format string, args ...interface{})
Notice(args ...interface{})
Noticef(format string, args ...interface{})
Panic(args ...interface{})
Panicf(format string, args ...interface{})
Warning(args ...interface{})

View File

@ -11,7 +11,7 @@ func (l LoggableMap) Loggable() map[string]interface{} {
return l
}
// Loggable converts a func into a Loggable
// LoggableF converts a func into a Loggable
type LoggableF func() map[string]interface{}
func (l LoggableF) Loggable() map[string]interface{} {

View File

@ -71,7 +71,7 @@ func (n *Notifier) Notify(e Notifiee) {
n.mu.Unlock()
}
// StopNotifying stops notifying Notifiee e. This function
// StopNotify stops notifying Notifiee e. This function
// is meant to be called behind your own type-safe function(s):
//
// // generic function for pattern-following

View File

@ -11,31 +11,31 @@ import (
query "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/query"
)
var _ datastore.Datastore = &RedisDatastore{}
var _ datastore.ThreadSafeDatastore = &RedisDatastore{}
var _ datastore.Datastore = &Datastore{}
var _ datastore.ThreadSafeDatastore = &Datastore{}
var ErrInvalidType = errors.New("redis datastore: invalid type error. this datastore only supports []byte values")
func NewExpiringDatastore(client *redis.Client, ttl time.Duration) (datastore.ThreadSafeDatastore, error) {
return &RedisDatastore{
return &Datastore{
client: client,
ttl: ttl,
}, nil
}
func NewDatastore(client *redis.Client) (datastore.ThreadSafeDatastore, error) {
return &RedisDatastore{
return &Datastore{
client: client,
}, nil
}
type RedisDatastore struct {
type Datastore struct {
mu sync.Mutex
client *redis.Client
ttl time.Duration
}
func (ds *RedisDatastore) Put(key datastore.Key, value interface{}) error {
func (ds *Datastore) Put(key datastore.Key, value interface{}) error {
ds.mu.Lock()
defer ds.mu.Unlock()
@ -59,26 +59,26 @@ func (ds *RedisDatastore) Put(key datastore.Key, value interface{}) error {
return nil
}
func (ds *RedisDatastore) Get(key datastore.Key) (value interface{}, err error) {
func (ds *Datastore) Get(key datastore.Key) (value interface{}, err error) {
ds.mu.Lock()
defer ds.mu.Unlock()
return ds.client.Cmd("GET", key.String()).Bytes()
}
func (ds *RedisDatastore) Has(key datastore.Key) (exists bool, err error) {
func (ds *Datastore) Has(key datastore.Key) (exists bool, err error) {
ds.mu.Lock()
defer ds.mu.Unlock()
return ds.client.Cmd("EXISTS", key.String()).Bool()
}
func (ds *RedisDatastore) Delete(key datastore.Key) (err error) {
func (ds *Datastore) Delete(key datastore.Key) (err error) {
ds.mu.Lock()
defer ds.mu.Unlock()
return ds.client.Cmd("DEL", key.String()).Err
}
func (ds *RedisDatastore) Query(q query.Query) (query.Results, error) {
func (ds *Datastore) Query(q query.Query) (query.Results, error) {
return nil, errors.New("TODO implement query for redis datastore?")
}
func (ds *RedisDatastore) IsThreadSafe() {}
func (ds *Datastore) IsThreadSafe() {}

View File

@ -19,7 +19,7 @@ func (i Information) String() string {
tmp := int64(i)
// default
var d int64 = tmp
var d = tmp
symbol := "B"
switch {

View File

@ -90,8 +90,7 @@ func init() {
var err error
currentVersion, err = parseVersion()
if err != nil {
log.Criticalf("invalid version number in code (must be semver): %q", Version)
os.Exit(1)
log.Fatalf("invalid version number in code (must be semver): %q", Version)
}
log.Infof("go-ipfs Version: %s", currentVersion)
}
@ -211,7 +210,7 @@ func CliCheckForUpdates(cfg *config.Config, repoPath string) error {
// if there is no update available, record it, and exit. NB: only record
// if we checked successfully.
if err == ErrNoUpdateAvailable {
log.Noticef("No update available, checked on %s", time.Now())
log.Infof("No update available, checked on %s", time.Now())
r, err := fsrepo.Open(repoPath)
if err != nil {
return err
@ -239,7 +238,7 @@ func CliCheckForUpdates(cfg *config.Config, repoPath string) error {
if cfg.Version.AutoUpdate != config.AutoUpdateNever {
// and we should auto update
if ShouldAutoUpdate(cfg.Version.AutoUpdate, u.Version) {
log.Noticef("Applying update %s", u.Version)
log.Infof("Applying update %s", u.Version)
if err = Apply(u); err != nil {
log.Debug(err)

View File

@ -3,23 +3,21 @@ package util
import (
"os"
logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging"
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/Sirupsen/logrus"
)
func init() {
SetupLogging()
}
var log = Logger("util")
var ansiGray = "\033[0;37m"
var ansiBlue = "\033[0;34m"
var log = logrus.New()
// LogFormats is a map of formats used for our logger, keyed by name.
var LogFormats = map[string]string{
"nocolor": "%{time:2006-01-02 15:04:05.000000} %{level} %{module} %{shortfile}: %{message}",
"color": ansiGray + "%{time:15:04:05.000} %{color}%{level:5.5s} " + ansiBlue +
"%{module:10.10s}: %{color:reset}%{message} " + ansiGray + "%{shortfile}%{color:reset}",
// TODO: write custom TextFormatter (don't print module=name explicitly) and
// fork logrus to add shortfile
var LogFormats = map[string]*logrus.TextFormatter{
"nocolor": &logrus.TextFormatter{DisableColors: true, FullTimestamp: true, TimestampFormat: "2006-01-02 15:04:05.000000", DisableSorting: true},
"color": &logrus.TextFormatter{DisableColors: false, FullTimestamp: true, TimestampFormat: "15:04:05:000", DisableSorting: true},
}
var defaultLogFormat = "color"
@ -30,65 +28,66 @@ const (
)
// loggers is the set of loggers in the system
var loggers = map[string]*logging.Logger{}
var loggers = map[string]*logrus.Entry{}
// SetupLogging will initialize the logger backend and set the flags.
func SetupLogging() {
fmt := LogFormats[os.Getenv(envLoggingFmt)]
if fmt == "" {
fmt = LogFormats[defaultLogFormat]
format, ok := LogFormats[os.Getenv(envLoggingFmt)]
if !ok {
format = LogFormats[defaultLogFormat]
}
backend := logging.NewLogBackend(os.Stderr, "", 0)
logging.SetBackend(backend)
logging.SetFormatter(logging.MustStringFormatter(fmt))
log.Out = os.Stderr
log.Formatter = format
lvl := logging.ERROR
lvl := logrus.ErrorLevel
if logenv := os.Getenv(envLogging); logenv != "" {
var err error
lvl, err = logging.LogLevel(logenv)
lvl, err = logrus.ParseLevel(logenv)
if err != nil {
log.Debugf("logging.LogLevel() Error: %q", err)
lvl = logging.ERROR // reset to ERROR, could be undefined now(?)
log.Debugf("logrus.ParseLevel() Error: %q", err)
lvl = logrus.ErrorLevel // reset to ERROR, could be undefined now(?)
}
}
Debug = GetenvBool("IPFS_DEBUG")
if Debug {
lvl = logging.DEBUG
if Debug := GetenvBool("IPFS_DEBUG"); Debug {
lvl = logrus.DebugLevel
}
SetAllLoggers(lvl)
}
// SetDebugLogging calls SetAllLoggers with logging.DEBUG
// SetDebugLogging calls SetAllLoggers with logrus.DebugLevel
func SetDebugLogging() {
SetAllLoggers(logging.DEBUG)
SetAllLoggers(logrus.DebugLevel)
}
// SetAllLoggers changes the logging.Level of all loggers to lvl
func SetAllLoggers(lvl logging.Level) {
logging.SetLevel(lvl, "")
for n := range loggers {
logging.SetLevel(lvl, n)
// SetAllLoggers changes the logrus.Level of all loggers to lvl
func SetAllLoggers(lvl logrus.Level) {
log.Level = lvl
for _, logger := range loggers {
logger.Level = lvl
}
}
// Logger retrieves a particular logger
func Logger(name string) *logging.Logger {
log := logging.MustGetLogger(name)
log.ExtraCalldepth = 1
loggers[name] = log
return log
func Logger(name string) *logrus.Entry {
if len(name) == 0 {
log.Warnf("Missing name parameter")
name = "undefined"
}
if _, ok := loggers[name]; !ok {
loggers[name] = log.WithField("module", name)
}
return loggers[name]
}
// SetLogLevel changes the log level of a specific subsystem
// name=="*" changes all subsystems
func SetLogLevel(name, level string) error {
lvl, err := logging.LogLevel(level)
lvl, err := logrus.ParseLevel(level)
if err != nil {
return err
}
@ -100,13 +99,11 @@ func SetLogLevel(name, level string) error {
}
// Check if we have a logger by that name
// logging.SetLevel() can't tell us...
_, ok := loggers[name]
if !ok {
if _, ok := loggers[name]; !ok {
return ErrNoSuchLogger
}
logging.SetLevel(lvl, name)
loggers[name].Level = lvl
return nil
}

View File

@ -1,151 +0,0 @@
package eventlog
import (
"strings"
"github.com/ipfs/go-ipfs/util"
)
// StandardLogger provides API compatibility with standard printf loggers
// eg. go-logging
type StandardLogger interface {
Critical(args ...interface{})
Criticalf(format string, args ...interface{})
Debug(args ...interface{})
Debugf(format string, args ...interface{})
Error(args ...interface{})
Errorf(format string, args ...interface{})
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Info(args ...interface{})
Infof(format string, args ...interface{})
Notice(args ...interface{})
Noticef(format string, args ...interface{})
Panic(args ...interface{})
Panicf(format string, args ...interface{})
Warning(args ...interface{})
Warningf(format string, args ...interface{})
}
// StandardLogger provides API compatibility with standard printf loggers
// eg. go-logging
type PrefixLogger interface {
StandardLogger
Format() string
Args() []interface{}
Prefix(fmt string, args ...interface{}) PrefixLogger
}
// Logger retrieves an event logger by name
func Logger(system string) PrefixLogger {
// TODO if we would like to adjust log levels at run-time. Store this event
// logger in a map (just like the util.Logger impl)
logger := util.Logger(system)
return Prefix(logger, "")
}
func Prefix(l StandardLogger, format string, args ...interface{}) PrefixLogger {
return &prefixLogger{logger: l, format: format, args: args}
}
type prefixLogger struct {
logger StandardLogger
format string
args []interface{}
}
func (pl *prefixLogger) Format() string {
return pl.format
}
func (pl *prefixLogger) Args() []interface{} {
return pl.args
}
func (pl *prefixLogger) Prefix(fmt string, args ...interface{}) PrefixLogger {
return Prefix(pl, fmt, args...)
}
func (pl *prefixLogger) prepend(fmt string, args []interface{}) (string, []interface{}) {
together := make([]interface{}, 0, len(pl.args)+len(args))
together = append(together, pl.args...)
together = append(together, args...)
if len(pl.format) > 0 {
fmt = pl.format + " " + fmt
}
return fmt, together
}
func valfmtn(count int) string {
s := strings.Repeat("%v ", count)
s = s[:len(s)-1] // remove last space
return s
}
type logFunc func(args ...interface{})
type logFuncf func(fmt string, args ...interface{})
func (pl *prefixLogger) logFunc(f logFuncf, args ...interface{}) {
// need to actually use the format version, with extra fmt strings appended
fmt := valfmtn(len(args))
pl.logFuncf(f, fmt, args...)
}
func (pl *prefixLogger) logFuncf(f logFuncf, format string, args ...interface{}) {
format, args = pl.prepend(format, args)
f(format, args...)
}
func (pl *prefixLogger) Critical(args ...interface{}) {
pl.logFunc(pl.logger.Criticalf, args...)
}
func (pl *prefixLogger) Debug(args ...interface{}) {
pl.logFunc(pl.logger.Debugf, args...)
}
func (pl *prefixLogger) Error(args ...interface{}) {
pl.logFunc(pl.logger.Errorf, args...)
}
func (pl *prefixLogger) Fatal(args ...interface{}) {
pl.logFunc(pl.logger.Fatalf, args...)
}
func (pl *prefixLogger) Info(args ...interface{}) {
pl.logFunc(pl.logger.Infof, args...)
}
func (pl *prefixLogger) Notice(args ...interface{}) {
pl.logFunc(pl.logger.Noticef, args...)
}
func (pl *prefixLogger) Panic(args ...interface{}) {
pl.logFunc(pl.logger.Panicf, args...)
}
func (pl *prefixLogger) Warning(args ...interface{}) {
pl.logFunc(pl.logger.Warningf, args...)
}
func (pl *prefixLogger) Criticalf(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Criticalf, format, args...)
}
func (pl *prefixLogger) Debugf(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Debugf, format, args...)
}
func (pl *prefixLogger) Errorf(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Errorf, format, args...)
}
func (pl *prefixLogger) Fatalf(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Fatalf, format, args...)
}
func (pl *prefixLogger) Infof(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Infof, format, args...)
}
func (pl *prefixLogger) Noticef(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Noticef, format, args...)
}
func (pl *prefixLogger) Panicf(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Panicf, format, args...)
}
func (pl *prefixLogger) Warningf(format string, args ...interface{}) {
pl.logFuncf(pl.logger.Warningf, format, args...)
}

View File

@ -122,7 +122,7 @@ func (p *PeerNetParams) checkKeys() error {
return fmt.Errorf("sig verify failed: %s", err)
}
if !sigok {
return fmt.Errorf("sig verify failed: sig invalid!")
return fmt.Errorf("sig verify failed: sig invalid")
}
return nil // ok. move along.

View File

@ -8,7 +8,7 @@ type LatencyConfig struct {
RoutingLatency time.Duration
}
func (c LatencyConfig) All_Instantaneous() LatencyConfig {
func (c LatencyConfig) AllInstantaneous() LatencyConfig {
// Could use a zero value but whatever. Consistency of interface
c.NetworkLatency = 0
c.RoutingLatency = 0
@ -16,33 +16,33 @@ func (c LatencyConfig) All_Instantaneous() LatencyConfig {
return c
}
func (c LatencyConfig) Network_NYtoSF() LatencyConfig {
func (c LatencyConfig) NetworkNYtoSF() LatencyConfig {
c.NetworkLatency = 20 * time.Millisecond
return c
}
func (c LatencyConfig) Network_IntraDatacenter2014() LatencyConfig {
func (c LatencyConfig) NetworkIntraDatacenter2014() LatencyConfig {
c.NetworkLatency = 250 * time.Microsecond
return c
}
func (c LatencyConfig) Blockstore_FastSSD2014() LatencyConfig {
func (c LatencyConfig) BlockstoreFastSSD2014() LatencyConfig {
const iops = 100000
c.BlockstoreLatency = (1 / iops) * time.Second
return c
}
func (c LatencyConfig) Blockstore_SlowSSD2014() LatencyConfig {
func (c LatencyConfig) BlockstoreSlowSSD2014() LatencyConfig {
c.BlockstoreLatency = 150 * time.Microsecond
return c
}
func (c LatencyConfig) Blockstore_7200RPM() LatencyConfig {
func (c LatencyConfig) Blockstore7200RPM() LatencyConfig {
c.BlockstoreLatency = 8 * time.Millisecond
return c
}
func (c LatencyConfig) Routing_Slow() LatencyConfig {
func (c LatencyConfig) RoutingSlow() LatencyConfig {
c.RoutingLatency = 200 * time.Millisecond
return c
}

View File

@ -1,4 +1,4 @@
// package util implements various utility functions used within ipfs
// Package util implements various utility functions used within ipfs
// that do not currently have a better place to live.
package util
@ -95,7 +95,7 @@ func GetenvBool(name string) bool {
return v == "true" || v == "t" || v == "1"
}
// multiErr is a util to return multiple errors
// MultiErr is a util to return multiple errors
type MultiErr []error
func (m MultiErr) Error() string {
@ -116,17 +116,15 @@ func (m MultiErr) Error() string {
func Partition(subject string, sep string) (string, string, string) {
if i := strings.Index(subject, sep); i != -1 {
return subject[:i], subject[i : i+len(sep)], subject[i+len(sep):]
} else {
return subject, "", ""
}
return subject, "", ""
}
func RPartition(subject string, sep string) (string, string, string) {
if i := strings.LastIndex(subject, sep); i != -1 {
return subject[:i], subject[i : i+len(sep)], subject[i+len(sep):]
} else {
return subject, "", ""
}
return subject, "", ""
}
// Hash is the global IPFS hash function. uses multihash SHA2_256, 256 bits