“47e5978f499fdad105f385937f774ec93c056600”上不存在“mobile/tools/pre-commit.hooks/clang-tidy.hook”
提交 b131797a 编写于 作者: L liipx

update pingcap parser deps

上级 bbf012d5
...@@ -81,7 +81,7 @@ cover: test ...@@ -81,7 +81,7 @@ cover: test
{print "\033[93m"$$0"%\033[0m"}}' {print "\033[93m"$$0"%\033[0m"}}'
# Builds the project # Builds the project
build: fmt tidb-parser build: fmt
@echo "\033[92mBuilding ...\033[0m" @echo "\033[92mBuilding ...\033[0m"
@mkdir -p bin @mkdir -p bin
@bash ./genver.sh @bash ./genver.sh
...@@ -91,16 +91,6 @@ build: fmt tidb-parser ...@@ -91,16 +91,6 @@ build: fmt tidb-parser
done ; exit $$ret done ; exit $$ret
@echo "build Success!" @echo "build Success!"
.PHONY: fast
fast: fmt
@echo "\033[92mBuilding ...\033[0m"
@bash ./genver.sh
@ret=0 && for d in $$(go list -f '{{if (eq .Name "main")}}{{.ImportPath}}{{end}}' ./...); do \
b=$$(basename $${d}) ; \
go build ${GCFLAGS} -o bin/$${b} $$d || ret=$$? ; \
done ; exit $$ret
@echo "build Success!"
# Installs our project: copies binaries # Installs our project: copies binaries
install: build install: build
@echo "\033[92mInstall ...\033[0m" @echo "\033[92mInstall ...\033[0m"
...@@ -109,7 +99,7 @@ install: build ...@@ -109,7 +99,7 @@ install: build
# Generate doc use -list* command # Generate doc use -list* command
.PHONY: doc .PHONY: doc
doc: fast doc: build
@echo "\033[92mAuto generate doc ...\033[0m" @echo "\033[92mAuto generate doc ...\033[0m"
./bin/soar -list-heuristic-rules > doc/heuristic.md ./bin/soar -list-heuristic-rules > doc/heuristic.md
./bin/soar -list-rewrite-rules > doc/rewrite.md ./bin/soar -list-rewrite-rules > doc/rewrite.md
...@@ -133,27 +123,22 @@ vitess: ...@@ -133,27 +123,22 @@ vitess:
.PHONY: tidb .PHONY: tidb
tidb: tidb:
@echo "\033[92mUpdate tidb deps ...\033[0m" @echo "\033[92mUpdate tidb deps ...\033[0m"
@echo -n "Current TiDB commit hash: " govendor fetch -v github.com/pingcap/tidb/...
@(cd ${GOPATH}/src/github.com/pingcap/tidb/ 2>/dev/null && git checkout master && git rev-parse HEAD) || echo "(init)"
@(go get -v -d github.com/pingcap/tidb/... || echo "go get tidb") # make pingcap parser
@echo -n "TiDB update to: " .PHONY: pingcap-parser
@cd ${GOPATH}/src/github.com/pingcap/tidb/ && git pull && git rev-parse HEAD pingcap-parser: tidb
@echo "\033[92mUpdate pingcap parser deps ...\033[0m"
govendor fetch -v github.com/pingcap/parser/...
# Update all vendor # Update all vendor
.PHONY: vendor .PHONY: vendor
vendor: vitess tidb vendor: vitess pingcap-parser
# make tidb parser
.PHONY: tidb-parser
tidb-parser: tidb
@echo "\033[92mimporting tidb sql parser ...\033[0m"
@cd ${GOPATH}/src/github.com/pingcap/tidb && git checkout --quiet ec9672cea6612481b1da845dbab620b7a5581ca4 && make parser
# gometalinter # gometalinter
# 如果有不想改的lint问题可以使用metalinter.sh加黑名单 # 如果有不想改的lint问题可以使用metalinter.sh加黑名单
#@bash doc/example/metalinter.sh #@bash doc/example/metalinter.sh
.PHONY: lint .PHONY: lint
lint: fast lint: build
@echo "\033[92mRun linter check ...\033[0m" @echo "\033[92mRun linter check ...\033[0m"
CGO_ENABLED=0 retool do gometalinter.v2 -j 1 --config doc/example/metalinter.json ./... CGO_ENABLED=0 retool do gometalinter.v2 -j 1 --config doc/example/metalinter.json ./...
retool do revive -formatter friendly --exclude vendor/... -config doc/example/revive.toml ./... retool do revive -formatter friendly --exclude vendor/... -config doc/example/revive.toml ./...
...@@ -206,10 +191,10 @@ main_test: install ...@@ -206,10 +191,10 @@ main_test: install
@echo "main_test Success!" @echo "main_test Success!"
.PHONY: daily .PHONY: daily
daily: | deps fmt vendor tidb-parser docker cover doc lint release install main_test clean logo daily: | deps fmt vendor docker cover doc lint release install main_test clean logo
@echo "\033[92mdaily build finished\033[0m" @echo "\033[92mdaily build finished\033[0m"
# vendor, tidb-parser, docker will cost long time, if all those are ready, daily-quick will much more fast. # vendor, docker will cost long time, if all those are ready, daily-quick will much more fast.
.PHONY: daily-quick .PHONY: daily-quick
daily-quick: | deps fmt cover doc lint logo daily-quick: | deps fmt cover doc lint logo
@echo "\033[92mdaily-quick build finished\033[0m" @echo "\033[92mdaily-quick build finished\033[0m"
......
...@@ -27,12 +27,10 @@ import ( ...@@ -27,12 +27,10 @@ import (
"github.com/XiaoMi/soar/ast" "github.com/XiaoMi/soar/ast"
"github.com/XiaoMi/soar/common" "github.com/XiaoMi/soar/common"
"github.com/XiaoMi/soar/database" "github.com/XiaoMi/soar/database"
"github.com/gedex/inflector" "github.com/gedex/inflector"
"github.com/percona/go-mysql/query" "github.com/percona/go-mysql/query"
tidb "github.com/pingcap/tidb/ast" tidb "github.com/pingcap/parser/ast"
"github.com/pingcap/tidb/mysql" "github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/types"
"vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/sqlparser"
) )
...@@ -1608,8 +1606,8 @@ func (q *Query4Audit) RuleImpreciseDataType() Rule { ...@@ -1608,8 +1606,8 @@ func (q *Query4Audit) RuleImpreciseDataType() Rule {
// Insert statement // Insert statement
for _, values := range node.Lists { for _, values := range node.Lists {
for _, value := range values { for _, value := range values {
switch value.GetDatum().Kind() { switch value.GetType().Tp {
case types.KindFloat32, types.KindFloat64, types.KindMysqlDecimal: case mysql.TypeNewDecimal, mysql.TypeFloat:
rule = HeuristicRules["COL.009"] rule = HeuristicRules["COL.009"]
} }
} }
...@@ -1619,8 +1617,8 @@ func (q *Query4Audit) RuleImpreciseDataType() Rule { ...@@ -1619,8 +1617,8 @@ func (q *Query4Audit) RuleImpreciseDataType() Rule {
// Select statement // Select statement
switch where := node.Where.(type) { switch where := node.Where.(type) {
case *tidb.BinaryOperationExpr: case *tidb.BinaryOperationExpr:
switch where.R.GetDatum().Kind() { switch where.R.GetType().Tp {
case types.KindFloat32, types.KindFloat64, types.KindMysqlDecimal: case mysql.TypeNewDecimal, mysql.TypeFloat:
rule = HeuristicRules["COL.009"] rule = HeuristicRules["COL.009"]
} }
} }
......
...@@ -29,7 +29,7 @@ import ( ...@@ -29,7 +29,7 @@ import (
"github.com/kr/pretty" "github.com/kr/pretty"
"github.com/percona/go-mysql/query" "github.com/percona/go-mysql/query"
tidb "github.com/pingcap/tidb/ast" tidb "github.com/pingcap/parser/ast"
"vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/sqlparser"
) )
......
...@@ -20,8 +20,9 @@ import ( ...@@ -20,8 +20,9 @@ import (
"github.com/XiaoMi/soar/common" "github.com/XiaoMi/soar/common"
"github.com/kr/pretty" "github.com/kr/pretty"
"github.com/pingcap/tidb/ast" "github.com/pingcap/parser"
"github.com/pingcap/tidb/parser" "github.com/pingcap/parser/ast"
_ "github.com/pingcap/tidb/types/parser_driver"
) )
// TiParse TiDB 语法解析 // TiParse TiDB 语法解析
......
...@@ -28,7 +28,7 @@ import ( ...@@ -28,7 +28,7 @@ import (
"github.com/XiaoMi/soar/ast" "github.com/XiaoMi/soar/ast"
"github.com/XiaoMi/soar/common" "github.com/XiaoMi/soar/common"
tidb "github.com/pingcap/tidb/ast" tidb "github.com/pingcap/parser/ast"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/sqlparser"
) )
......
...@@ -16,48 +16,57 @@ As of now this logs support console, file,smtp and conn. ...@@ -16,48 +16,57 @@ As of now this logs support console, file,smtp and conn.
First you must import it First you must import it
import ( ```golang
"github.com/astaxie/beego/logs" import (
) "github.com/astaxie/beego/logs"
)
```
Then init a Log (example with console adapter) Then init a Log (example with console adapter)
log := NewLogger(10000) ```golang
log.SetLogger("console", "") log := logs.NewLogger(10000)
log.SetLogger("console", "")
```
> the first params stand for how many channel > the first params stand for how many channel
Use it like this: Use it like this:
log.Trace("trace")
log.Info("info")
log.Warn("warning")
log.Debug("debug")
log.Critical("critical")
```golang
log.Trace("trace")
log.Info("info")
log.Warn("warning")
log.Debug("debug")
log.Critical("critical")
```
## File adapter ## File adapter
Configure file adapter like this: Configure file adapter like this:
log := NewLogger(10000) ```golang
log.SetLogger("file", `{"filename":"test.log"}`) log := NewLogger(10000)
log.SetLogger("file", `{"filename":"test.log"}`)
```
## Conn adapter ## Conn adapter
Configure like this: Configure like this:
log := NewLogger(1000) ```golang
log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`) log := NewLogger(1000)
log.Info("info") log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`)
log.Info("info")
```
## Smtp adapter ## Smtp adapter
Configure like this: Configure like this:
log := NewLogger(10000) ```golang
log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`) log := NewLogger(10000)
log.Critical("sendmail critical") log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`)
time.Sleep(time.Second * 30) log.Critical("sendmail critical")
time.Sleep(time.Second * 30)
```
...@@ -16,13 +16,14 @@ package logs ...@@ -16,13 +16,14 @@ package logs
import ( import (
"bytes" "bytes"
"strings"
"encoding/json" "encoding/json"
"time"
"fmt" "fmt"
"time"
) )
const ( const (
apacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f %s %s\n" apacheFormatPattern = "%s - - [%s] \"%s %d %d\" %f %s %s"
apacheFormat = "APACHE_FORMAT" apacheFormat = "APACHE_FORMAT"
jsonFormat = "JSON_FORMAT" jsonFormat = "JSON_FORMAT"
) )
...@@ -53,10 +54,9 @@ func (r *AccessLogRecord) json() ([]byte, error) { ...@@ -53,10 +54,9 @@ func (r *AccessLogRecord) json() ([]byte, error) {
} }
func disableEscapeHTML(i interface{}) { func disableEscapeHTML(i interface{}) {
e, ok := i.(interface { if e, ok := i.(interface {
SetEscapeHTML(bool) SetEscapeHTML(bool)
}); }); ok {
if ok {
e.SetEscapeHTML(false) e.SetEscapeHTML(false)
} }
} }
...@@ -64,9 +64,7 @@ func disableEscapeHTML(i interface{}) { ...@@ -64,9 +64,7 @@ func disableEscapeHTML(i interface{}) {
// AccessLog - Format and print access log. // AccessLog - Format and print access log.
func AccessLog(r *AccessLogRecord, format string) { func AccessLog(r *AccessLogRecord, format string) {
var msg string var msg string
switch format { switch format {
case apacheFormat: case apacheFormat:
timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05") timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05")
msg = fmt.Sprintf(apacheFormatPattern, r.RemoteAddr, timeFormatted, r.Request, r.Status, r.BodyBytesSent, msg = fmt.Sprintf(apacheFormatPattern, r.RemoteAddr, timeFormatted, r.Request, r.Status, r.BodyBytesSent,
...@@ -81,6 +79,5 @@ func AccessLog(r *AccessLogRecord, format string) { ...@@ -81,6 +79,5 @@ func AccessLog(r *AccessLogRecord, format string) {
msg = string(jsonData) msg = string(jsonData)
} }
} }
beeLogger.writeMsg(levelLoggerImpl, strings.TrimSpace(msg))
beeLogger.Debug(msg)
} }
...@@ -21,6 +21,7 @@ import ( ...@@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
...@@ -40,6 +41,9 @@ type fileLogWriter struct { ...@@ -40,6 +41,9 @@ type fileLogWriter struct {
MaxLines int `json:"maxlines"` MaxLines int `json:"maxlines"`
maxLinesCurLines int maxLinesCurLines int
MaxFiles int `json:"maxfiles"`
MaxFilesCurFiles int
// Rotate at size // Rotate at size
MaxSize int `json:"maxsize"` MaxSize int `json:"maxsize"`
maxSizeCurSize int maxSizeCurSize int
...@@ -50,6 +54,12 @@ type fileLogWriter struct { ...@@ -50,6 +54,12 @@ type fileLogWriter struct {
dailyOpenDate int dailyOpenDate int
dailyOpenTime time.Time dailyOpenTime time.Time
// Rotate hourly
Hourly bool `json:"hourly"`
MaxHours int64 `json:"maxhours"`
hourlyOpenDate int
hourlyOpenTime time.Time
Rotate bool `json:"rotate"` Rotate bool `json:"rotate"`
Level int `json:"level"` Level int `json:"level"`
...@@ -66,25 +76,30 @@ func newFileWriter() Logger { ...@@ -66,25 +76,30 @@ func newFileWriter() Logger {
w := &fileLogWriter{ w := &fileLogWriter{
Daily: true, Daily: true,
MaxDays: 7, MaxDays: 7,
Hourly: false,
MaxHours: 168,
Rotate: true, Rotate: true,
RotatePerm: "0440", RotatePerm: "0440",
Level: LevelTrace, Level: LevelTrace,
Perm: "0660", Perm: "0660",
MaxLines: 10000000,
MaxFiles: 999,
MaxSize: 1 << 28,
} }
return w return w
} }
// Init file logger with json config. // Init file logger with json config.
// jsonConfig like: // jsonConfig like:
// { // {
// "filename":"logs/beego.log", // "filename":"logs/beego.log",
// "maxLines":10000, // "maxLines":10000,
// "maxsize":1024, // "maxsize":1024,
// "daily":true, // "daily":true,
// "maxDays":15, // "maxDays":15,
// "rotate":true, // "rotate":true,
// "perm":"0600" // "perm":"0600"
// } // }
func (w *fileLogWriter) Init(jsonConfig string) error { func (w *fileLogWriter) Init(jsonConfig string) error {
err := json.Unmarshal([]byte(jsonConfig), w) err := json.Unmarshal([]byte(jsonConfig), w)
if err != nil { if err != nil {
...@@ -115,10 +130,16 @@ func (w *fileLogWriter) startLogger() error { ...@@ -115,10 +130,16 @@ func (w *fileLogWriter) startLogger() error {
return w.initFd() return w.initFd()
} }
func (w *fileLogWriter) needRotate(size int, day int) bool { func (w *fileLogWriter) needRotateDaily(size int, day int) bool {
return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) || return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) || (w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
(w.Daily && day != w.dailyOpenDate) (w.Daily && day != w.dailyOpenDate)
}
func (w *fileLogWriter) needRotateHourly(size int, hour int) bool {
return (w.MaxLines > 0 && w.maxLinesCurLines >= w.MaxLines) ||
(w.MaxSize > 0 && w.maxSizeCurSize >= w.MaxSize) ||
(w.Hourly && hour != w.hourlyOpenDate)
} }
...@@ -127,14 +148,23 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { ...@@ -127,14 +148,23 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error {
if level > w.Level { if level > w.Level {
return nil return nil
} }
h, d := formatTimeHeader(when) hd, d, h := formatTimeHeader(when)
msg = string(h) + msg + "\n" msg = string(hd) + msg + "\n"
if w.Rotate { if w.Rotate {
w.RLock() w.RLock()
if w.needRotate(len(msg), d) { if w.needRotateHourly(len(msg), h) {
w.RUnlock()
w.Lock()
if w.needRotateHourly(len(msg), h) {
if err := w.doRotate(when); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
}
w.Unlock()
} else if w.needRotateDaily(len(msg), d) {
w.RUnlock() w.RUnlock()
w.Lock() w.Lock()
if w.needRotate(len(msg), d) { if w.needRotateDaily(len(msg), d) {
if err := w.doRotate(when); err != nil { if err := w.doRotate(when); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
} }
...@@ -161,6 +191,10 @@ func (w *fileLogWriter) createLogFile() (*os.File, error) { ...@@ -161,6 +191,10 @@ func (w *fileLogWriter) createLogFile() (*os.File, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
filepath := path.Dir(w.Filename)
os.MkdirAll(filepath, os.FileMode(perm))
fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm)) fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm))
if err == nil { if err == nil {
// Make sure file perm is user set perm cause of `os.OpenFile` will obey umask // Make sure file perm is user set perm cause of `os.OpenFile` will obey umask
...@@ -178,8 +212,12 @@ func (w *fileLogWriter) initFd() error { ...@@ -178,8 +212,12 @@ func (w *fileLogWriter) initFd() error {
w.maxSizeCurSize = int(fInfo.Size()) w.maxSizeCurSize = int(fInfo.Size())
w.dailyOpenTime = time.Now() w.dailyOpenTime = time.Now()
w.dailyOpenDate = w.dailyOpenTime.Day() w.dailyOpenDate = w.dailyOpenTime.Day()
w.hourlyOpenTime = time.Now()
w.hourlyOpenDate = w.hourlyOpenTime.Hour()
w.maxLinesCurLines = 0 w.maxLinesCurLines = 0
if w.Daily { if w.Hourly {
go w.hourlyRotate(w.hourlyOpenTime)
} else if w.Daily {
go w.dailyRotate(w.dailyOpenTime) go w.dailyRotate(w.dailyOpenTime)
} }
if fInfo.Size() > 0 && w.MaxLines > 0 { if fInfo.Size() > 0 && w.MaxLines > 0 {
...@@ -198,7 +236,22 @@ func (w *fileLogWriter) dailyRotate(openTime time.Time) { ...@@ -198,7 +236,22 @@ func (w *fileLogWriter) dailyRotate(openTime time.Time) {
tm := time.NewTimer(time.Duration(nextDay.UnixNano() - openTime.UnixNano() + 100)) tm := time.NewTimer(time.Duration(nextDay.UnixNano() - openTime.UnixNano() + 100))
<-tm.C <-tm.C
w.Lock() w.Lock()
if w.needRotate(0, time.Now().Day()) { if w.needRotateDaily(0, time.Now().Day()) {
if err := w.doRotate(time.Now()); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
}
}
w.Unlock()
}
func (w *fileLogWriter) hourlyRotate(openTime time.Time) {
y, m, d := openTime.Add(1 * time.Hour).Date()
h, _, _ := openTime.Add(1 * time.Hour).Clock()
nextHour := time.Date(y, m, d, h, 0, 0, 0, openTime.Location())
tm := time.NewTimer(time.Duration(nextHour.UnixNano() - openTime.UnixNano() + 100))
<-tm.C
w.Lock()
if w.needRotateHourly(0, time.Now().Hour()) {
if err := w.doRotate(time.Now()); err != nil { if err := w.doRotate(time.Now()); err != nil {
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
} }
...@@ -238,8 +291,10 @@ func (w *fileLogWriter) lines() (int, error) { ...@@ -238,8 +291,10 @@ func (w *fileLogWriter) lines() (int, error) {
func (w *fileLogWriter) doRotate(logTime time.Time) error { func (w *fileLogWriter) doRotate(logTime time.Time) error {
// file exists // file exists
// Find the next available number // Find the next available number
num := 1 num := w.MaxFilesCurFiles + 1
fName := "" fName := ""
format := ""
var openTime time.Time
rotatePerm, err := strconv.ParseInt(w.RotatePerm, 8, 64) rotatePerm, err := strconv.ParseInt(w.RotatePerm, 8, 64)
if err != nil { if err != nil {
return err return err
...@@ -251,19 +306,26 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { ...@@ -251,19 +306,26 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error {
goto RESTART_LOGGER goto RESTART_LOGGER
} }
if w.Hourly {
format = "2006010215"
openTime = w.hourlyOpenTime
} else if w.Daily {
format = "2006-01-02"
openTime = w.dailyOpenTime
}
// only when one of them be setted, then the file would be splited
if w.MaxLines > 0 || w.MaxSize > 0 { if w.MaxLines > 0 || w.MaxSize > 0 {
for ; err == nil && num <= 999; num++ { for ; err == nil && num <= w.MaxFiles; num++ {
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix) fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format(format), num, w.suffix)
_, err = os.Lstat(fName) _, err = os.Lstat(fName)
} }
} else { } else {
fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, w.dailyOpenTime.Format("2006-01-02"), w.suffix) fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", openTime.Format(format), num, w.suffix)
_, err = os.Lstat(fName) _, err = os.Lstat(fName)
for ; err == nil && num <= 999; num++ { w.MaxFilesCurFiles = num
fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", w.dailyOpenTime.Format("2006-01-02"), num, w.suffix)
_, err = os.Lstat(fName)
}
} }
// return error if the last file checked still existed // return error if the last file checked still existed
if err == nil { if err == nil {
return fmt.Errorf("Rotate: Cannot find free log number to rename %s", w.Filename) return fmt.Errorf("Rotate: Cannot find free log number to rename %s", w.Filename)
...@@ -307,13 +369,21 @@ func (w *fileLogWriter) deleteOldLog() { ...@@ -307,13 +369,21 @@ func (w *fileLogWriter) deleteOldLog() {
if info == nil { if info == nil {
return return
} }
if w.Hourly {
if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) { if !info.IsDir() && info.ModTime().Add(1 * time.Hour * time.Duration(w.MaxHours)).Before(time.Now()) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
strings.HasSuffix(filepath.Base(path), w.suffix) { strings.HasSuffix(filepath.Base(path), w.suffix) {
os.Remove(path) os.Remove(path)
} }
} }
} else if w.Daily {
if !info.IsDir() && info.ModTime().Add(24 * time.Hour * time.Duration(w.MaxDays)).Before(time.Now()) {
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) &&
strings.HasSuffix(filepath.Base(path), w.suffix) {
os.Remove(path)
}
}
}
return return
}) })
} }
......
...@@ -47,7 +47,7 @@ import ( ...@@ -47,7 +47,7 @@ import (
// RFC5424 log message levels. // RFC5424 log message levels.
const ( const (
LevelEmergency = iota LevelEmergency = iota
LevelAlert LevelAlert
LevelCritical LevelCritical
LevelError LevelError
...@@ -116,6 +116,7 @@ type BeeLogger struct { ...@@ -116,6 +116,7 @@ type BeeLogger struct {
enableFuncCallDepth bool enableFuncCallDepth bool
loggerFuncCallDepth int loggerFuncCallDepth int
asynchronous bool asynchronous bool
prefix string
msgChanLen int64 msgChanLen int64
msgChan chan *logMsg msgChan chan *logMsg
signalChan chan string signalChan chan string
...@@ -247,7 +248,7 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { ...@@ -247,7 +248,7 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) {
} }
// writeMsg will always add a '\n' character // writeMsg will always add a '\n' character
if p[len(p)-1] == '\n' { if p[len(p)-1] == '\n' {
p = p[0 : len(p)-1] p = p[0: len(p)-1]
} }
// set levelLoggerImpl to ensure all log message will be write out // set levelLoggerImpl to ensure all log message will be write out
err = bl.writeMsg(levelLoggerImpl, string(p)) err = bl.writeMsg(levelLoggerImpl, string(p))
...@@ -267,6 +268,9 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error ...@@ -267,6 +268,9 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error
if len(v) > 0 { if len(v) > 0 {
msg = fmt.Sprintf(msg, v...) msg = fmt.Sprintf(msg, v...)
} }
msg = bl.prefix + " " + msg
when := time.Now() when := time.Now()
if bl.enableFuncCallDepth { if bl.enableFuncCallDepth {
_, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
...@@ -305,6 +309,11 @@ func (bl *BeeLogger) SetLevel(l int) { ...@@ -305,6 +309,11 @@ func (bl *BeeLogger) SetLevel(l int) {
bl.level = l bl.level = l
} }
// GetLevel Get Current log message level.
func (bl *BeeLogger) GetLevel() int {
return bl.level
}
// SetLogFuncCallDepth set log funcCallDepth // SetLogFuncCallDepth set log funcCallDepth
func (bl *BeeLogger) SetLogFuncCallDepth(d int) { func (bl *BeeLogger) SetLogFuncCallDepth(d int) {
bl.loggerFuncCallDepth = d bl.loggerFuncCallDepth = d
...@@ -320,6 +329,11 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) { ...@@ -320,6 +329,11 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
bl.enableFuncCallDepth = b bl.enableFuncCallDepth = b
} }
// set prefix
func (bl *BeeLogger) SetPrefix(s string) {
bl.prefix = s
}
// start logger chan reading. // start logger chan reading.
// when chan is not empty, write logs. // when chan is not empty, write logs.
func (bl *BeeLogger) startLogger() { func (bl *BeeLogger) startLogger() {
...@@ -544,6 +558,11 @@ func SetLevel(l int) { ...@@ -544,6 +558,11 @@ func SetLevel(l int) {
beeLogger.SetLevel(l) beeLogger.SetLevel(l)
} }
// SetPrefix sets the prefix
func SetPrefix(s string) {
beeLogger.SetPrefix(s)
}
// EnableFuncCallDepth enable log funcCallDepth // EnableFuncCallDepth enable log funcCallDepth
func EnableFuncCallDepth(b bool) { func EnableFuncCallDepth(b bool) {
beeLogger.enableFuncCallDepth = b beeLogger.enableFuncCallDepth = b
......
...@@ -33,7 +33,7 @@ func newLogWriter(wr io.Writer) *logWriter { ...@@ -33,7 +33,7 @@ func newLogWriter(wr io.Writer) *logWriter {
func (lg *logWriter) println(when time.Time, msg string) { func (lg *logWriter) println(when time.Time, msg string) {
lg.Lock() lg.Lock()
h, _ := formatTimeHeader(when) h, _, _:= formatTimeHeader(when)
lg.writer.Write(append(append(h, msg...), '\n')) lg.writer.Write(append(append(h, msg...), '\n'))
lg.Unlock() lg.Unlock()
} }
...@@ -90,10 +90,10 @@ const ( ...@@ -90,10 +90,10 @@ const (
ns1 = `0123456789` ns1 = `0123456789`
) )
func formatTimeHeader(when time.Time) ([]byte, int) { func formatTimeHeader(when time.Time) ([]byte, int, int) {
y, mo, d := when.Date() y, mo, d := when.Date()
h, mi, s := when.Clock() h, mi, s := when.Clock()
ns := when.Nanosecond()/1000000 ns := when.Nanosecond() / 1000000
//len("2006/01/02 15:04:05.123 ")==24 //len("2006/01/02 15:04:05.123 ")==24
var buf [24]byte var buf [24]byte
...@@ -123,7 +123,7 @@ func formatTimeHeader(when time.Time) ([]byte, int) { ...@@ -123,7 +123,7 @@ func formatTimeHeader(when time.Time) ([]byte, int) {
buf[23] = ' ' buf[23] = ' '
return buf[0:], d return buf[0:], d, h
} }
var ( var (
......
...@@ -67,7 +67,10 @@ func (f *multiFileLogWriter) Init(config string) error { ...@@ -67,7 +67,10 @@ func (f *multiFileLogWriter) Init(config string) error {
jsonMap["level"] = i jsonMap["level"] = i
bs, _ := json.Marshal(jsonMap) bs, _ := json.Marshal(jsonMap)
writer = newFileWriter().(*fileLogWriter) writer = newFileWriter().(*fileLogWriter)
writer.Init(string(bs)) err := writer.Init(string(bs))
if err != nil {
return err
}
f.writers[i] = writer f.writers[i] = writer
} }
} }
......
...@@ -149,7 +149,7 @@ func BitLenUintptr(n uintptr) int { ...@@ -149,7 +149,7 @@ func BitLenUintptr(n uintptr) int {
// PopCountByte returns population count of n (number of bits set in n). // PopCountByte returns population count of n (number of bits set in n).
func PopCountByte(n byte) int { func PopCountByte(n byte) int {
return int(popcnt[byte(n)]) return int(popcnt[n])
} }
// PopCountUint16 returns population count of n (number of bits set in n). // PopCountUint16 returns population count of n (number of bits set in n).
......
...@@ -5,7 +5,25 @@ ...@@ -5,7 +5,25 @@
// Package mathutil provides utilities supplementing the standard 'math' and // Package mathutil provides utilities supplementing the standard 'math' and
// 'math/rand' packages. // 'math/rand' packages.
// //
// Compatibility issues // Release history and compatibility issues
//
// 2018-10-21 Added BinaryLog
//
// 2018-04-25: New functions for determinig Max/Min of nullable values. Ex:
// func MaxPtr(a, b *int) *int {
// func MinPtr(a, b *int) *int {
// func MaxBytePtr(a, b *byte) *byte {
// func MinBytePtr(a, b *byte) *byte {
// ...
//
// 2017-10-14: New variadic functions for Max/Min. Ex:
// func MaxVal(val int, vals ...int) int {
// func MinVal(val int, vals ...int) int {
// func MaxByteVal(val byte, vals ...byte) byte {
// func MinByteVal(val byte, vals ...byte) byte {
// ...
//
// 2016-10-10: New functions QuadPolyDiscriminant and QuadPolyFactors.
// //
// 2013-12-13: The following functions have been REMOVED // 2013-12-13: The following functions have been REMOVED
// //
...@@ -68,8 +86,9 @@ const ( ...@@ -68,8 +86,9 @@ const (
) )
var ( var (
_1 = big.NewInt(1) _m1 = big.NewInt(-1)
_2 = big.NewInt(2) _1 = big.NewInt(1)
_2 = big.NewInt(2)
) )
// GCDByte returns the greatest common divisor of a and b. Based on: // GCDByte returns the greatest common divisor of a and b. Based on:
...@@ -89,7 +108,7 @@ func GCDUint16(a, b uint16) uint16 { ...@@ -89,7 +108,7 @@ func GCDUint16(a, b uint16) uint16 {
return a return a
} }
// GCD returns the greatest common divisor of a and b. // GCDUint32 returns the greatest common divisor of a and b.
func GCDUint32(a, b uint32) uint32 { func GCDUint32(a, b uint32) uint32 {
for b != 0 { for b != 0 {
a, b = b, a%b a, b = b, a%b
...@@ -97,7 +116,7 @@ func GCDUint32(a, b uint32) uint32 { ...@@ -97,7 +116,7 @@ func GCDUint32(a, b uint32) uint32 {
return a return a
} }
// GCD64 returns the greatest common divisor of a and b. // GCDUint64 returns the greatest common divisor of a and b.
func GCDUint64(a, b uint64) uint64 { func GCDUint64(a, b uint64) uint64 {
for b != 0 { for b != 0 {
a, b = b, a%b a, b = b, a%b
...@@ -257,7 +276,7 @@ func ModPowByte(b, e, m byte) byte { ...@@ -257,7 +276,7 @@ func ModPowByte(b, e, m byte) byte {
return byte(r) return byte(r)
} }
// ModPowByte computes (b^e)%m. It panics for m == 0 || b == e == 0. // ModPowUint16 computes (b^e)%m. It panics for m == 0 || b == e == 0.
func ModPowUint16(b, e, m uint16) uint16 { func ModPowUint16(b, e, m uint16) uint16 {
if b == 0 && e == 0 { if b == 0 && e == 0 {
panic(0) panic(0)
...@@ -360,7 +379,7 @@ func AddUint128_64(a, b uint64) (hi uint64, lo uint64) { ...@@ -360,7 +379,7 @@ func AddUint128_64(a, b uint64) (hi uint64, lo uint64) {
if lo < a { if lo < a {
hi = 1 hi = 1
} }
return return hi, lo
} }
// MulUint128_64 returns the uint128 bit product of uint64 a and b. // MulUint128_64 returns the uint128 bit product of uint64 a and b.
...@@ -382,7 +401,7 @@ func MulUint128_64(a, b uint64) (hi, lo uint64) { ...@@ -382,7 +401,7 @@ func MulUint128_64(a, b uint64) (hi, lo uint64) {
mid2 := ahi * blo mid2 := ahi * blo
c1, lo := AddUint128_64(lo, mid1<<w) c1, lo := AddUint128_64(lo, mid1<<w)
c2, lo := AddUint128_64(lo, mid2<<w) c2, lo := AddUint128_64(lo, mid2<<w)
_, hi = AddUint128_64(ahi*bhi, mid1>>w+mid2>>w+uint64(c1+c2)) _, hi = AddUint128_64(ahi*bhi, mid1>>w+mid2>>w+c1+c2)
return return
} }
...@@ -629,6 +648,63 @@ func Min(a, b int) int { ...@@ -629,6 +648,63 @@ func Min(a, b int) int {
return b return b
} }
// MaxPtr returns a pointer to the larger of a and b, or nil.
func MaxPtr(a, b *int) *int {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinPtr returns a pointer to the smaller of a and b, or nil.
func MinPtr(a, b *int) *int {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxVal returns the largest argument passed.
func MaxVal(val int, vals ...int) int {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinVal returns the smallest argument passed.
func MinVal(val int, vals ...int) int {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// Clamp returns a value restricted between lo and hi.
func Clamp(v, lo, hi int) int {
return Min(Max(v, lo), hi)
}
// UMax returns the larger of a and b. // UMax returns the larger of a and b.
func UMax(a, b uint) uint { func UMax(a, b uint) uint {
if a > b { if a > b {
...@@ -647,6 +723,63 @@ func UMin(a, b uint) uint { ...@@ -647,6 +723,63 @@ func UMin(a, b uint) uint {
return b return b
} }
// UMaxPtr returns a pointer to the larger of a and b, or nil.
func UMaxPtr(a, b *uint) *uint {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// UMinPtr returns a pointer to the smaller of a and b, or nil.
func UMinPtr(a, b *uint) *uint {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// UMaxVal returns the largest argument passed.
func UMaxVal(val uint, vals ...uint) uint {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// UMinVal returns the smallest argument passed.
func UMinVal(val uint, vals ...uint) uint {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// UClamp returns a value restricted between lo and hi.
func UClamp(v, lo, hi uint) uint {
return UMin(UMax(v, lo), hi)
}
// MaxByte returns the larger of a and b. // MaxByte returns the larger of a and b.
func MaxByte(a, b byte) byte { func MaxByte(a, b byte) byte {
if a > b { if a > b {
...@@ -665,6 +798,63 @@ func MinByte(a, b byte) byte { ...@@ -665,6 +798,63 @@ func MinByte(a, b byte) byte {
return b return b
} }
// MaxBytePtr returns a pointer to the larger of a and b, or nil.
func MaxBytePtr(a, b *byte) *byte {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinBytePtr returns a pointer to the smaller of a and b, or nil.
func MinBytePtr(a, b *byte) *byte {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxByteVal returns the largest argument passed.
func MaxByteVal(val byte, vals ...byte) byte {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinByteVal returns the smallest argument passed.
func MinByteVal(val byte, vals ...byte) byte {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampByte returns a value restricted between lo and hi.
func ClampByte(v, lo, hi byte) byte {
return MinByte(MaxByte(v, lo), hi)
}
// MaxInt8 returns the larger of a and b. // MaxInt8 returns the larger of a and b.
func MaxInt8(a, b int8) int8 { func MaxInt8(a, b int8) int8 {
if a > b { if a > b {
...@@ -683,6 +873,63 @@ func MinInt8(a, b int8) int8 { ...@@ -683,6 +873,63 @@ func MinInt8(a, b int8) int8 {
return b return b
} }
// MaxInt8Ptr returns a pointer to the larger of a and b, or nil.
func MaxInt8Ptr(a, b *int8) *int8 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinInt8Ptr returns a pointer to the smaller of a and b, or nil.
func MinInt8Ptr(a, b *int8) *int8 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxInt8Val returns the largest argument passed.
func MaxInt8Val(val int8, vals ...int8) int8 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt8Val returns the smallest argument passed.
func MinInt8Val(val int8, vals ...int8) int8 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt8 returns a value restricted between lo and hi.
func ClampInt8(v, lo, hi int8) int8 {
return MinInt8(MaxInt8(v, lo), hi)
}
// MaxUint16 returns the larger of a and b. // MaxUint16 returns the larger of a and b.
func MaxUint16(a, b uint16) uint16 { func MaxUint16(a, b uint16) uint16 {
if a > b { if a > b {
...@@ -701,6 +948,63 @@ func MinUint16(a, b uint16) uint16 { ...@@ -701,6 +948,63 @@ func MinUint16(a, b uint16) uint16 {
return b return b
} }
// MaxUint16Ptr returns a pointer to the larger of a and b, or nil.
func MaxUint16Ptr(a, b *uint16) *uint16 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinUint16Ptr returns a pointer to the smaller of a and b, or nil.
func MinUint16Ptr(a, b *uint16) *uint16 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxUint16Val returns the largest argument passed.
func MaxUint16Val(val uint16, vals ...uint16) uint16 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinUint16Val returns the smallest argument passed.
func MinUint16Val(val uint16, vals ...uint16) uint16 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampUint16 returns a value restricted between lo and hi.
func ClampUint16(v, lo, hi uint16) uint16 {
return MinUint16(MaxUint16(v, lo), hi)
}
// MaxInt16 returns the larger of a and b. // MaxInt16 returns the larger of a and b.
func MaxInt16(a, b int16) int16 { func MaxInt16(a, b int16) int16 {
if a > b { if a > b {
...@@ -719,6 +1023,63 @@ func MinInt16(a, b int16) int16 { ...@@ -719,6 +1023,63 @@ func MinInt16(a, b int16) int16 {
return b return b
} }
// MaxInt16Ptr returns a pointer to the larger of a and b, or nil.
func MaxInt16Ptr(a, b *int16) *int16 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinInt16Ptr returns a pointer to the smaller of a and b, or nil.
func MinInt16Ptr(a, b *int16) *int16 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxInt16Val returns the largest argument passed.
func MaxInt16Val(val int16, vals ...int16) int16 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt16Val returns the smallest argument passed.
func MinInt16Val(val int16, vals ...int16) int16 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt16 returns a value restricted between lo and hi.
func ClampInt16(v, lo, hi int16) int16 {
return MinInt16(MaxInt16(v, lo), hi)
}
// MaxUint32 returns the larger of a and b. // MaxUint32 returns the larger of a and b.
func MaxUint32(a, b uint32) uint32 { func MaxUint32(a, b uint32) uint32 {
if a > b { if a > b {
...@@ -737,6 +1098,63 @@ func MinUint32(a, b uint32) uint32 { ...@@ -737,6 +1098,63 @@ func MinUint32(a, b uint32) uint32 {
return b return b
} }
// MaxUint32Ptr returns a pointer to the larger of a and b, or nil.
func MaxUint32Ptr(a, b *uint32) *uint32 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinUint32Ptr returns a pointer to the smaller of a and b, or nil.
func MinUint32Ptr(a, b *uint32) *uint32 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxUint32Val returns the largest argument passed.
func MaxUint32Val(val uint32, vals ...uint32) uint32 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinUint32Val returns the smallest argument passed.
func MinUint32Val(val uint32, vals ...uint32) uint32 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampUint32 returns a value restricted between lo and hi.
func ClampUint32(v, lo, hi uint32) uint32 {
return MinUint32(MaxUint32(v, lo), hi)
}
// MaxInt32 returns the larger of a and b. // MaxInt32 returns the larger of a and b.
func MaxInt32(a, b int32) int32 { func MaxInt32(a, b int32) int32 {
if a > b { if a > b {
...@@ -755,6 +1173,63 @@ func MinInt32(a, b int32) int32 { ...@@ -755,6 +1173,63 @@ func MinInt32(a, b int32) int32 {
return b return b
} }
// MaxInt32Ptr returns a pointer to the larger of a and b, or nil.
func MaxInt32Ptr(a, b *int32) *int32 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinInt32Ptr returns a pointer to the smaller of a and b, or nil.
func MinInt32Ptr(a, b *int32) *int32 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxInt32Val returns the largest argument passed.
func MaxInt32Val(val int32, vals ...int32) int32 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt32Val returns the smallest argument passed.
func MinInt32Val(val int32, vals ...int32) int32 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt32 returns a value restricted between lo and hi.
func ClampInt32(v, lo, hi int32) int32 {
return MinInt32(MaxInt32(v, lo), hi)
}
// MaxUint64 returns the larger of a and b. // MaxUint64 returns the larger of a and b.
func MaxUint64(a, b uint64) uint64 { func MaxUint64(a, b uint64) uint64 {
if a > b { if a > b {
...@@ -773,6 +1248,63 @@ func MinUint64(a, b uint64) uint64 { ...@@ -773,6 +1248,63 @@ func MinUint64(a, b uint64) uint64 {
return b return b
} }
// MaxUint64Ptr returns a pointer to the larger of a and b, or nil.
func MaxUint64Ptr(a, b *uint64) *uint64 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinUint64Ptr returns a pointer to the smaller of a and b, or nil.
func MinUint64Ptr(a, b *uint64) *uint64 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxUint64Val returns the largest argument passed.
func MaxUint64Val(val uint64, vals ...uint64) uint64 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinUint64Val returns the smallest argument passed.
func MinUint64Val(val uint64, vals ...uint64) uint64 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampUint64 returns a value restricted between lo and hi.
func ClampUint64(v, lo, hi uint64) uint64 {
return MinUint64(MaxUint64(v, lo), hi)
}
// MaxInt64 returns the larger of a and b. // MaxInt64 returns the larger of a and b.
func MaxInt64(a, b int64) int64 { func MaxInt64(a, b int64) int64 {
if a > b { if a > b {
...@@ -791,6 +1323,63 @@ func MinInt64(a, b int64) int64 { ...@@ -791,6 +1323,63 @@ func MinInt64(a, b int64) int64 {
return b return b
} }
// MaxInt64Ptr returns a pointer to the larger of a and b, or nil.
func MaxInt64Ptr(a, b *int64) *int64 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a > *b {
return a
}
return b
}
// MinInt64Ptr returns a pointer to the smaller of a and b, or nil.
func MinInt64Ptr(a, b *int64) *int64 {
if a == nil {
return b
}
if b == nil {
return a
}
if *a < *b {
return a
}
return b
}
// MaxInt64Val returns the largest argument passed.
func MaxInt64Val(val int64, vals ...int64) int64 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt64Val returns the smallest argument passed.
func MinInt64Val(val int64, vals ...int64) int64 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt64 returns a value restricted between lo and hi.
func ClampInt64(v, lo, hi int64) int64 {
return MinInt64(MaxInt64(v, lo), hi)
}
// ToBase produces n in base b. For example // ToBase produces n in base b. For example
// //
// ToBase(2047, 22) -> [1, 5, 4] // ToBase(2047, 22) -> [1, 5, 4]
......
...@@ -8,14 +8,14 @@ import ( ...@@ -8,14 +8,14 @@ import (
"sort" "sort"
) )
// Generate the first permutation of data. // PermutationFirst generates the first permutation of data.
func PermutationFirst(data sort.Interface) { func PermutationFirst(data sort.Interface) {
sort.Sort(data) sort.Sort(data)
} }
// Generate the next permutation of data if possible and return true. // PermutationNext generates the next permutation of data if possible and
// Return false if there is no more permutation left. // return true. Return false if there is no more permutation left. Based on
// Based on the algorithm described here: // the algorithm described here:
// http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order // http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
func PermutationNext(data sort.Interface) bool { func PermutationNext(data sort.Interface) bool {
var k, l int var k, l int
......
...@@ -186,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) { ...@@ -186,7 +186,6 @@ func (p *Buffer) DecodeVarint() (x uint64, err error) {
if b&0x80 == 0 { if b&0x80 == 0 {
goto done goto done
} }
// x -= 0x80 << 63 // Always zero.
return 0, errOverflow return 0, errOverflow
......
...@@ -37,24 +37,9 @@ package proto ...@@ -37,24 +37,9 @@ package proto
import ( import (
"errors" "errors"
"fmt"
"reflect" "reflect"
) )
// RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
// Marshal reports this when a required field is not initialized.
// Unmarshal reports this when a required field is missing from the wire data.
type RequiredNotSetError struct {
field string
}
func (e *RequiredNotSetError) Error() string {
if e.field == "" {
return fmt.Sprintf("proto: required field not set")
}
return fmt.Sprintf("proto: required field %q not set", e.field)
}
var ( var (
// errRepeatedHasNil is the error returned if Marshal is called with // errRepeatedHasNil is the error returned if Marshal is called with
// a struct with a repeated field containing a nil element. // a struct with a repeated field containing a nil element.
......
...@@ -488,7 +488,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error ...@@ -488,7 +488,7 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error
} }
typ := reflect.TypeOf(extension.ExtensionType) typ := reflect.TypeOf(extension.ExtensionType)
if typ != reflect.TypeOf(value) { if typ != reflect.TypeOf(value) {
return errors.New("proto: bad extension value type") return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", value, extension.ExtensionType)
} }
// nil extension values need to be caught early, because the // nil extension values need to be caught early, because the
// encoder can't distinguish an ErrNil due to a nil extension // encoder can't distinguish an ErrNil due to a nil extension
......
...@@ -265,7 +265,6 @@ package proto ...@@ -265,7 +265,6 @@ package proto
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log" "log"
"reflect" "reflect"
...@@ -274,34 +273,73 @@ import ( ...@@ -274,34 +273,73 @@ import (
"sync" "sync"
) )
var errInvalidUTF8 = errors.New("proto: invalid UTF-8 string") // RequiredNotSetError is an error type returned by either Marshal or Unmarshal.
// Marshal reports this when a required field is not initialized.
// Unmarshal reports this when a required field is missing from the wire data.
type RequiredNotSetError struct{ field string }
// Message is implemented by generated protocol buffer messages. func (e *RequiredNotSetError) Error() string {
type Message interface { if e.field == "" {
Reset() return fmt.Sprintf("proto: required field not set")
String() string }
ProtoMessage() return fmt.Sprintf("proto: required field %q not set", e.field)
}
func (e *RequiredNotSetError) RequiredNotSet() bool {
return true
} }
// Stats records allocation details about the protocol buffer encoders type invalidUTF8Error struct{ field string }
// and decoders. Useful for tuning the library itself.
type Stats struct { func (e *invalidUTF8Error) Error() string {
Emalloc uint64 // mallocs in encode if e.field == "" {
Dmalloc uint64 // mallocs in decode return "proto: invalid UTF-8 detected"
Encode uint64 // number of encodes }
Decode uint64 // number of decodes return fmt.Sprintf("proto: field %q contains invalid UTF-8", e.field)
Chit uint64 // number of cache hits }
Cmiss uint64 // number of cache misses func (e *invalidUTF8Error) InvalidUTF8() bool {
Size uint64 // number of sizes return true
}
// errInvalidUTF8 is a sentinel error to identify fields with invalid UTF-8.
// This error should not be exposed to the external API as such errors should
// be recreated with the field information.
var errInvalidUTF8 = &invalidUTF8Error{}
// isNonFatal reports whether the error is either a RequiredNotSet error
// or a InvalidUTF8 error.
func isNonFatal(err error) bool {
if re, ok := err.(interface{ RequiredNotSet() bool }); ok && re.RequiredNotSet() {
return true
}
if re, ok := err.(interface{ InvalidUTF8() bool }); ok && re.InvalidUTF8() {
return true
}
return false
} }
// Set to true to enable stats collection. type nonFatal struct{ E error }
const collectStats = false
var stats Stats // Merge merges err into nf and reports whether it was successful.
// Otherwise it returns false for any fatal non-nil errors.
func (nf *nonFatal) Merge(err error) (ok bool) {
if err == nil {
return true // not an error
}
if !isNonFatal(err) {
return false // fatal error
}
if nf.E == nil {
nf.E = err // store first instance of non-fatal error
}
return true
}
// GetStats returns a copy of the global Stats structure. // Message is implemented by generated protocol buffer messages.
func GetStats() Stats { return stats } type Message interface {
Reset()
String() string
ProtoMessage()
}
// A Buffer is a buffer manager for marshaling and unmarshaling // A Buffer is a buffer manager for marshaling and unmarshaling
// protocol buffers. It may be reused between invocations to // protocol buffers. It may be reused between invocations to
......
...@@ -139,7 +139,7 @@ type Properties struct { ...@@ -139,7 +139,7 @@ type Properties struct {
Repeated bool Repeated bool
Packed bool // relevant for repeated primitives only Packed bool // relevant for repeated primitives only
Enum string // set for enum types only Enum string // set for enum types only
proto3 bool // whether this is known to be a proto3 field; set for []byte only proto3 bool // whether this is known to be a proto3 field
oneof bool // whether this is a oneof field oneof bool // whether this is a oneof field
Default string // default value Default string // default value
...@@ -148,9 +148,9 @@ type Properties struct { ...@@ -148,9 +148,9 @@ type Properties struct {
stype reflect.Type // set for struct types only stype reflect.Type // set for struct types only
sprop *StructProperties // set for struct types only sprop *StructProperties // set for struct types only
mtype reflect.Type // set for map types only mtype reflect.Type // set for map types only
mkeyprop *Properties // set for map types only MapKeyProp *Properties // set for map types only
mvalprop *Properties // set for map types only MapValProp *Properties // set for map types only
} }
// String formats the properties in the protobuf struct field tag style. // String formats the properties in the protobuf struct field tag style.
...@@ -275,16 +275,16 @@ func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, loc ...@@ -275,16 +275,16 @@ func (p *Properties) setFieldProps(typ reflect.Type, f *reflect.StructField, loc
case reflect.Map: case reflect.Map:
p.mtype = t1 p.mtype = t1
p.mkeyprop = &Properties{} p.MapKeyProp = &Properties{}
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp) p.MapKeyProp.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
p.mvalprop = &Properties{} p.MapValProp = &Properties{}
vtype := p.mtype.Elem() vtype := p.mtype.Elem()
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice { if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
// The value type is not a message (*T) or bytes ([]byte), // The value type is not a message (*T) or bytes ([]byte),
// so we need encoders for the pointer to this type. // so we need encoders for the pointer to this type.
vtype = reflect.PtrTo(vtype) vtype = reflect.PtrTo(vtype)
} }
p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) p.MapValProp.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
} }
if p.stype != nil { if p.stype != nil {
...@@ -334,9 +334,6 @@ func GetProperties(t reflect.Type) *StructProperties { ...@@ -334,9 +334,6 @@ func GetProperties(t reflect.Type) *StructProperties {
sprop, ok := propertiesMap[t] sprop, ok := propertiesMap[t]
propertiesMu.RUnlock() propertiesMu.RUnlock()
if ok { if ok {
if collectStats {
stats.Chit++
}
return sprop return sprop
} }
...@@ -349,14 +346,8 @@ func GetProperties(t reflect.Type) *StructProperties { ...@@ -349,14 +346,8 @@ func GetProperties(t reflect.Type) *StructProperties {
// getPropertiesLocked requires that propertiesMu is held. // getPropertiesLocked requires that propertiesMu is held.
func getPropertiesLocked(t reflect.Type) *StructProperties { func getPropertiesLocked(t reflect.Type) *StructProperties {
if prop, ok := propertiesMap[t]; ok { if prop, ok := propertiesMap[t]; ok {
if collectStats {
stats.Chit++
}
return prop return prop
} }
if collectStats {
stats.Cmiss++
}
prop := new(StructProperties) prop := new(StructProperties)
// in case of recursive protos, fill this in now. // in case of recursive protos, fill this in now.
......
...@@ -231,7 +231,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte ...@@ -231,7 +231,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
return b, err return b, err
} }
var err, errreq error var err, errLater error
// The old marshaler encodes extensions at beginning. // The old marshaler encodes extensions at beginning.
if u.extensions.IsValid() { if u.extensions.IsValid() {
e := ptr.offset(u.extensions).toExtensions() e := ptr.offset(u.extensions).toExtensions()
...@@ -252,11 +252,13 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte ...@@ -252,11 +252,13 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
} }
} }
for _, f := range u.fields { for _, f := range u.fields {
if f.required && errreq == nil { if f.required {
if ptr.offset(f.field).getPointer().isNil() { if ptr.offset(f.field).getPointer().isNil() {
// Required field is not set. // Required field is not set.
// We record the error but keep going, to give a complete marshaling. // We record the error but keep going, to give a complete marshaling.
errreq = &RequiredNotSetError{f.name} if errLater == nil {
errLater = &RequiredNotSetError{f.name}
}
continue continue
} }
} }
...@@ -269,8 +271,8 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte ...@@ -269,8 +271,8 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
if err1, ok := err.(*RequiredNotSetError); ok { if err1, ok := err.(*RequiredNotSetError); ok {
// Required field in submessage is not set. // Required field in submessage is not set.
// We record the error but keep going, to give a complete marshaling. // We record the error but keep going, to give a complete marshaling.
if errreq == nil { if errLater == nil {
errreq = &RequiredNotSetError{f.name + "." + err1.field} errLater = &RequiredNotSetError{f.name + "." + err1.field}
} }
continue continue
} }
...@@ -278,8 +280,11 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte ...@@ -278,8 +280,11 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
err = errors.New("proto: repeated field " + f.name + " has nil element") err = errors.New("proto: repeated field " + f.name + " has nil element")
} }
if err == errInvalidUTF8 { if err == errInvalidUTF8 {
fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name if errLater == nil {
err = fmt.Errorf("proto: string field %q contains invalid UTF-8", fullName) fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
errLater = &invalidUTF8Error{fullName}
}
continue
} }
return b, err return b, err
} }
...@@ -288,7 +293,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte ...@@ -288,7 +293,7 @@ func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte
s := *ptr.offset(u.unrecognized).toBytes() s := *ptr.offset(u.unrecognized).toBytes()
b = append(b, s...) b = append(b, s...)
} }
return b, errreq return b, errLater
} }
// computeMarshalInfo initializes the marshal info. // computeMarshalInfo initializes the marshal info.
...@@ -443,7 +448,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) { ...@@ -443,7 +448,7 @@ func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) {
func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) { func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
fi.field = toField(f) fi.field = toField(f)
fi.wiretag = 1<<31 - 1 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire. fi.wiretag = math.MaxInt32 // Use a large tag number, make oneofs sorted at the end. This tag will not appear on the wire.
fi.isPointer = true fi.isPointer = true
fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f) fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
fi.oneofElems = make(map[reflect.Type]*marshalElemInfo) fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
...@@ -534,6 +539,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma ...@@ -534,6 +539,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
packed := false packed := false
proto3 := false proto3 := false
validateUTF8 := true
for i := 2; i < len(tags); i++ { for i := 2; i < len(tags); i++ {
if tags[i] == "packed" { if tags[i] == "packed" {
packed = true packed = true
...@@ -542,6 +548,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma ...@@ -542,6 +548,7 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
proto3 = true proto3 = true
} }
} }
validateUTF8 = validateUTF8 && proto3
switch t.Kind() { switch t.Kind() {
case reflect.Bool: case reflect.Bool:
...@@ -739,6 +746,18 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma ...@@ -739,6 +746,18 @@ func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, ma
} }
return sizeFloat64Value, appendFloat64Value return sizeFloat64Value, appendFloat64Value
case reflect.String: case reflect.String:
if validateUTF8 {
if pointer {
return sizeStringPtr, appendUTF8StringPtr
}
if slice {
return sizeStringSlice, appendUTF8StringSlice
}
if nozero {
return sizeStringValueNoZero, appendUTF8StringValueNoZero
}
return sizeStringValue, appendUTF8StringValue
}
if pointer { if pointer {
return sizeStringPtr, appendStringPtr return sizeStringPtr, appendStringPtr
} }
...@@ -1987,52 +2006,105 @@ func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byt ...@@ -1987,52 +2006,105 @@ func appendBoolPackedSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byt
return b, nil return b, nil
} }
func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { func appendStringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
v := *ptr.toString()
b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v)))
b = append(b, v...)
return b, nil
}
func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
v := *ptr.toString()
if v == "" {
return b, nil
}
b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v)))
b = append(b, v...)
return b, nil
}
func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
p := *ptr.toStringPtr()
if p == nil {
return b, nil
}
v := *p
b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v)))
b = append(b, v...)
return b, nil
}
func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
s := *ptr.toStringSlice()
for _, v := range s {
b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v)))
b = append(b, v...)
}
return b, nil
}
func appendUTF8StringValue(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
var invalidUTF8 bool
v := *ptr.toString() v := *ptr.toString()
if !utf8.ValidString(v) { if !utf8.ValidString(v) {
return nil, errInvalidUTF8 invalidUTF8 = true
} }
b = appendVarint(b, wiretag) b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v))) b = appendVarint(b, uint64(len(v)))
b = append(b, v...) b = append(b, v...)
if invalidUTF8 {
return b, errInvalidUTF8
}
return b, nil return b, nil
} }
func appendStringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { func appendUTF8StringValueNoZero(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
var invalidUTF8 bool
v := *ptr.toString() v := *ptr.toString()
if v == "" { if v == "" {
return b, nil return b, nil
} }
if !utf8.ValidString(v) { if !utf8.ValidString(v) {
return nil, errInvalidUTF8 invalidUTF8 = true
} }
b = appendVarint(b, wiretag) b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v))) b = appendVarint(b, uint64(len(v)))
b = append(b, v...) b = append(b, v...)
if invalidUTF8 {
return b, errInvalidUTF8
}
return b, nil return b, nil
} }
func appendStringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { func appendUTF8StringPtr(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
var invalidUTF8 bool
p := *ptr.toStringPtr() p := *ptr.toStringPtr()
if p == nil { if p == nil {
return b, nil return b, nil
} }
v := *p v := *p
if !utf8.ValidString(v) { if !utf8.ValidString(v) {
return nil, errInvalidUTF8 invalidUTF8 = true
} }
b = appendVarint(b, wiretag) b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v))) b = appendVarint(b, uint64(len(v)))
b = append(b, v...) b = append(b, v...)
if invalidUTF8 {
return b, errInvalidUTF8
}
return b, nil return b, nil
} }
func appendStringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { func appendUTF8StringSlice(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
var invalidUTF8 bool
s := *ptr.toStringSlice() s := *ptr.toStringSlice()
for _, v := range s { for _, v := range s {
if !utf8.ValidString(v) { if !utf8.ValidString(v) {
return nil, errInvalidUTF8 invalidUTF8 = true
} }
b = appendVarint(b, wiretag) b = appendVarint(b, wiretag)
b = appendVarint(b, uint64(len(v))) b = appendVarint(b, uint64(len(v)))
b = append(b, v...) b = append(b, v...)
} }
if invalidUTF8 {
return b, errInvalidUTF8
}
return b, nil return b, nil
} }
func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) { func appendBytes(b []byte, ptr pointer, wiretag uint64, _ bool) ([]byte, error) {
...@@ -2111,7 +2183,8 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { ...@@ -2111,7 +2183,8 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
}, },
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
s := ptr.getPointerSlice() s := ptr.getPointerSlice()
var err, errreq error var err error
var nerr nonFatal
for _, v := range s { for _, v := range s {
if v.isNil() { if v.isNil() {
return b, errRepeatedHasNil return b, errRepeatedHasNil
...@@ -2119,22 +2192,14 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) { ...@@ -2119,22 +2192,14 @@ func makeGroupSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
b = appendVarint(b, wiretag) // start group b = appendVarint(b, wiretag) // start group
b, err = u.marshal(b, v, deterministic) b, err = u.marshal(b, v, deterministic)
b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group b = appendVarint(b, wiretag+(WireEndGroup-WireStartGroup)) // end group
if err != nil { if !nerr.Merge(err) {
if _, ok := err.(*RequiredNotSetError); ok {
// Required field in submessage is not set.
// We record the error but keep going, to give a complete marshaling.
if errreq == nil {
errreq = err
}
continue
}
if err == ErrNil { if err == ErrNil {
err = errRepeatedHasNil err = errRepeatedHasNil
} }
return b, err return b, err
} }
} }
return b, errreq return b, nerr.E
} }
} }
...@@ -2178,7 +2243,8 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { ...@@ -2178,7 +2243,8 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
}, },
func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) { func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error) {
s := ptr.getPointerSlice() s := ptr.getPointerSlice()
var err, errreq error var err error
var nerr nonFatal
for _, v := range s { for _, v := range s {
if v.isNil() { if v.isNil() {
return b, errRepeatedHasNil return b, errRepeatedHasNil
...@@ -2188,22 +2254,14 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) { ...@@ -2188,22 +2254,14 @@ func makeMessageSliceMarshaler(u *marshalInfo) (sizer, marshaler) {
b = appendVarint(b, uint64(siz)) b = appendVarint(b, uint64(siz))
b, err = u.marshal(b, v, deterministic) b, err = u.marshal(b, v, deterministic)
if err != nil { if !nerr.Merge(err) {
if _, ok := err.(*RequiredNotSetError); ok {
// Required field in submessage is not set.
// We record the error but keep going, to give a complete marshaling.
if errreq == nil {
errreq = err
}
continue
}
if err == ErrNil { if err == ErrNil {
err = errRepeatedHasNil err = errRepeatedHasNil
} }
return b, err return b, err
} }
} }
return b, errreq return b, nerr.E
} }
} }
...@@ -2227,6 +2285,25 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { ...@@ -2227,6 +2285,25 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
// value. // value.
// Key cannot be pointer-typed. // Key cannot be pointer-typed.
valIsPtr := valType.Kind() == reflect.Ptr valIsPtr := valType.Kind() == reflect.Ptr
// If value is a message with nested maps, calling
// valSizer in marshal may be quadratic. We should use
// cached version in marshal (but not in size).
// If value is not message type, we don't have size cache,
// but it cannot be nested either. Just use valSizer.
valCachedSizer := valSizer
if valIsPtr && valType.Elem().Kind() == reflect.Struct {
u := getMarshalInfo(valType.Elem())
valCachedSizer = func(ptr pointer, tagsize int) int {
// Same as message sizer, but use cache.
p := ptr.getPointer()
if p.isNil() {
return 0
}
siz := u.cachedsize(p)
return siz + SizeVarint(uint64(siz)) + tagsize
}
}
return func(ptr pointer, tagsize int) int { return func(ptr pointer, tagsize int) int {
m := ptr.asPointerTo(t).Elem() // the map m := ptr.asPointerTo(t).Elem() // the map
n := 0 n := 0
...@@ -2247,24 +2324,26 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) { ...@@ -2247,24 +2324,26 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
if len(keys) > 1 && deterministic { if len(keys) > 1 && deterministic {
sort.Sort(mapKeys(keys)) sort.Sort(mapKeys(keys))
} }
var nerr nonFatal
for _, k := range keys { for _, k := range keys {
ki := k.Interface() ki := k.Interface()
vi := m.MapIndex(k).Interface() vi := m.MapIndex(k).Interface()
kaddr := toAddrPointer(&ki, false) // pointer to key kaddr := toAddrPointer(&ki, false) // pointer to key
vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value vaddr := toAddrPointer(&vi, valIsPtr) // pointer to value
b = appendVarint(b, tag) b = appendVarint(b, tag)
siz := keySizer(kaddr, 1) + valSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1) siz := keySizer(kaddr, 1) + valCachedSizer(vaddr, 1) // tag of key = 1 (size=1), tag of val = 2 (size=1)
b = appendVarint(b, uint64(siz)) b = appendVarint(b, uint64(siz))
b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic) b, err = keyMarshaler(b, kaddr, keyWireTag, deterministic)
if err != nil { if !nerr.Merge(err) {
return b, err return b, err
} }
b, err = valMarshaler(b, vaddr, valWireTag, deterministic) b, err = valMarshaler(b, vaddr, valWireTag, deterministic)
if err != nil && err != ErrNil { // allow nil value in map if err != ErrNil && !nerr.Merge(err) { // allow nil value in map
return b, err return b, err
} }
} }
return b, nil return b, nerr.E
} }
} }
...@@ -2337,6 +2416,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de ...@@ -2337,6 +2416,7 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
defer mu.Unlock() defer mu.Unlock()
var err error var err error
var nerr nonFatal
// Fast-path for common cases: zero or one extensions. // Fast-path for common cases: zero or one extensions.
// Don't bother sorting the keys. // Don't bother sorting the keys.
...@@ -2356,11 +2436,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de ...@@ -2356,11 +2436,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic) b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if err != nil { if !nerr.Merge(err) {
return b, err return b, err
} }
} }
return b, nil return b, nerr.E
} }
// Sort the keys to provide a deterministic encoding. // Sort the keys to provide a deterministic encoding.
...@@ -2387,11 +2467,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de ...@@ -2387,11 +2467,11 @@ func (u *marshalInfo) appendExtensions(b []byte, ext *XXX_InternalExtensions, de
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic) b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if err != nil { if !nerr.Merge(err) {
return b, err return b, err
} }
} }
return b, nil return b, nerr.E
} }
// message set format is: // message set format is:
...@@ -2448,6 +2528,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de ...@@ -2448,6 +2528,7 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
defer mu.Unlock() defer mu.Unlock()
var err error var err error
var nerr nonFatal
// Fast-path for common cases: zero or one extensions. // Fast-path for common cases: zero or one extensions.
// Don't bother sorting the keys. // Don't bother sorting the keys.
...@@ -2474,12 +2555,12 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de ...@@ -2474,12 +2555,12 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
if err != nil { if !nerr.Merge(err) {
return b, err return b, err
} }
b = append(b, 1<<3|WireEndGroup) b = append(b, 1<<3|WireEndGroup)
} }
return b, nil return b, nerr.E
} }
// Sort the keys to provide a deterministic encoding. // Sort the keys to provide a deterministic encoding.
...@@ -2513,11 +2594,11 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de ...@@ -2513,11 +2594,11 @@ func (u *marshalInfo) appendMessageSet(b []byte, ext *XXX_InternalExtensions, de
p := toAddrPointer(&v, ei.isptr) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic) b, err = ei.marshaler(b, p, 3<<3|WireBytes, deterministic)
b = append(b, 1<<3|WireEndGroup) b = append(b, 1<<3|WireEndGroup)
if err != nil { if !nerr.Merge(err) {
return b, err return b, err
} }
} }
return b, nil return b, nerr.E
} }
// sizeV1Extensions computes the size of encoded data for a V1-API extension field. // sizeV1Extensions computes the size of encoded data for a V1-API extension field.
...@@ -2560,6 +2641,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ ...@@ -2560,6 +2641,7 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
sort.Ints(keys) sort.Ints(keys)
var err error var err error
var nerr nonFatal
for _, k := range keys { for _, k := range keys {
e := m[int32(k)] e := m[int32(k)]
if e.value == nil || e.desc == nil { if e.value == nil || e.desc == nil {
...@@ -2576,11 +2658,11 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ ...@@ -2576,11 +2658,11 @@ func (u *marshalInfo) appendV1Extensions(b []byte, m map[int32]Extension, determ
v := e.value v := e.value
p := toAddrPointer(&v, ei.isptr) p := toAddrPointer(&v, ei.isptr)
b, err = ei.marshaler(b, p, ei.wiretag, deterministic) b, err = ei.marshaler(b, p, ei.wiretag, deterministic)
if err != nil { if !nerr.Merge(err) {
return b, err return b, err
} }
} }
return b, nil return b, nerr.E
} }
// newMarshaler is the interface representing objects that can marshal themselves. // newMarshaler is the interface representing objects that can marshal themselves.
......
...@@ -138,8 +138,8 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error { ...@@ -138,8 +138,8 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
if u.isMessageSet { if u.isMessageSet {
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions()) return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
} }
var reqMask uint64 // bitmask of required fields we've seen. var reqMask uint64 // bitmask of required fields we've seen.
var rnse *RequiredNotSetError // an instance of a RequiredNotSetError returned by a submessage. var errLater error
for len(b) > 0 { for len(b) > 0 {
// Read tag and wire type. // Read tag and wire type.
// Special case 1 and 2 byte varints. // Special case 1 and 2 byte varints.
...@@ -178,14 +178,19 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error { ...@@ -178,14 +178,19 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
if r, ok := err.(*RequiredNotSetError); ok { if r, ok := err.(*RequiredNotSetError); ok {
// Remember this error, but keep parsing. We need to produce // Remember this error, but keep parsing. We need to produce
// a full parse even if a required field is missing. // a full parse even if a required field is missing.
rnse = r if errLater == nil {
errLater = r
}
reqMask |= f.reqMask reqMask |= f.reqMask
continue continue
} }
if err != errInternalBadWireType { if err != errInternalBadWireType {
if err == errInvalidUTF8 { if err == errInvalidUTF8 {
fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name if errLater == nil {
err = fmt.Errorf("proto: string field %q contains invalid UTF-8", fullName) fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
errLater = &invalidUTF8Error{fullName}
}
continue
} }
return err return err
} }
...@@ -245,20 +250,16 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error { ...@@ -245,20 +250,16 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
emap[int32(tag)] = e emap[int32(tag)] = e
} }
} }
if rnse != nil { if reqMask != u.reqMask && errLater == nil {
// A required field of a submessage/group is missing. Return that error.
return rnse
}
if reqMask != u.reqMask {
// A required field of this message is missing. // A required field of this message is missing.
for _, n := range u.reqFields { for _, n := range u.reqFields {
if reqMask&1 == 0 { if reqMask&1 == 0 {
return &RequiredNotSetError{n} errLater = &RequiredNotSetError{n}
} }
reqMask >>= 1 reqMask >>= 1
} }
} }
return nil return errLater
} }
// computeUnmarshalInfo fills in u with information for use // computeUnmarshalInfo fills in u with information for use
...@@ -456,11 +457,17 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { ...@@ -456,11 +457,17 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
tagArray := strings.Split(tags, ",") tagArray := strings.Split(tags, ",")
encoding := tagArray[0] encoding := tagArray[0]
name := "unknown" name := "unknown"
proto3 := false
validateUTF8 := true
for _, tag := range tagArray[3:] { for _, tag := range tagArray[3:] {
if strings.HasPrefix(tag, "name=") { if strings.HasPrefix(tag, "name=") {
name = tag[5:] name = tag[5:]
} }
if tag == "proto3" {
proto3 = true
}
} }
validateUTF8 = validateUTF8 && proto3
// Figure out packaging (pointer, slice, or both) // Figure out packaging (pointer, slice, or both)
slice := false slice := false
...@@ -608,6 +615,15 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler { ...@@ -608,6 +615,15 @@ func typeUnmarshaler(t reflect.Type, tags string) unmarshaler {
} }
return unmarshalBytesValue return unmarshalBytesValue
case reflect.String: case reflect.String:
if validateUTF8 {
if pointer {
return unmarshalUTF8StringPtr
}
if slice {
return unmarshalUTF8StringSlice
}
return unmarshalUTF8StringValue
}
if pointer { if pointer {
return unmarshalStringPtr return unmarshalStringPtr
} }
...@@ -1462,9 +1478,6 @@ func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) { ...@@ -1462,9 +1478,6 @@ func unmarshalStringValue(b []byte, f pointer, w int) ([]byte, error) {
return nil, io.ErrUnexpectedEOF return nil, io.ErrUnexpectedEOF
} }
v := string(b[:x]) v := string(b[:x])
if !utf8.ValidString(v) {
return nil, errInvalidUTF8
}
*f.toString() = v *f.toString() = v
return b[x:], nil return b[x:], nil
} }
...@@ -1482,9 +1495,6 @@ func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) { ...@@ -1482,9 +1495,6 @@ func unmarshalStringPtr(b []byte, f pointer, w int) ([]byte, error) {
return nil, io.ErrUnexpectedEOF return nil, io.ErrUnexpectedEOF
} }
v := string(b[:x]) v := string(b[:x])
if !utf8.ValidString(v) {
return nil, errInvalidUTF8
}
*f.toStringPtr() = &v *f.toStringPtr() = &v
return b[x:], nil return b[x:], nil
} }
...@@ -1502,11 +1512,69 @@ func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) { ...@@ -1502,11 +1512,69 @@ func unmarshalStringSlice(b []byte, f pointer, w int) ([]byte, error) {
return nil, io.ErrUnexpectedEOF return nil, io.ErrUnexpectedEOF
} }
v := string(b[:x]) v := string(b[:x])
s := f.toStringSlice()
*s = append(*s, v)
return b[x:], nil
}
func unmarshalUTF8StringValue(b []byte, f pointer, w int) ([]byte, error) {
if w != WireBytes {
return b, errInternalBadWireType
}
x, n := decodeVarint(b)
if n == 0 {
return nil, io.ErrUnexpectedEOF
}
b = b[n:]
if x > uint64(len(b)) {
return nil, io.ErrUnexpectedEOF
}
v := string(b[:x])
*f.toString() = v
if !utf8.ValidString(v) {
return b[x:], errInvalidUTF8
}
return b[x:], nil
}
func unmarshalUTF8StringPtr(b []byte, f pointer, w int) ([]byte, error) {
if w != WireBytes {
return b, errInternalBadWireType
}
x, n := decodeVarint(b)
if n == 0 {
return nil, io.ErrUnexpectedEOF
}
b = b[n:]
if x > uint64(len(b)) {
return nil, io.ErrUnexpectedEOF
}
v := string(b[:x])
*f.toStringPtr() = &v
if !utf8.ValidString(v) { if !utf8.ValidString(v) {
return nil, errInvalidUTF8 return b[x:], errInvalidUTF8
}
return b[x:], nil
}
func unmarshalUTF8StringSlice(b []byte, f pointer, w int) ([]byte, error) {
if w != WireBytes {
return b, errInternalBadWireType
} }
x, n := decodeVarint(b)
if n == 0 {
return nil, io.ErrUnexpectedEOF
}
b = b[n:]
if x > uint64(len(b)) {
return nil, io.ErrUnexpectedEOF
}
v := string(b[:x])
s := f.toStringSlice() s := f.toStringSlice()
*s = append(*s, v) *s = append(*s, v)
if !utf8.ValidString(v) {
return b[x:], errInvalidUTF8
}
return b[x:], nil return b[x:], nil
} }
...@@ -1688,6 +1756,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler { ...@@ -1688,6 +1756,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
// Maps will be somewhat slow. Oh well. // Maps will be somewhat slow. Oh well.
// Read key and value from data. // Read key and value from data.
var nerr nonFatal
k := reflect.New(kt) k := reflect.New(kt)
v := reflect.New(vt) v := reflect.New(vt)
for len(b) > 0 { for len(b) > 0 {
...@@ -1708,7 +1777,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler { ...@@ -1708,7 +1777,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
err = errInternalBadWireType // skip unknown tag err = errInternalBadWireType // skip unknown tag
} }
if err == nil { if nerr.Merge(err) {
continue continue
} }
if err != errInternalBadWireType { if err != errInternalBadWireType {
...@@ -1731,7 +1800,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler { ...@@ -1731,7 +1800,7 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler {
// Insert into map. // Insert into map.
m.SetMapIndex(k.Elem(), v.Elem()) m.SetMapIndex(k.Elem(), v.Elem())
return r, nil return r, nerr.E
} }
} }
...@@ -1757,15 +1826,16 @@ func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshal ...@@ -1757,15 +1826,16 @@ func makeUnmarshalOneof(typ, ityp reflect.Type, unmarshal unmarshaler) unmarshal
// Unmarshal data into holder. // Unmarshal data into holder.
// We unmarshal into the first field of the holder object. // We unmarshal into the first field of the holder object.
var err error var err error
var nerr nonFatal
b, err = unmarshal(b, valToPointer(v).offset(field0), w) b, err = unmarshal(b, valToPointer(v).offset(field0), w)
if err != nil { if !nerr.Merge(err) {
return nil, err return nil, err
} }
// Write pointer to holder into target field. // Write pointer to holder into target field.
f.asPointerTo(ityp).Elem().Set(v) f.asPointerTo(ityp).Elem().Set(v)
return b, nil return b, nerr.E
} }
} }
...@@ -1878,7 +1948,7 @@ func encodeVarint(b []byte, x uint64) []byte { ...@@ -1878,7 +1948,7 @@ func encodeVarint(b []byte, x uint64) []byte {
// If there is an error, it returns 0,0. // If there is an error, it returns 0,0.
func decodeVarint(b []byte) (uint64, int) { func decodeVarint(b []byte) (uint64, int) {
var x, y uint64 var x, y uint64
if len(b) <= 0 { if len(b) == 0 {
goto bad goto bad
} }
x = uint64(b[0]) x = uint64(b[0])
......
...@@ -353,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { ...@@ -353,7 +353,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err return err
} }
} }
if err := tm.writeAny(w, key, props.mkeyprop); err != nil { if err := tm.writeAny(w, key, props.MapKeyProp); err != nil {
return err return err
} }
if err := w.WriteByte('\n'); err != nil { if err := w.WriteByte('\n'); err != nil {
...@@ -370,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { ...@@ -370,7 +370,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
return err return err
} }
} }
if err := tm.writeAny(w, val, props.mvalprop); err != nil { if err := tm.writeAny(w, val, props.MapValProp); err != nil {
return err return err
} }
if err := w.WriteByte('\n'); err != nil { if err := w.WriteByte('\n'); err != nil {
......
...@@ -630,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error { ...@@ -630,17 +630,17 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
if err := p.consumeToken(":"); err != nil { if err := p.consumeToken(":"); err != nil {
return err return err
} }
if err := p.readAny(key, props.mkeyprop); err != nil { if err := p.readAny(key, props.MapKeyProp); err != nil {
return err return err
} }
if err := p.consumeOptionalSeparator(); err != nil { if err := p.consumeOptionalSeparator(); err != nil {
return err return err
} }
case "value": case "value":
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil { if err := p.checkForColon(props.MapValProp, dst.Type().Elem()); err != nil {
return err return err
} }
if err := p.readAny(val, props.mvalprop); err != nil { if err := p.readAny(val, props.MapValProp); err != nil {
return err return err
} }
if err := p.consumeOptionalSeparator(); err != nil { if err := p.consumeOptionalSeparator(); err != nil {
......
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/any.proto // source: google/protobuf/any.proto
package any // import "github.com/golang/protobuf/ptypes/any" package any
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
...@@ -121,7 +123,7 @@ type Any struct { ...@@ -121,7 +123,7 @@ type Any struct {
// Schemes other than `http`, `https` (or the empty scheme) might be // Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics. // used with implementation specific semantics.
// //
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"` TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
// Must be a valid serialized protocol buffer of the above specified type. // Must be a valid serialized protocol buffer of the above specified type.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -133,17 +135,19 @@ func (m *Any) Reset() { *m = Any{} } ...@@ -133,17 +135,19 @@ func (m *Any) Reset() { *m = Any{} }
func (m *Any) String() string { return proto.CompactTextString(m) } func (m *Any) String() string { return proto.CompactTextString(m) }
func (*Any) ProtoMessage() {} func (*Any) ProtoMessage() {}
func (*Any) Descriptor() ([]byte, []int) { func (*Any) Descriptor() ([]byte, []int) {
return fileDescriptor_any_744b9ca530f228db, []int{0} return fileDescriptor_b53526c13ae22eb4, []int{0}
} }
func (*Any) XXX_WellKnownType() string { return "Any" } func (*Any) XXX_WellKnownType() string { return "Any" }
func (m *Any) XXX_Unmarshal(b []byte) error { func (m *Any) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Any.Unmarshal(m, b) return xxx_messageInfo_Any.Unmarshal(m, b)
} }
func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { func (m *Any) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Any.Marshal(b, m, deterministic) return xxx_messageInfo_Any.Marshal(b, m, deterministic)
} }
func (dst *Any) XXX_Merge(src proto.Message) { func (m *Any) XXX_Merge(src proto.Message) {
xxx_messageInfo_Any.Merge(dst, src) xxx_messageInfo_Any.Merge(m, src)
} }
func (m *Any) XXX_Size() int { func (m *Any) XXX_Size() int {
return xxx_messageInfo_Any.Size(m) return xxx_messageInfo_Any.Size(m)
...@@ -172,9 +176,9 @@ func init() { ...@@ -172,9 +176,9 @@ func init() {
proto.RegisterType((*Any)(nil), "google.protobuf.Any") proto.RegisterType((*Any)(nil), "google.protobuf.Any")
} }
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_any_744b9ca530f228db) } func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor_b53526c13ae22eb4) }
var fileDescriptor_any_744b9ca530f228db = []byte{ var fileDescriptor_b53526c13ae22eb4 = []byte{
// 185 bytes of a gzipped FileDescriptorProto // 185 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
......
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/duration.proto // source: google/protobuf/duration.proto
package duration // import "github.com/golang/protobuf/ptypes/duration" package duration
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
...@@ -82,14 +84,14 @@ type Duration struct { ...@@ -82,14 +84,14 @@ type Duration struct {
// Signed seconds of the span of time. Must be from -315,576,000,000 // Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive. Note: these bounds are computed from: // to +315,576,000,000 inclusive. Note: these bounds are computed from:
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
// Signed fractions of a second at nanosecond resolution of the span // Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0 // of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations // `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be // of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999 // of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive. // to +999,999,999 inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -99,17 +101,19 @@ func (m *Duration) Reset() { *m = Duration{} } ...@@ -99,17 +101,19 @@ func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) } func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {} func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) { func (*Duration) Descriptor() ([]byte, []int) {
return fileDescriptor_duration_e7d612259e3f0613, []int{0} return fileDescriptor_23597b2ebd7ac6c5, []int{0}
} }
func (*Duration) XXX_WellKnownType() string { return "Duration" } func (*Duration) XXX_WellKnownType() string { return "Duration" }
func (m *Duration) XXX_Unmarshal(b []byte) error { func (m *Duration) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Duration.Unmarshal(m, b) return xxx_messageInfo_Duration.Unmarshal(m, b)
} }
func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { func (m *Duration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Duration.Marshal(b, m, deterministic) return xxx_messageInfo_Duration.Marshal(b, m, deterministic)
} }
func (dst *Duration) XXX_Merge(src proto.Message) { func (m *Duration) XXX_Merge(src proto.Message) {
xxx_messageInfo_Duration.Merge(dst, src) xxx_messageInfo_Duration.Merge(m, src)
} }
func (m *Duration) XXX_Size() int { func (m *Duration) XXX_Size() int {
return xxx_messageInfo_Duration.Size(m) return xxx_messageInfo_Duration.Size(m)
...@@ -138,11 +142,9 @@ func init() { ...@@ -138,11 +142,9 @@ func init() {
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration") proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
} }
func init() { func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_23597b2ebd7ac6c5) }
proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor_duration_e7d612259e3f0613)
}
var fileDescriptor_duration_e7d612259e3f0613 = []byte{ var fileDescriptor_23597b2ebd7ac6c5 = []byte{
// 190 bytes of a gzipped FileDescriptorProto // 190 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
......
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: google/protobuf/timestamp.proto // source: google/protobuf/timestamp.proto
package timestamp // import "github.com/golang/protobuf/ptypes/timestamp" package timestamp
import proto "github.com/golang/protobuf/proto" import (
import fmt "fmt" fmt "fmt"
import math "math" proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal var _ = proto.Marshal
...@@ -100,12 +102,12 @@ type Timestamp struct { ...@@ -100,12 +102,12 @@ type Timestamp struct {
// Represents seconds of UTC time since Unix epoch // Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive. // 9999-12-31T23:59:59Z inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"` Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. Negative // Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values // second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999 // that count forward in time. Must be from 0 to 999,999,999
// inclusive. // inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"` Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -115,17 +117,19 @@ func (m *Timestamp) Reset() { *m = Timestamp{} } ...@@ -115,17 +117,19 @@ func (m *Timestamp) Reset() { *m = Timestamp{} }
func (m *Timestamp) String() string { return proto.CompactTextString(m) } func (m *Timestamp) String() string { return proto.CompactTextString(m) }
func (*Timestamp) ProtoMessage() {} func (*Timestamp) ProtoMessage() {}
func (*Timestamp) Descriptor() ([]byte, []int) { func (*Timestamp) Descriptor() ([]byte, []int) {
return fileDescriptor_timestamp_b826e8e5fba671a8, []int{0} return fileDescriptor_292007bbfe81227e, []int{0}
} }
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" } func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
func (m *Timestamp) XXX_Unmarshal(b []byte) error { func (m *Timestamp) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Timestamp.Unmarshal(m, b) return xxx_messageInfo_Timestamp.Unmarshal(m, b)
} }
func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { func (m *Timestamp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic) return xxx_messageInfo_Timestamp.Marshal(b, m, deterministic)
} }
func (dst *Timestamp) XXX_Merge(src proto.Message) { func (m *Timestamp) XXX_Merge(src proto.Message) {
xxx_messageInfo_Timestamp.Merge(dst, src) xxx_messageInfo_Timestamp.Merge(m, src)
} }
func (m *Timestamp) XXX_Size() int { func (m *Timestamp) XXX_Size() int {
return xxx_messageInfo_Timestamp.Size(m) return xxx_messageInfo_Timestamp.Size(m)
...@@ -154,11 +158,9 @@ func init() { ...@@ -154,11 +158,9 @@ func init() {
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp") proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
} }
func init() { func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_292007bbfe81227e) }
proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor_timestamp_b826e8e5fba671a8)
}
var fileDescriptor_timestamp_b826e8e5fba671a8 = []byte{ var fileDescriptor_292007bbfe81227e = []byte{
// 191 bytes of a gzipped FileDescriptorProto // 191 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d, 0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
......
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
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.
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 HOLDER 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.
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Before proposing a change, please discuss your change by raising an issue.
## License
BSD-2-Clause
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// and the supplied message. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// If additional control is required the errors.WithStack and errors.WithMessage
// functions destructure errors.Wrap into its component operations of annotating
// an error with a stack trace and an a message, respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
// %s print the error. If the error has a Cause it will be
// printed recursively
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// Where errors.StackTrace is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// }
// }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &withStack{
err,
callers(),
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: message,
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strings"
)
// Frame represents a program counter inside a stack frame.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s function name and path of source file relative to the compile time
// GOPATH separated by \n\t (<funcname>\n\t<path>)
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
// Format formats the stack of Frames according to the fmt.Formatter interface.
//
// %s lists source files for each Frame in the stack
// %v lists the source file and line number for each Frame in the stack
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
}
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}
...@@ -331,6 +331,12 @@ are a few of note: ...@@ -331,6 +331,12 @@ are a few of note:
* [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex): * [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex):
renders output as LaTeX. renders output as LaTeX.
* [bfchroma](https://github.com/Depado/bfchroma/): provides convenience
integration with the [Chroma](https://github.com/alecthomas/chroma) code
highlighting library. bfchroma is only compatible with v2 of Blackfriday and
provides a drop-in renderer ready to use with Blackfriday, as well as
options and means for further customization.
TODO TODO
---- ----
......
...@@ -1143,6 +1143,7 @@ func (p *parser) listItem(out *bytes.Buffer, data []byte, flags *int) int { ...@@ -1143,6 +1143,7 @@ func (p *parser) listItem(out *bytes.Buffer, data []byte, flags *int) int {
// process the following lines // process the following lines
containsBlankLine := false containsBlankLine := false
sublist := 0 sublist := 0
codeBlockMarker := ""
gatherlines: gatherlines:
for line < len(data) { for line < len(data) {
...@@ -1170,6 +1171,28 @@ gatherlines: ...@@ -1170,6 +1171,28 @@ gatherlines:
chunk := data[line+indent : i] chunk := data[line+indent : i]
if p.flags&EXTENSION_FENCED_CODE != 0 {
// determine if in or out of codeblock
// if in codeblock, ignore normal list processing
_, marker := isFenceLine(chunk, nil, codeBlockMarker, false)
if marker != "" {
if codeBlockMarker == "" {
// start of codeblock
codeBlockMarker = marker
} else {
// end of codeblock.
*flags |= LIST_ITEM_CONTAINS_BLOCK
codeBlockMarker = ""
}
}
// we are in a codeblock, write line, and continue
if codeBlockMarker != "" || marker != "" {
raw.Write(data[line+indent : i])
line = i
continue gatherlines
}
}
// evaluate how this line fits in // evaluate how this line fits in
switch { switch {
// is this a nested list item? // is this a nested list item?
......
...@@ -7,7 +7,7 @@ The simplest way to use Logrus is simply the package-level exported logger: ...@@ -7,7 +7,7 @@ The simplest way to use Logrus is simply the package-level exported logger:
package main package main
import ( import (
log "github.com/Sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func main() { func main() {
...@@ -21,6 +21,6 @@ The simplest way to use Logrus is simply the package-level exported logger: ...@@ -21,6 +21,6 @@ The simplest way to use Logrus is simply the package-level exported logger:
Output: Output:
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
For a full guide visit https://github.com/Sirupsen/logrus For a full guide visit https://github.com/sirupsen/logrus
*/ */
package logrus package logrus
...@@ -35,19 +35,20 @@ type Entry struct { ...@@ -35,19 +35,20 @@ type Entry struct {
Time time.Time Time time.Time
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
Level Level Level Level
// Message passed to Debug, Info, Warn, Error, Fatal or Panic // Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string Message string
// When formatter is called in entry.log(), an Buffer may be set to entry // When formatter is called in entry.log(), a Buffer may be set to entry
Buffer *bytes.Buffer Buffer *bytes.Buffer
} }
func NewEntry(logger *Logger) *Entry { func NewEntry(logger *Logger) *Entry {
return &Entry{ return &Entry{
Logger: logger, Logger: logger,
// Default is three fields, give a little extra room // Default is five fields, give a little extra room
Data: make(Fields, 5), Data: make(Fields, 5),
} }
} }
...@@ -82,51 +83,75 @@ func (entry *Entry) WithFields(fields Fields) *Entry { ...@@ -82,51 +83,75 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
for k, v := range fields { for k, v := range fields {
data[k] = v data[k] = v
} }
return &Entry{Logger: entry.Logger, Data: data} return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
} }
// This function is not declared with a pointer value because otherwise // This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines // race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) { func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer var buffer *bytes.Buffer
entry.Time = time.Now()
// Default to now, but allow users to override if they want.
//
// We don't have to worry about polluting future calls to Entry#log()
// with this assignment because this function is declared with a
// non-pointer receiver.
if entry.Time.IsZero() {
entry.Time = time.Now()
}
entry.Level = level entry.Level = level
entry.Message = msg entry.Message = msg
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil { entry.fireHooks()
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
entry.Logger.mu.Unlock()
}
buffer = bufferPool.Get().(*bytes.Buffer) buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset() buffer.Reset()
defer bufferPool.Put(buffer) defer bufferPool.Put(buffer)
entry.Buffer = buffer entry.Buffer = buffer
serialized, err := entry.Logger.Formatter.Format(&entry)
entry.write()
entry.Buffer = nil entry.Buffer = nil
// To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking
// directly here.
if level <= PanicLevel {
panic(&entry)
}
}
func (entry *Entry) fireHooks() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
err := entry.Logger.Hooks.Fire(entry.Level, entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
}
}
func (entry *Entry) write() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil { if err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
entry.Logger.mu.Unlock()
} else { } else {
entry.Logger.mu.Lock()
_, err = entry.Logger.Out.Write(serialized) _, err = entry.Logger.Out.Write(serialized)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
} }
entry.Logger.mu.Unlock()
}
// To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking
// directly here.
if level <= PanicLevel {
panic(&entry)
} }
} }
func (entry *Entry) Debug(args ...interface{}) { func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.level() >= DebugLevel { if entry.Logger.IsLevelEnabled(DebugLevel) {
entry.log(DebugLevel, fmt.Sprint(args...)) entry.log(DebugLevel, fmt.Sprint(args...))
} }
} }
...@@ -136,13 +161,13 @@ func (entry *Entry) Print(args ...interface{}) { ...@@ -136,13 +161,13 @@ func (entry *Entry) Print(args ...interface{}) {
} }
func (entry *Entry) Info(args ...interface{}) { func (entry *Entry) Info(args ...interface{}) {
if entry.Logger.level() >= InfoLevel { if entry.Logger.IsLevelEnabled(InfoLevel) {
entry.log(InfoLevel, fmt.Sprint(args...)) entry.log(InfoLevel, fmt.Sprint(args...))
} }
} }
func (entry *Entry) Warn(args ...interface{}) { func (entry *Entry) Warn(args ...interface{}) {
if entry.Logger.level() >= WarnLevel { if entry.Logger.IsLevelEnabled(WarnLevel) {
entry.log(WarnLevel, fmt.Sprint(args...)) entry.log(WarnLevel, fmt.Sprint(args...))
} }
} }
...@@ -152,20 +177,20 @@ func (entry *Entry) Warning(args ...interface{}) { ...@@ -152,20 +177,20 @@ func (entry *Entry) Warning(args ...interface{}) {
} }
func (entry *Entry) Error(args ...interface{}) { func (entry *Entry) Error(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel { if entry.Logger.IsLevelEnabled(ErrorLevel) {
entry.log(ErrorLevel, fmt.Sprint(args...)) entry.log(ErrorLevel, fmt.Sprint(args...))
} }
} }
func (entry *Entry) Fatal(args ...interface{}) { func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.level() >= FatalLevel { if entry.Logger.IsLevelEnabled(FatalLevel) {
entry.log(FatalLevel, fmt.Sprint(args...)) entry.log(FatalLevel, fmt.Sprint(args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panic(args ...interface{}) { func (entry *Entry) Panic(args ...interface{}) {
if entry.Logger.level() >= PanicLevel { if entry.Logger.IsLevelEnabled(PanicLevel) {
entry.log(PanicLevel, fmt.Sprint(args...)) entry.log(PanicLevel, fmt.Sprint(args...))
} }
panic(fmt.Sprint(args...)) panic(fmt.Sprint(args...))
...@@ -174,13 +199,13 @@ func (entry *Entry) Panic(args ...interface{}) { ...@@ -174,13 +199,13 @@ func (entry *Entry) Panic(args ...interface{}) {
// Entry Printf family functions // Entry Printf family functions
func (entry *Entry) Debugf(format string, args ...interface{}) { func (entry *Entry) Debugf(format string, args ...interface{}) {
if entry.Logger.level() >= DebugLevel { if entry.Logger.IsLevelEnabled(DebugLevel) {
entry.Debug(fmt.Sprintf(format, args...)) entry.Debug(fmt.Sprintf(format, args...))
} }
} }
func (entry *Entry) Infof(format string, args ...interface{}) { func (entry *Entry) Infof(format string, args ...interface{}) {
if entry.Logger.level() >= InfoLevel { if entry.Logger.IsLevelEnabled(InfoLevel) {
entry.Info(fmt.Sprintf(format, args...)) entry.Info(fmt.Sprintf(format, args...))
} }
} }
...@@ -190,7 +215,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) { ...@@ -190,7 +215,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
} }
func (entry *Entry) Warnf(format string, args ...interface{}) { func (entry *Entry) Warnf(format string, args ...interface{}) {
if entry.Logger.level() >= WarnLevel { if entry.Logger.IsLevelEnabled(WarnLevel) {
entry.Warn(fmt.Sprintf(format, args...)) entry.Warn(fmt.Sprintf(format, args...))
} }
} }
...@@ -200,20 +225,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) { ...@@ -200,20 +225,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
} }
func (entry *Entry) Errorf(format string, args ...interface{}) { func (entry *Entry) Errorf(format string, args ...interface{}) {
if entry.Logger.level() >= ErrorLevel { if entry.Logger.IsLevelEnabled(ErrorLevel) {
entry.Error(fmt.Sprintf(format, args...)) entry.Error(fmt.Sprintf(format, args...))
} }
} }
func (entry *Entry) Fatalf(format string, args ...interface{}) { func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.level() >= FatalLevel { if entry.Logger.IsLevelEnabled(FatalLevel) {
entry.Fatal(fmt.Sprintf(format, args...)) entry.Fatal(fmt.Sprintf(format, args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panicf(format string, args ...interface{}) { func (entry *Entry) Panicf(format string, args ...interface{}) {
if entry.Logger.level() >= PanicLevel { if entry.Logger.IsLevelEnabled(PanicLevel) {
entry.Panic(fmt.Sprintf(format, args...)) entry.Panic(fmt.Sprintf(format, args...))
} }
} }
...@@ -221,13 +246,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) { ...@@ -221,13 +246,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
// Entry Println family functions // Entry Println family functions
func (entry *Entry) Debugln(args ...interface{}) { func (entry *Entry) Debugln(args ...interface{}) {
if entry.Logger.level() >= DebugLevel { if entry.Logger.IsLevelEnabled(DebugLevel) {
entry.Debug(entry.sprintlnn(args...)) entry.Debug(entry.sprintlnn(args...))
} }
} }
func (entry *Entry) Infoln(args ...interface{}) { func (entry *Entry) Infoln(args ...interface{}) {
if entry.Logger.level() >= InfoLevel { if entry.Logger.IsLevelEnabled(InfoLevel) {
entry.Info(entry.sprintlnn(args...)) entry.Info(entry.sprintlnn(args...))
} }
} }
...@@ -237,7 +262,7 @@ func (entry *Entry) Println(args ...interface{}) { ...@@ -237,7 +262,7 @@ func (entry *Entry) Println(args ...interface{}) {
} }
func (entry *Entry) Warnln(args ...interface{}) { func (entry *Entry) Warnln(args ...interface{}) {
if entry.Logger.level() >= WarnLevel { if entry.Logger.IsLevelEnabled(WarnLevel) {
entry.Warn(entry.sprintlnn(args...)) entry.Warn(entry.sprintlnn(args...))
} }
} }
...@@ -247,20 +272,20 @@ func (entry *Entry) Warningln(args ...interface{}) { ...@@ -247,20 +272,20 @@ func (entry *Entry) Warningln(args ...interface{}) {
} }
func (entry *Entry) Errorln(args ...interface{}) { func (entry *Entry) Errorln(args ...interface{}) {
if entry.Logger.level() >= ErrorLevel { if entry.Logger.IsLevelEnabled(ErrorLevel) {
entry.Error(entry.sprintlnn(args...)) entry.Error(entry.sprintlnn(args...))
} }
} }
func (entry *Entry) Fatalln(args ...interface{}) { func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.level() >= FatalLevel { if entry.Logger.IsLevelEnabled(FatalLevel) {
entry.Fatal(entry.sprintlnn(args...)) entry.Fatal(entry.sprintlnn(args...))
} }
Exit(1) Exit(1)
} }
func (entry *Entry) Panicln(args ...interface{}) { func (entry *Entry) Panicln(args ...interface{}) {
if entry.Logger.level() >= PanicLevel { if entry.Logger.IsLevelEnabled(PanicLevel) {
entry.Panic(entry.sprintlnn(args...)) entry.Panic(entry.sprintlnn(args...))
} }
} }
......
...@@ -2,6 +2,7 @@ package logrus ...@@ -2,6 +2,7 @@ package logrus
import ( import (
"io" "io"
"time"
) )
var ( var (
...@@ -15,37 +16,32 @@ func StandardLogger() *Logger { ...@@ -15,37 +16,32 @@ func StandardLogger() *Logger {
// SetOutput sets the standard logger output. // SetOutput sets the standard logger output.
func SetOutput(out io.Writer) { func SetOutput(out io.Writer) {
std.mu.Lock() std.SetOutput(out)
defer std.mu.Unlock()
std.Out = out
} }
// SetFormatter sets the standard logger formatter. // SetFormatter sets the standard logger formatter.
func SetFormatter(formatter Formatter) { func SetFormatter(formatter Formatter) {
std.mu.Lock() std.SetFormatter(formatter)
defer std.mu.Unlock()
std.Formatter = formatter
} }
// SetLevel sets the standard logger level. // SetLevel sets the standard logger level.
func SetLevel(level Level) { func SetLevel(level Level) {
std.mu.Lock() std.SetLevel(level)
defer std.mu.Unlock()
std.setLevel(level)
} }
// GetLevel returns the standard logger level. // GetLevel returns the standard logger level.
func GetLevel() Level { func GetLevel() Level {
std.mu.Lock() return std.GetLevel()
defer std.mu.Unlock() }
return std.level()
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
func IsLevelEnabled(level Level) bool {
return std.IsLevelEnabled(level)
} }
// AddHook adds a hook to the standard logger hooks. // AddHook adds a hook to the standard logger hooks.
func AddHook(hook Hook) { func AddHook(hook Hook) {
std.mu.Lock() std.AddHook(hook)
defer std.mu.Unlock()
std.Hooks.Add(hook)
} }
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. // WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
...@@ -72,6 +68,15 @@ func WithFields(fields Fields) *Entry { ...@@ -72,6 +68,15 @@ func WithFields(fields Fields) *Entry {
return std.WithFields(fields) return std.WithFields(fields)
} }
// WithTime creats an entry from the standard logger and overrides the time of
// logs generated with it.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithTime(t time.Time) *Entry {
return std.WithTime(t)
}
// Debug logs a message at level Debug on the standard logger. // Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) { func Debug(args ...interface{}) {
std.Debug(args...) std.Debug(args...)
...@@ -107,7 +112,7 @@ func Panic(args ...interface{}) { ...@@ -107,7 +112,7 @@ func Panic(args ...interface{}) {
std.Panic(args...) std.Panic(args...)
} }
// Fatal logs a message at level Fatal on the standard logger. // Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatal(args ...interface{}) { func Fatal(args ...interface{}) {
std.Fatal(args...) std.Fatal(args...)
} }
...@@ -147,7 +152,7 @@ func Panicf(format string, args ...interface{}) { ...@@ -147,7 +152,7 @@ func Panicf(format string, args ...interface{}) {
std.Panicf(format, args...) std.Panicf(format, args...)
} }
// Fatalf logs a message at level Fatal on the standard logger. // Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalf(format string, args ...interface{}) { func Fatalf(format string, args ...interface{}) {
std.Fatalf(format, args...) std.Fatalf(format, args...)
} }
...@@ -187,7 +192,7 @@ func Panicln(args ...interface{}) { ...@@ -187,7 +192,7 @@ func Panicln(args ...interface{}) {
std.Panicln(args...) std.Panicln(args...)
} }
// Fatalln logs a message at level Fatal on the standard logger. // Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalln(args ...interface{}) { func Fatalln(args ...interface{}) {
std.Fatalln(args...) std.Fatalln(args...)
} }
...@@ -2,7 +2,7 @@ package logrus ...@@ -2,7 +2,7 @@ package logrus
import "time" import "time"
const DefaultTimestampFormat = time.RFC3339 const defaultTimestampFormat = time.RFC3339
// The Formatter interface is used to implement a custom Formatter. It takes an // The Formatter interface is used to implement a custom Formatter. It takes an
// `Entry`. It exposes all the fields, including the default ones: // `Entry`. It exposes all the fields, including the default ones:
...@@ -30,16 +30,22 @@ type Formatter interface { ...@@ -30,16 +30,22 @@ type Formatter interface {
// //
// It's not exported because it's still using Data in an opinionated way. It's to // It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters. // avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields) { func prefixFieldClashes(data Fields, fieldMap FieldMap) {
if t, ok := data["time"]; ok { timeKey := fieldMap.resolve(FieldKeyTime)
data["fields.time"] = t if t, ok := data[timeKey]; ok {
data["fields."+timeKey] = t
delete(data, timeKey)
} }
if m, ok := data["msg"]; ok { msgKey := fieldMap.resolve(FieldKeyMsg)
data["fields.msg"] = m if m, ok := data[msgKey]; ok {
data["fields."+msgKey] = m
delete(data, msgKey)
} }
if l, ok := data["level"]; ok { levelKey := fieldMap.resolve(FieldKeyLevel)
data["fields.level"] = l if l, ok := data[levelKey]; ok {
data["fields."+levelKey] = l
delete(data, levelKey)
} }
} }
package logrus package logrus
import ( import (
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
) )
type fieldKey string type fieldKey string
// FieldMap allows customization of the key names for default fields.
type FieldMap map[fieldKey]string type FieldMap map[fieldKey]string
// Default key names for the default fields
const ( const (
FieldKeyMsg = "msg" FieldKeyMsg = "msg"
FieldKeyLevel = "level" FieldKeyLevel = "level"
...@@ -22,6 +26,7 @@ func (f FieldMap) resolve(key fieldKey) string { ...@@ -22,6 +26,7 @@ func (f FieldMap) resolve(key fieldKey) string {
return string(key) return string(key)
} }
// JSONFormatter formats logs into parsable json
type JSONFormatter struct { type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps. // TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string TimestampFormat string
...@@ -29,35 +34,49 @@ type JSONFormatter struct { ...@@ -29,35 +34,49 @@ type JSONFormatter struct {
// DisableTimestamp allows disabling automatic timestamps in output // DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields. // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
DataKey string
// FieldMap allows users to customize the names of keys for default fields.
// As an example: // As an example:
// formatter := &JSONFormatter{ // formatter := &JSONFormatter{
// FieldMap: FieldMap{ // FieldMap: FieldMap{
// FieldKeyTime: "@timestamp", // FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level", // FieldKeyLevel: "@level",
// FieldKeyLevel: "@message", // FieldKeyMsg: "@message",
// }, // },
// } // }
FieldMap FieldMap FieldMap FieldMap
// PrettyPrint will indent all json logs
PrettyPrint bool
} }
// Format renders a single log entry
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data := make(Fields, len(entry.Data)+3) data := make(Fields, len(entry.Data)+3)
for k, v := range entry.Data { for k, v := range entry.Data {
switch v := v.(type) { switch v := v.(type) {
case error: case error:
// Otherwise errors are ignored by `encoding/json` // Otherwise errors are ignored by `encoding/json`
// https://github.com/Sirupsen/logrus/issues/137 // https://github.com/sirupsen/logrus/issues/137
data[k] = v.Error() data[k] = v.Error()
default: default:
data[k] = v data[k] = v
} }
} }
prefixFieldClashes(data)
if f.DataKey != "" {
newData := make(Fields, 4)
newData[f.DataKey] = data
data = newData
}
prefixFieldClashes(data, f.FieldMap)
timestampFormat := f.TimestampFormat timestampFormat := f.TimestampFormat
if timestampFormat == "" { if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat timestampFormat = defaultTimestampFormat
} }
if !f.DisableTimestamp { if !f.DisableTimestamp {
...@@ -66,9 +85,20 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { ...@@ -66,9 +85,20 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
serialized, err := json.Marshal(data) var b *bytes.Buffer
if err != nil { if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
encoder := json.NewEncoder(b)
if f.PrettyPrint {
encoder.SetIndent("", " ")
}
if err := encoder.Encode(data); err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
} }
return append(serialized, '\n'), nil
return b.Bytes(), nil
} }
...@@ -5,12 +5,13 @@ import ( ...@@ -5,12 +5,13 @@ import (
"os" "os"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time"
) )
type Logger struct { type Logger struct {
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
// file, or leave it default which is `os.Stderr`. You can also set this to // file, or leave it default which is `os.Stderr`. You can also set this to
// something more adventorous, such as logging to Kafka. // something more adventurous, such as logging to Kafka.
Out io.Writer Out io.Writer
// Hooks for the logger instance. These allow firing events based on logging // Hooks for the logger instance. These allow firing events based on logging
// levels and log entries. For example, to send errors to an error tracking // levels and log entries. For example, to send errors to an error tracking
...@@ -25,7 +26,7 @@ type Logger struct { ...@@ -25,7 +26,7 @@ type Logger struct {
Formatter Formatter Formatter Formatter
// The logging level the logger should log at. This is typically (and defaults // The logging level the logger should log at. This is typically (and defaults
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
// logged. `logrus.Debug` is useful in // logged.
Level Level Level Level
// Used to sync writing to the log. Locking is enabled by Default // Used to sync writing to the log. Locking is enabled by Default
mu MutexWrap mu MutexWrap
...@@ -84,11 +85,12 @@ func (logger *Logger) newEntry() *Entry { ...@@ -84,11 +85,12 @@ func (logger *Logger) newEntry() *Entry {
} }
func (logger *Logger) releaseEntry(entry *Entry) { func (logger *Logger) releaseEntry(entry *Entry) {
entry.Data = map[string]interface{}{}
logger.entryPool.Put(entry) logger.entryPool.Put(entry)
} }
// Adds a field to the log entry, note that it doesn't log until you call // Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. // Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`. // If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry { func (logger *Logger) WithField(key string, value interface{}) *Entry {
entry := logger.newEntry() entry := logger.newEntry()
...@@ -112,8 +114,15 @@ func (logger *Logger) WithError(err error) *Entry { ...@@ -112,8 +114,15 @@ func (logger *Logger) WithError(err error) *Entry {
return entry.WithError(err) return entry.WithError(err)
} }
// Overrides the time of the log entry.
func (logger *Logger) WithTime(t time.Time) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithTime(t)
}
func (logger *Logger) Debugf(format string, args ...interface{}) { func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.level() >= DebugLevel { if logger.IsLevelEnabled(DebugLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debugf(format, args...) entry.Debugf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -121,7 +130,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) { ...@@ -121,7 +130,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) {
} }
func (logger *Logger) Infof(format string, args ...interface{}) { func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.level() >= InfoLevel { if logger.IsLevelEnabled(InfoLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Infof(format, args...) entry.Infof(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -135,7 +144,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) { ...@@ -135,7 +144,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
} }
func (logger *Logger) Warnf(format string, args ...interface{}) { func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.level() >= WarnLevel { if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnf(format, args...) entry.Warnf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -143,7 +152,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) { ...@@ -143,7 +152,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) {
} }
func (logger *Logger) Warningf(format string, args ...interface{}) { func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.level() >= WarnLevel { if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnf(format, args...) entry.Warnf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -151,7 +160,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) { ...@@ -151,7 +160,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) {
} }
func (logger *Logger) Errorf(format string, args ...interface{}) { func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.level() >= ErrorLevel { if logger.IsLevelEnabled(ErrorLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Errorf(format, args...) entry.Errorf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -159,7 +168,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) { ...@@ -159,7 +168,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) {
} }
func (logger *Logger) Fatalf(format string, args ...interface{}) { func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.level() >= FatalLevel { if logger.IsLevelEnabled(FatalLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatalf(format, args...) entry.Fatalf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -168,7 +177,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) { ...@@ -168,7 +177,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
} }
func (logger *Logger) Panicf(format string, args ...interface{}) { func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.level() >= PanicLevel { if logger.IsLevelEnabled(PanicLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panicf(format, args...) entry.Panicf(format, args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -176,7 +185,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) { ...@@ -176,7 +185,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
} }
func (logger *Logger) Debug(args ...interface{}) { func (logger *Logger) Debug(args ...interface{}) {
if logger.level() >= DebugLevel { if logger.IsLevelEnabled(DebugLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debug(args...) entry.Debug(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -184,7 +193,7 @@ func (logger *Logger) Debug(args ...interface{}) { ...@@ -184,7 +193,7 @@ func (logger *Logger) Debug(args ...interface{}) {
} }
func (logger *Logger) Info(args ...interface{}) { func (logger *Logger) Info(args ...interface{}) {
if logger.level() >= InfoLevel { if logger.IsLevelEnabled(InfoLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Info(args...) entry.Info(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -198,7 +207,7 @@ func (logger *Logger) Print(args ...interface{}) { ...@@ -198,7 +207,7 @@ func (logger *Logger) Print(args ...interface{}) {
} }
func (logger *Logger) Warn(args ...interface{}) { func (logger *Logger) Warn(args ...interface{}) {
if logger.level() >= WarnLevel { if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warn(args...) entry.Warn(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -206,7 +215,7 @@ func (logger *Logger) Warn(args ...interface{}) { ...@@ -206,7 +215,7 @@ func (logger *Logger) Warn(args ...interface{}) {
} }
func (logger *Logger) Warning(args ...interface{}) { func (logger *Logger) Warning(args ...interface{}) {
if logger.level() >= WarnLevel { if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warn(args...) entry.Warn(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -214,7 +223,7 @@ func (logger *Logger) Warning(args ...interface{}) { ...@@ -214,7 +223,7 @@ func (logger *Logger) Warning(args ...interface{}) {
} }
func (logger *Logger) Error(args ...interface{}) { func (logger *Logger) Error(args ...interface{}) {
if logger.level() >= ErrorLevel { if logger.IsLevelEnabled(ErrorLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Error(args...) entry.Error(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -222,7 +231,7 @@ func (logger *Logger) Error(args ...interface{}) { ...@@ -222,7 +231,7 @@ func (logger *Logger) Error(args ...interface{}) {
} }
func (logger *Logger) Fatal(args ...interface{}) { func (logger *Logger) Fatal(args ...interface{}) {
if logger.level() >= FatalLevel { if logger.IsLevelEnabled(FatalLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatal(args...) entry.Fatal(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -231,7 +240,7 @@ func (logger *Logger) Fatal(args ...interface{}) { ...@@ -231,7 +240,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
} }
func (logger *Logger) Panic(args ...interface{}) { func (logger *Logger) Panic(args ...interface{}) {
if logger.level() >= PanicLevel { if logger.IsLevelEnabled(PanicLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panic(args...) entry.Panic(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -239,7 +248,7 @@ func (logger *Logger) Panic(args ...interface{}) { ...@@ -239,7 +248,7 @@ func (logger *Logger) Panic(args ...interface{}) {
} }
func (logger *Logger) Debugln(args ...interface{}) { func (logger *Logger) Debugln(args ...interface{}) {
if logger.level() >= DebugLevel { if logger.IsLevelEnabled(DebugLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Debugln(args...) entry.Debugln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -247,7 +256,7 @@ func (logger *Logger) Debugln(args ...interface{}) { ...@@ -247,7 +256,7 @@ func (logger *Logger) Debugln(args ...interface{}) {
} }
func (logger *Logger) Infoln(args ...interface{}) { func (logger *Logger) Infoln(args ...interface{}) {
if logger.level() >= InfoLevel { if logger.IsLevelEnabled(InfoLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Infoln(args...) entry.Infoln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -261,7 +270,7 @@ func (logger *Logger) Println(args ...interface{}) { ...@@ -261,7 +270,7 @@ func (logger *Logger) Println(args ...interface{}) {
} }
func (logger *Logger) Warnln(args ...interface{}) { func (logger *Logger) Warnln(args ...interface{}) {
if logger.level() >= WarnLevel { if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnln(args...) entry.Warnln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -269,7 +278,7 @@ func (logger *Logger) Warnln(args ...interface{}) { ...@@ -269,7 +278,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
} }
func (logger *Logger) Warningln(args ...interface{}) { func (logger *Logger) Warningln(args ...interface{}) {
if logger.level() >= WarnLevel { if logger.IsLevelEnabled(WarnLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Warnln(args...) entry.Warnln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -277,7 +286,7 @@ func (logger *Logger) Warningln(args ...interface{}) { ...@@ -277,7 +286,7 @@ func (logger *Logger) Warningln(args ...interface{}) {
} }
func (logger *Logger) Errorln(args ...interface{}) { func (logger *Logger) Errorln(args ...interface{}) {
if logger.level() >= ErrorLevel { if logger.IsLevelEnabled(ErrorLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Errorln(args...) entry.Errorln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -285,7 +294,7 @@ func (logger *Logger) Errorln(args ...interface{}) { ...@@ -285,7 +294,7 @@ func (logger *Logger) Errorln(args ...interface{}) {
} }
func (logger *Logger) Fatalln(args ...interface{}) { func (logger *Logger) Fatalln(args ...interface{}) {
if logger.level() >= FatalLevel { if logger.IsLevelEnabled(FatalLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Fatalln(args...) entry.Fatalln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -294,7 +303,7 @@ func (logger *Logger) Fatalln(args ...interface{}) { ...@@ -294,7 +303,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
} }
func (logger *Logger) Panicln(args ...interface{}) { func (logger *Logger) Panicln(args ...interface{}) {
if logger.level() >= PanicLevel { if logger.IsLevelEnabled(PanicLevel) {
entry := logger.newEntry() entry := logger.newEntry()
entry.Panicln(args...) entry.Panicln(args...)
logger.releaseEntry(entry) logger.releaseEntry(entry)
...@@ -312,6 +321,47 @@ func (logger *Logger) level() Level { ...@@ -312,6 +321,47 @@ func (logger *Logger) level() Level {
return Level(atomic.LoadUint32((*uint32)(&logger.Level))) return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
} }
func (logger *Logger) setLevel(level Level) { // SetLevel sets the logger level.
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
} }
// GetLevel returns the logger level.
func (logger *Logger) GetLevel() Level {
return logger.level()
}
// AddHook adds a hook to the logger hooks.
func (logger *Logger) AddHook(hook Hook) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Hooks.Add(hook)
}
// IsLevelEnabled checks if the log level of the logger is greater than the level param
func (logger *Logger) IsLevelEnabled(level Level) bool {
return logger.level() >= level
}
// SetFormatter sets the logger formatter.
func (logger *Logger) SetFormatter(formatter Formatter) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Formatter = formatter
}
// SetOutput sets the logger output.
func (logger *Logger) SetOutput(output io.Writer) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Out = output
}
// ReplaceHooks replaces the logger hooks and returns the old ones
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
logger.mu.Lock()
oldHooks := logger.Hooks
logger.Hooks = hooks
logger.mu.Unlock()
return oldHooks
}
...@@ -140,4 +140,11 @@ type FieldLogger interface { ...@@ -140,4 +140,11 @@ type FieldLogger interface {
Errorln(args ...interface{}) Errorln(args ...interface{})
Fatalln(args ...interface{}) Fatalln(args ...interface{})
Panicln(args ...interface{}) Panicln(args ...interface{})
// IsDebugEnabled() bool
// IsInfoEnabled() bool
// IsWarnEnabled() bool
// IsErrorEnabled() bool
// IsFatalEnabled() bool
// IsPanicEnabled() bool
} }
// +build appengine
package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
return true
}
// +build darwin freebsd openbsd netbsd dragonfly // +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine // +build !appengine,!js
package logrus package logrus
import "syscall" import "golang.org/x/sys/unix"
const ioctlReadTermios = syscall.TIOCGETA const ioctlReadTermios = unix.TIOCGETA
type Termios syscall.Termios type Termios unix.Termios
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !appengine // +build !appengine,!js
package logrus package logrus
import "syscall" import "golang.org/x/sys/unix"
const ioctlReadTermios = syscall.TCGETS const ioctlReadTermios = unix.TCGETS
type Termios syscall.Termios type Termios unix.Termios
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
var termios Termios
switch v := f.(type) {
case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
}
// +build solaris,!appengine
package logrus
import (
"io"
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
}
// Based on ssh/terminal:
// Copyright 2011 The Go Authors. 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,!appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}
...@@ -3,6 +3,7 @@ package logrus ...@@ -3,6 +3,7 @@ package logrus
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"os"
"sort" "sort"
"strings" "strings"
"sync" "sync"
...@@ -14,18 +15,20 @@ const ( ...@@ -14,18 +15,20 @@ const (
red = 31 red = 31
green = 32 green = 32
yellow = 33 yellow = 33
blue = 34 blue = 36
gray = 37 gray = 37
) )
var ( var (
baseTimestamp time.Time baseTimestamp time.Time
emptyFieldMap FieldMap
) )
func init() { func init() {
baseTimestamp = time.Now() baseTimestamp = time.Now()
} }
// TextFormatter formats logs into text
type TextFormatter struct { type TextFormatter struct {
// Set to true to bypass checking for a TTY before outputting colors. // Set to true to bypass checking for a TTY before outputting colors.
ForceColors bool ForceColors bool
...@@ -33,6 +36,9 @@ type TextFormatter struct { ...@@ -33,6 +36,9 @@ type TextFormatter struct {
// Force disabling colors. // Force disabling colors.
DisableColors bool DisableColors bool
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
EnvironmentOverrideColors bool
// Disable timestamp logging. useful when output is redirected to logging // Disable timestamp logging. useful when output is redirected to logging
// system that already adds timestamps. // system that already adds timestamps.
DisableTimestamp bool DisableTimestamp bool
...@@ -49,30 +55,53 @@ type TextFormatter struct { ...@@ -49,30 +55,53 @@ type TextFormatter struct {
// be desired. // be desired.
DisableSorting bool DisableSorting bool
// Disables the truncation of the level text to 4 characters.
DisableLevelTruncation bool
// QuoteEmptyFields will wrap empty fields in quotes if true // QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal // Whether the logger's out is to a terminal
isTerminal bool isTerminal bool
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &TextFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message"}}
FieldMap FieldMap
sync.Once sync.Once
} }
func (f *TextFormatter) init(entry *Entry) { func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil { if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out) f.isTerminal = checkIfTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) isColored() bool {
isColored := f.ForceColors || f.isTerminal
if f.EnvironmentOverrideColors {
if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" {
isColored = true
} else if ok && force == "0" {
isColored = false
} else if os.Getenv("CLICOLOR") == "0" {
isColored = false
}
} }
return isColored && !f.DisableColors
} }
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer prefixFieldClashes(entry.Data, f.FieldMap)
keys := make([]string, 0, len(entry.Data)) keys := make([]string, 0, len(entry.Data))
for k := range entry.Data { for k := range entry.Data {
keys = append(keys, k) keys = append(keys, k)
...@@ -81,31 +110,29 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { ...@@ -81,31 +110,29 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if !f.DisableSorting { if !f.DisableSorting {
sort.Strings(keys) sort.Strings(keys)
} }
var b *bytes.Buffer
if entry.Buffer != nil { if entry.Buffer != nil {
b = entry.Buffer b = entry.Buffer
} else { } else {
b = &bytes.Buffer{} b = &bytes.Buffer{}
} }
prefixFieldClashes(entry.Data)
f.Do(func() { f.init(entry) }) f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
timestampFormat := f.TimestampFormat timestampFormat := f.TimestampFormat
if timestampFormat == "" { if timestampFormat == "" {
timestampFormat = DefaultTimestampFormat timestampFormat = defaultTimestampFormat
} }
if isColored { if f.isColored() {
f.printColored(b, entry, keys, timestampFormat) f.printColored(b, entry, keys, timestampFormat)
} else { } else {
if !f.DisableTimestamp { if !f.DisableTimestamp {
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyTime), entry.Time.Format(timestampFormat))
} }
f.appendKeyValue(b, "level", entry.Level.String()) f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyLevel), entry.Level.String())
if entry.Message != "" { if entry.Message != "" {
f.appendKeyValue(b, "msg", entry.Message) f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyMsg), entry.Message)
} }
for _, key := range keys { for _, key := range keys {
f.appendKeyValue(b, key, entry.Data[key]) f.appendKeyValue(b, key, entry.Data[key])
...@@ -129,7 +156,14 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin ...@@ -129,7 +156,14 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelColor = blue levelColor = blue
} }
levelText := strings.ToUpper(entry.Level.String())[0:4] levelText := strings.ToUpper(entry.Level.String())
if !f.DisableLevelTruncation {
levelText = levelText[0:4]
}
// Remove a single newline if it already exists in the message to keep
// the behavior of logrus text_formatter the same as the stdlib log package
entry.Message = strings.TrimSuffix(entry.Message, "\n")
if f.DisableTimestamp { if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
...@@ -153,7 +187,7 @@ func (f *TextFormatter) needsQuoting(text string) bool { ...@@ -153,7 +187,7 @@ func (f *TextFormatter) needsQuoting(text string) bool {
if !((ch >= 'a' && ch <= 'z') || if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || (ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.') { ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
return true return true
} }
} }
...@@ -161,29 +195,23 @@ func (f *TextFormatter) needsQuoting(text string) bool { ...@@ -161,29 +195,23 @@ func (f *TextFormatter) needsQuoting(text string) bool {
} }
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
if b.Len() > 0 {
b.WriteByte(' ')
}
b.WriteString(key) b.WriteString(key)
b.WriteByte('=') b.WriteByte('=')
f.appendValue(b, value) f.appendValue(b, value)
b.WriteByte(' ')
} }
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) { stringVal, ok := value.(string)
case string: if !ok {
if !f.needsQuoting(value) { stringVal = fmt.Sprint(value)
b.WriteString(value) }
} else {
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter) if !f.needsQuoting(stringVal) {
} b.WriteString(stringVal)
case error: } else {
errmsg := value.Error() b.WriteString(fmt.Sprintf("%q", stringVal))
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprint(b, value)
} }
} }
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"time" "time"
"unicode/utf16" "unicode/utf16"
"unicode/utf8" "unicode/utf8"
"unsafe"
"github.com/tidwall/match" "github.com/tidwall/match"
) )
...@@ -78,7 +77,20 @@ func (t Result) String() string { ...@@ -78,7 +77,20 @@ func (t Result) String() string {
case False: case False:
return "false" return "false"
case Number: case Number:
return strconv.FormatFloat(t.Num, 'f', -1, 64) if len(t.Raw) == 0 {
// calculated result
return strconv.FormatFloat(t.Num, 'f', -1, 64)
}
var i int
if t.Raw[0] == '-' {
i++
}
for ; i < len(t.Raw); i++ {
if t.Raw[i] < '0' || t.Raw[i] > '9' {
return strconv.FormatFloat(t.Num, 'f', -1, 64)
}
}
return t.Raw
case String: case String:
return t.Str return t.Str
case JSON: case JSON:
...@@ -345,24 +357,30 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { ...@@ -345,24 +357,30 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' { if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
value.Type = Number value.Type = Number
value.Raw, value.Num = tonum(json[i:]) value.Raw, value.Num = tonum(json[i:])
value.Str = ""
} else { } else {
continue continue
} }
case '{', '[': case '{', '[':
value.Type = JSON value.Type = JSON
value.Raw = squash(json[i:]) value.Raw = squash(json[i:])
value.Str, value.Num = "", 0
case 'n': case 'n':
value.Type = Null value.Type = Null
value.Raw = tolit(json[i:]) value.Raw = tolit(json[i:])
value.Str, value.Num = "", 0
case 't': case 't':
value.Type = True value.Type = True
value.Raw = tolit(json[i:]) value.Raw = tolit(json[i:])
value.Str, value.Num = "", 0
case 'f': case 'f':
value.Type = False value.Type = False
value.Raw = tolit(json[i:]) value.Raw = tolit(json[i:])
value.Str, value.Num = "", 0
case '"': case '"':
value.Type = String value.Type = String
value.Raw, value.Str = tostr(json[i:]) value.Raw, value.Str = tostr(json[i:])
value.Num = 0
} }
i += len(value.Raw) - 1 i += len(value.Raw) - 1
...@@ -371,9 +389,13 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { ...@@ -371,9 +389,13 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) {
key = value key = value
} else { } else {
if valueize { if valueize {
r.oi[key.Str] = value.Value() if _, ok := r.oi[key.Str]; !ok {
r.oi[key.Str] = value.Value()
}
} else { } else {
r.o[key.Str] = value if _, ok := r.o[key.Str]; !ok {
r.o[key.Str] = value
}
} }
} }
count++ count++
...@@ -1289,7 +1311,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { ...@@ -1289,7 +1311,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
if rp.alogok { if rp.alogok {
break break
} }
c.value.Raw = val c.value.Raw = ""
c.value.Type = Number c.value.Type = Number
c.value.Num = float64(h - 1) c.value.Num = float64(h - 1)
c.calcd = true c.calcd = true
...@@ -1385,64 +1407,14 @@ func Get(json, path string) Result { ...@@ -1385,64 +1407,14 @@ func Get(json, path string) Result {
} }
} }
} }
if len(c.value.Raw) > 0 && !c.calcd { fillIndex(json, c)
jhdr := *(*reflect.StringHeader)(unsafe.Pointer(&json))
rhdr := *(*reflect.StringHeader)(unsafe.Pointer(&(c.value.Raw)))
c.value.Index = int(rhdr.Data - jhdr.Data)
if c.value.Index < 0 || c.value.Index >= len(json) {
c.value.Index = 0
}
}
return c.value return c.value
} }
func fromBytesGet(result Result) Result {
// safely get the string headers
rawhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Raw))
strhi := *(*reflect.StringHeader)(unsafe.Pointer(&result.Str))
// create byte slice headers
rawh := reflect.SliceHeader{Data: rawhi.Data, Len: rawhi.Len}
strh := reflect.SliceHeader{Data: strhi.Data, Len: strhi.Len}
if strh.Data == 0 {
// str is nil
if rawh.Data == 0 {
// raw is nil
result.Raw = ""
} else {
// raw has data, safely copy the slice header to a string
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
}
result.Str = ""
} else if rawh.Data == 0 {
// raw is nil
result.Raw = ""
// str has data, safely copy the slice header to a string
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
} else if strh.Data >= rawh.Data &&
int(strh.Data)+strh.Len <= int(rawh.Data)+rawh.Len {
// Str is a substring of Raw.
start := int(strh.Data - rawh.Data)
// safely copy the raw slice header
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
// substring the raw
result.Str = result.Raw[start : start+strh.Len]
} else {
// safely copy both the raw and str slice headers to strings
result.Raw = string(*(*[]byte)(unsafe.Pointer(&rawh)))
result.Str = string(*(*[]byte)(unsafe.Pointer(&strh)))
}
return result
}
// GetBytes searches json for the specified path. // GetBytes searches json for the specified path.
// If working with bytes, this method preferred over Get(string(data), path) // If working with bytes, this method preferred over Get(string(data), path)
func GetBytes(json []byte, path string) Result { func GetBytes(json []byte, path string) Result {
var result Result return getBytes(json, path)
if json != nil {
// unsafe cast to string
result = Get(*(*string)(unsafe.Pointer(&json)), path)
result = fromBytesGet(result)
}
return result
} }
// runeit returns the rune from the the \uXXXX // runeit returns the rune from the the \uXXXX
...@@ -1865,8 +1837,14 @@ func validobject(data []byte, i int) (outi int, ok bool) { ...@@ -1865,8 +1837,14 @@ func validobject(data []byte, i int) (outi int, ok bool) {
if data[i] == '}' { if data[i] == '}' {
return i + 1, true return i + 1, true
} }
i++
for ; i < len(data); i++ { for ; i < len(data); i++ {
if data[i] == '"' { switch data[i] {
default:
return i, false
case ' ', '\t', '\n', '\r':
continue
case '"':
goto key goto key
} }
} }
...@@ -2058,6 +2036,20 @@ func Valid(json string) bool { ...@@ -2058,6 +2036,20 @@ func Valid(json string) bool {
return ok return ok
} }
// ValidBytes returns true if the input is valid json.
//
// if !gjson.Valid(json) {
// return errors.New("invalid json")
// }
// value := gjson.Get(json, "name.last")
//
// If working with bytes, this method preferred over Valid(string(data))
//
func ValidBytes(json []byte) bool {
_, ok := validpayload(json, 0)
return ok
}
func parseUint(s string) (n uint64, ok bool) { func parseUint(s string) (n uint64, ok bool) {
var i int var i int
if i == len(s) { if i == len(s) {
......
此差异已折叠。
#!/usr/bin/env bash
p=github.com/ziutek/mymysql
go $* $p/mysql $p/native $p/thrsafe $p/autorc $p/godrv
// Package mymysql provides MySQL client API and database/sql driver.
//
// It can be used as a library or as a database/sql driver.
//
// Using as a library
//
// Import native or thrsafe engine. Optionally import autorc for autoreconnect connections.
//
// import (
// "github.com/ziutek/mymysql/mysql"
// _ "github.com/ziutek/mymysql/thrsafe" // OR native
// // _ "github.com/ziutek/mymysql/native"
// "github.com/ziutek/mymysql/autorc" // for autoreconnect
// )
//
//
//
// Using as a Go sql driver
//
// Import Go standard sql package and godrv driver.
//
// import (
// "database/sql"
// _ "github.com/ziutek/mymysql/godrv"
// )
//
//
//
package mymysql
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册