diff --git a/.travis.yml b/.travis.yml index 3a3a6f66..92e53577 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ install: - go get github.com/casbin/casbin - go get github.com/elazarl/go-bindata-assetfs - go get github.com/OwnLocal/goes + - go get github.com/shiena/ansicolor - go get -u honnef.co/go/tools/cmd/staticcheck - go get -u github.com/mdempsky/unconvert - go get -u github.com/gordonklaus/ineffassign diff --git a/app.go b/app.go index 32ff159d..d9e85e9b 100644 --- a/app.go +++ b/app.go @@ -176,7 +176,7 @@ func (app *App) Run(mws ...MiddleWare) { if BConfig.Listen.HTTPSPort != 0 { app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort) } else if BConfig.Listen.EnableHTTP { - BeeLogger.Info("Start https server error, conflict with http. Please reset https port") + logs.Info("Start https server error, conflict with http. Please reset https port") return } logs.Info("https server Running on https://%s", app.Server.Addr) @@ -192,7 +192,7 @@ func (app *App) Run(mws ...MiddleWare) { pool := x509.NewCertPool() data, err := ioutil.ReadFile(BConfig.Listen.TrustCaFile) if err != nil { - BeeLogger.Info("MutualHTTPS should provide TrustCaFile") + logs.Info("MutualHTTPS should provide TrustCaFile") return } pool.AppendCertsFromPEM(data) diff --git a/log.go b/log.go deleted file mode 100644 index e9412f92..00000000 --- a/log.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package beego - -import ( - "strings" - - "github.com/astaxie/beego/logs" -) - -// Log levels to control the logging output. -const ( - LevelEmergency = iota - LevelAlert - LevelCritical - LevelError - LevelWarning - LevelNotice - LevelInformational - LevelDebug -) - -// BeeLogger references the used application logger. -var BeeLogger = logs.GetBeeLogger() - -// SetLevel sets the global log level used by the simple logger. -func SetLevel(l int) { - logs.SetLevel(l) -} - -// SetLogFuncCall set the CallDepth, default is 3 -func SetLogFuncCall(b bool) { - logs.SetLogFuncCall(b) -} - -// SetLogger sets a new logger. -func SetLogger(adaptername string, config string) error { - return logs.SetLogger(adaptername, config) -} - -// Emergency logs a message at emergency level. -func Emergency(v ...interface{}) { - logs.Emergency(generateFmtStr(len(v)), v...) -} - -// Alert logs a message at alert level. -func Alert(v ...interface{}) { - logs.Alert(generateFmtStr(len(v)), v...) -} - -// Critical logs a message at critical level. -func Critical(v ...interface{}) { - logs.Critical(generateFmtStr(len(v)), v...) -} - -// Error logs a message at error level. -func Error(v ...interface{}) { - logs.Error(generateFmtStr(len(v)), v...) -} - -// Warning logs a message at warning level. -func Warning(v ...interface{}) { - logs.Warning(generateFmtStr(len(v)), v...) -} - -// Warn compatibility alias for Warning() -func Warn(v ...interface{}) { - logs.Warn(generateFmtStr(len(v)), v...) -} - -// Notice logs a message at notice level. -func Notice(v ...interface{}) { - logs.Notice(generateFmtStr(len(v)), v...) -} - -// Informational logs a message at info level. -func Informational(v ...interface{}) { - logs.Informational(generateFmtStr(len(v)), v...) -} - -// Info compatibility alias for Warning() -func Info(v ...interface{}) { - logs.Info(generateFmtStr(len(v)), v...) -} - -// Debug logs a message at debug level. -func Debug(v ...interface{}) { - logs.Debug(generateFmtStr(len(v)), v...) -} - -// Trace logs a message at trace level. -// compatibility alias for Warning() -func Trace(v ...interface{}) { - logs.Trace(generateFmtStr(len(v)), v...) -} - -func generateFmtStr(n int) string { - return strings.Repeat("%v ", n) -} diff --git a/logs/color.go b/logs/color.go deleted file mode 100644 index 41d23638..00000000 --- a/logs/color.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !windows - -package logs - -import "io" - -type ansiColorWriter struct { - w io.Writer - mode outputMode -} - -func (cw *ansiColorWriter) Write(p []byte) (int, error) { - return cw.w.Write(p) -} diff --git a/logs/color_windows.go b/logs/color_windows.go deleted file mode 100644 index 4e28f188..00000000 --- a/logs/color_windows.go +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build windows - -package logs - -import ( - "bytes" - "io" - "strings" - "syscall" - "unsafe" -) - -type ( - csiState int - parseResult int -) - -const ( - outsideCsiCode csiState = iota - firstCsiCode - secondCsiCode -) - -const ( - noConsole parseResult = iota - changedColor - unknown -) - -type ansiColorWriter struct { - w io.Writer - mode outputMode - state csiState - paramStartBuf bytes.Buffer - paramBuf bytes.Buffer -} - -const ( - firstCsiChar byte = '\x1b' - secondeCsiChar byte = '[' - separatorChar byte = ';' - sgrCode byte = 'm' -) - -const ( - foregroundBlue = uint16(0x0001) - foregroundGreen = uint16(0x0002) - foregroundRed = uint16(0x0004) - foregroundIntensity = uint16(0x0008) - backgroundBlue = uint16(0x0010) - backgroundGreen = uint16(0x0020) - backgroundRed = uint16(0x0040) - backgroundIntensity = uint16(0x0080) - underscore = uint16(0x8000) - - foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity - backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity -) - -const ( - ansiReset = "0" - ansiIntensityOn = "1" - ansiIntensityOff = "21" - ansiUnderlineOn = "4" - ansiUnderlineOff = "24" - ansiBlinkOn = "5" - ansiBlinkOff = "25" - - ansiForegroundBlack = "30" - ansiForegroundRed = "31" - ansiForegroundGreen = "32" - ansiForegroundYellow = "33" - ansiForegroundBlue = "34" - ansiForegroundMagenta = "35" - ansiForegroundCyan = "36" - ansiForegroundWhite = "37" - ansiForegroundDefault = "39" - - ansiBackgroundBlack = "40" - ansiBackgroundRed = "41" - ansiBackgroundGreen = "42" - ansiBackgroundYellow = "43" - ansiBackgroundBlue = "44" - ansiBackgroundMagenta = "45" - ansiBackgroundCyan = "46" - ansiBackgroundWhite = "47" - ansiBackgroundDefault = "49" - - ansiLightForegroundGray = "90" - ansiLightForegroundRed = "91" - ansiLightForegroundGreen = "92" - ansiLightForegroundYellow = "93" - ansiLightForegroundBlue = "94" - ansiLightForegroundMagenta = "95" - ansiLightForegroundCyan = "96" - ansiLightForegroundWhite = "97" - - ansiLightBackgroundGray = "100" - ansiLightBackgroundRed = "101" - ansiLightBackgroundGreen = "102" - ansiLightBackgroundYellow = "103" - ansiLightBackgroundBlue = "104" - ansiLightBackgroundMagenta = "105" - ansiLightBackgroundCyan = "106" - ansiLightBackgroundWhite = "107" -) - -type drawType int - -const ( - foreground drawType = iota - background -) - -type winColor struct { - code uint16 - drawType drawType -} - -var colorMap = map[string]winColor{ - ansiForegroundBlack: {0, foreground}, - ansiForegroundRed: {foregroundRed, foreground}, - ansiForegroundGreen: {foregroundGreen, foreground}, - ansiForegroundYellow: {foregroundRed | foregroundGreen, foreground}, - ansiForegroundBlue: {foregroundBlue, foreground}, - ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground}, - ansiForegroundCyan: {foregroundGreen | foregroundBlue, foreground}, - ansiForegroundWhite: {foregroundRed | foregroundGreen | foregroundBlue, foreground}, - ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground}, - - ansiBackgroundBlack: {0, background}, - ansiBackgroundRed: {backgroundRed, background}, - ansiBackgroundGreen: {backgroundGreen, background}, - ansiBackgroundYellow: {backgroundRed | backgroundGreen, background}, - ansiBackgroundBlue: {backgroundBlue, background}, - ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background}, - ansiBackgroundCyan: {backgroundGreen | backgroundBlue, background}, - ansiBackgroundWhite: {backgroundRed | backgroundGreen | backgroundBlue, background}, - ansiBackgroundDefault: {0, background}, - - ansiLightForegroundGray: {foregroundIntensity, foreground}, - ansiLightForegroundRed: {foregroundIntensity | foregroundRed, foreground}, - ansiLightForegroundGreen: {foregroundIntensity | foregroundGreen, foreground}, - ansiLightForegroundYellow: {foregroundIntensity | foregroundRed | foregroundGreen, foreground}, - ansiLightForegroundBlue: {foregroundIntensity | foregroundBlue, foreground}, - ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground}, - ansiLightForegroundCyan: {foregroundIntensity | foregroundGreen | foregroundBlue, foreground}, - ansiLightForegroundWhite: {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground}, - - ansiLightBackgroundGray: {backgroundIntensity, background}, - ansiLightBackgroundRed: {backgroundIntensity | backgroundRed, background}, - ansiLightBackgroundGreen: {backgroundIntensity | backgroundGreen, background}, - ansiLightBackgroundYellow: {backgroundIntensity | backgroundRed | backgroundGreen, background}, - ansiLightBackgroundBlue: {backgroundIntensity | backgroundBlue, background}, - ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background}, - ansiLightBackgroundCyan: {backgroundIntensity | backgroundGreen | backgroundBlue, background}, - ansiLightBackgroundWhite: {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background}, -} - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - defaultAttr *textAttributes -) - -func init() { - screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout)) - if screenInfo != nil { - colorMap[ansiForegroundDefault] = winColor{ - screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue), - foreground, - } - colorMap[ansiBackgroundDefault] = winColor{ - screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue), - background, - } - defaultAttr = convertTextAttr(screenInfo.WAttributes) - } -} - -type coord struct { - X, Y int16 -} - -type smallRect struct { - Left, Top, Right, Bottom int16 -} - -type consoleScreenBufferInfo struct { - DwSize coord - DwCursorPosition coord - WAttributes uint16 - SrWindow smallRect - DwMaximumWindowSize coord -} - -func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo { - var csbi consoleScreenBufferInfo - ret, _, _ := procGetConsoleScreenBufferInfo.Call( - hConsoleOutput, - uintptr(unsafe.Pointer(&csbi))) - if ret == 0 { - return nil - } - return &csbi -} - -func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { - ret, _, _ := procSetConsoleTextAttribute.Call( - hConsoleOutput, - uintptr(wAttributes)) - return ret != 0 -} - -type textAttributes struct { - foregroundColor uint16 - backgroundColor uint16 - foregroundIntensity uint16 - backgroundIntensity uint16 - underscore uint16 - otherAttributes uint16 -} - -func convertTextAttr(winAttr uint16) *textAttributes { - fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue) - bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue) - fgIntensity := winAttr & foregroundIntensity - bgIntensity := winAttr & backgroundIntensity - underline := winAttr & underscore - otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore) - return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes} -} - -func convertWinAttr(textAttr *textAttributes) uint16 { - var winAttr uint16 - winAttr |= textAttr.foregroundColor - winAttr |= textAttr.backgroundColor - winAttr |= textAttr.foregroundIntensity - winAttr |= textAttr.backgroundIntensity - winAttr |= textAttr.underscore - winAttr |= textAttr.otherAttributes - return winAttr -} - -func changeColor(param []byte) parseResult { - screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout)) - if screenInfo == nil { - return noConsole - } - - winAttr := convertTextAttr(screenInfo.WAttributes) - strParam := string(param) - if len(strParam) <= 0 { - strParam = "0" - } - csiParam := strings.Split(strParam, string(separatorChar)) - for _, p := range csiParam { - c, ok := colorMap[p] - switch { - case !ok: - switch p { - case ansiReset: - winAttr.foregroundColor = defaultAttr.foregroundColor - winAttr.backgroundColor = defaultAttr.backgroundColor - winAttr.foregroundIntensity = defaultAttr.foregroundIntensity - winAttr.backgroundIntensity = defaultAttr.backgroundIntensity - winAttr.underscore = 0 - winAttr.otherAttributes = 0 - case ansiIntensityOn: - winAttr.foregroundIntensity = foregroundIntensity - case ansiIntensityOff: - winAttr.foregroundIntensity = 0 - case ansiUnderlineOn: - winAttr.underscore = underscore - case ansiUnderlineOff: - winAttr.underscore = 0 - case ansiBlinkOn: - winAttr.backgroundIntensity = backgroundIntensity - case ansiBlinkOff: - winAttr.backgroundIntensity = 0 - default: - // unknown code - } - case c.drawType == foreground: - winAttr.foregroundColor = c.code - case c.drawType == background: - winAttr.backgroundColor = c.code - } - } - winTextAttribute := convertWinAttr(winAttr) - setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute) - - return changedColor -} - -func parseEscapeSequence(command byte, param []byte) parseResult { - if defaultAttr == nil { - return noConsole - } - - switch command { - case sgrCode: - return changeColor(param) - default: - return unknown - } -} - -func (cw *ansiColorWriter) flushBuffer() (int, error) { - return cw.flushTo(cw.w) -} - -func (cw *ansiColorWriter) resetBuffer() (int, error) { - return cw.flushTo(nil) -} - -func (cw *ansiColorWriter) flushTo(w io.Writer) (int, error) { - var n1, n2 int - var err error - - startBytes := cw.paramStartBuf.Bytes() - cw.paramStartBuf.Reset() - if w != nil { - n1, err = cw.w.Write(startBytes) - if err != nil { - return n1, err - } - } else { - n1 = len(startBytes) - } - paramBytes := cw.paramBuf.Bytes() - cw.paramBuf.Reset() - if w != nil { - n2, err = cw.w.Write(paramBytes) - if err != nil { - return n1 + n2, err - } - } else { - n2 = len(paramBytes) - } - return n1 + n2, nil -} - -func isParameterChar(b byte) bool { - return ('0' <= b && b <= '9') || b == separatorChar -} - -func (cw *ansiColorWriter) Write(p []byte) (int, error) { - var r, nw, first, last int - if cw.mode != DiscardNonColorEscSeq { - cw.state = outsideCsiCode - cw.resetBuffer() - } - - var err error - for i, ch := range p { - switch cw.state { - case outsideCsiCode: - if ch == firstCsiChar { - cw.paramStartBuf.WriteByte(ch) - cw.state = firstCsiCode - } - case firstCsiCode: - switch ch { - case firstCsiChar: - cw.paramStartBuf.WriteByte(ch) - break - case secondeCsiChar: - cw.paramStartBuf.WriteByte(ch) - cw.state = secondCsiCode - last = i - 1 - default: - cw.resetBuffer() - cw.state = outsideCsiCode - } - case secondCsiCode: - if isParameterChar(ch) { - cw.paramBuf.WriteByte(ch) - } else { - nw, err = cw.w.Write(p[first:last]) - r += nw - if err != nil { - return r, err - } - first = i + 1 - result := parseEscapeSequence(ch, cw.paramBuf.Bytes()) - if result == noConsole || (cw.mode == OutputNonColorEscSeq && result == unknown) { - cw.paramBuf.WriteByte(ch) - nw, err := cw.flushBuffer() - if err != nil { - return r, err - } - r += nw - } else { - n, _ := cw.resetBuffer() - // Add one more to the size of the buffer for the last ch - r += n + 1 - } - - cw.state = outsideCsiCode - } - default: - cw.state = outsideCsiCode - } - } - - if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode { - nw, err = cw.w.Write(p[first:]) - r += nw - } - - return r, err -} diff --git a/logs/color_windows_test.go b/logs/color_windows_test.go deleted file mode 100644 index 5074841a..00000000 --- a/logs/color_windows_test.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build windows - -package logs - -import ( - "bytes" - "fmt" - "syscall" - "testing" -) - -var GetConsoleScreenBufferInfo = getConsoleScreenBufferInfo - -func ChangeColor(color uint16) { - setConsoleTextAttribute(uintptr(syscall.Stdout), color) -} - -func ResetColor() { - ChangeColor(uint16(0x0007)) -} - -func TestWritePlanText(t *testing.T) { - inner := bytes.NewBufferString("") - w := NewAnsiColorWriter(inner) - expected := "plain text" - fmt.Fprintf(w, expected) - actual := inner.String() - if actual != expected { - t.Errorf("Get %q, want %q", actual, expected) - } -} - -func TestWriteParseText(t *testing.T) { - inner := bytes.NewBufferString("") - w := NewAnsiColorWriter(inner) - - inputTail := "\x1b[0mtail text" - expectedTail := "tail text" - fmt.Fprintf(w, inputTail) - actualTail := inner.String() - inner.Reset() - if actualTail != expectedTail { - t.Errorf("Get %q, want %q", actualTail, expectedTail) - } - - inputHead := "head text\x1b[0m" - expectedHead := "head text" - fmt.Fprintf(w, inputHead) - actualHead := inner.String() - inner.Reset() - if actualHead != expectedHead { - t.Errorf("Get %q, want %q", actualHead, expectedHead) - } - - inputBothEnds := "both ends \x1b[0m text" - expectedBothEnds := "both ends text" - fmt.Fprintf(w, inputBothEnds) - actualBothEnds := inner.String() - inner.Reset() - if actualBothEnds != expectedBothEnds { - t.Errorf("Get %q, want %q", actualBothEnds, expectedBothEnds) - } - - inputManyEsc := "\x1b\x1b\x1b\x1b[0m many esc" - expectedManyEsc := "\x1b\x1b\x1b many esc" - fmt.Fprintf(w, inputManyEsc) - actualManyEsc := inner.String() - inner.Reset() - if actualManyEsc != expectedManyEsc { - t.Errorf("Get %q, want %q", actualManyEsc, expectedManyEsc) - } - - expectedSplit := "split text" - for _, ch := range "split \x1b[0m text" { - fmt.Fprintf(w, string(ch)) - } - actualSplit := inner.String() - inner.Reset() - if actualSplit != expectedSplit { - t.Errorf("Get %q, want %q", actualSplit, expectedSplit) - } -} - -type screenNotFoundError struct { - error -} - -func writeAnsiColor(expectedText, colorCode string) (actualText string, actualAttributes uint16, err error) { - inner := bytes.NewBufferString("") - w := NewAnsiColorWriter(inner) - fmt.Fprintf(w, "\x1b[%sm%s", colorCode, expectedText) - - actualText = inner.String() - screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout)) - if screenInfo != nil { - actualAttributes = screenInfo.WAttributes - } else { - err = &screenNotFoundError{} - } - return -} - -type testParam struct { - text string - attributes uint16 - ansiColor string -} - -func TestWriteAnsiColorText(t *testing.T) { - screenInfo := GetConsoleScreenBufferInfo(uintptr(syscall.Stdout)) - if screenInfo == nil { - t.Fatal("Could not get ConsoleScreenBufferInfo") - } - defer ChangeColor(screenInfo.WAttributes) - defaultFgColor := screenInfo.WAttributes & uint16(0x0007) - defaultBgColor := screenInfo.WAttributes & uint16(0x0070) - defaultFgIntensity := screenInfo.WAttributes & uint16(0x0008) - defaultBgIntensity := screenInfo.WAttributes & uint16(0x0080) - - fgParam := []testParam{ - {"foreground black ", uint16(0x0000 | 0x0000), "30"}, - {"foreground red ", uint16(0x0004 | 0x0000), "31"}, - {"foreground green ", uint16(0x0002 | 0x0000), "32"}, - {"foreground yellow ", uint16(0x0006 | 0x0000), "33"}, - {"foreground blue ", uint16(0x0001 | 0x0000), "34"}, - {"foreground magenta", uint16(0x0005 | 0x0000), "35"}, - {"foreground cyan ", uint16(0x0003 | 0x0000), "36"}, - {"foreground white ", uint16(0x0007 | 0x0000), "37"}, - {"foreground default", defaultFgColor | 0x0000, "39"}, - {"foreground light gray ", uint16(0x0000 | 0x0008 | 0x0000), "90"}, - {"foreground light red ", uint16(0x0004 | 0x0008 | 0x0000), "91"}, - {"foreground light green ", uint16(0x0002 | 0x0008 | 0x0000), "92"}, - {"foreground light yellow ", uint16(0x0006 | 0x0008 | 0x0000), "93"}, - {"foreground light blue ", uint16(0x0001 | 0x0008 | 0x0000), "94"}, - {"foreground light magenta", uint16(0x0005 | 0x0008 | 0x0000), "95"}, - {"foreground light cyan ", uint16(0x0003 | 0x0008 | 0x0000), "96"}, - {"foreground light white ", uint16(0x0007 | 0x0008 | 0x0000), "97"}, - } - - bgParam := []testParam{ - {"background black ", uint16(0x0007 | 0x0000), "40"}, - {"background red ", uint16(0x0007 | 0x0040), "41"}, - {"background green ", uint16(0x0007 | 0x0020), "42"}, - {"background yellow ", uint16(0x0007 | 0x0060), "43"}, - {"background blue ", uint16(0x0007 | 0x0010), "44"}, - {"background magenta", uint16(0x0007 | 0x0050), "45"}, - {"background cyan ", uint16(0x0007 | 0x0030), "46"}, - {"background white ", uint16(0x0007 | 0x0070), "47"}, - {"background default", uint16(0x0007) | defaultBgColor, "49"}, - {"background light gray ", uint16(0x0007 | 0x0000 | 0x0080), "100"}, - {"background light red ", uint16(0x0007 | 0x0040 | 0x0080), "101"}, - {"background light green ", uint16(0x0007 | 0x0020 | 0x0080), "102"}, - {"background light yellow ", uint16(0x0007 | 0x0060 | 0x0080), "103"}, - {"background light blue ", uint16(0x0007 | 0x0010 | 0x0080), "104"}, - {"background light magenta", uint16(0x0007 | 0x0050 | 0x0080), "105"}, - {"background light cyan ", uint16(0x0007 | 0x0030 | 0x0080), "106"}, - {"background light white ", uint16(0x0007 | 0x0070 | 0x0080), "107"}, - } - - resetParam := []testParam{ - {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, "0"}, - {"all reset", defaultFgColor | defaultBgColor | defaultFgIntensity | defaultBgIntensity, ""}, - } - - boldParam := []testParam{ - {"bold on", uint16(0x0007 | 0x0008), "1"}, - {"bold off", uint16(0x0007), "21"}, - } - - underscoreParam := []testParam{ - {"underscore on", uint16(0x0007 | 0x8000), "4"}, - {"underscore off", uint16(0x0007), "24"}, - } - - blinkParam := []testParam{ - {"blink on", uint16(0x0007 | 0x0080), "5"}, - {"blink off", uint16(0x0007), "25"}, - } - - mixedParam := []testParam{ - {"both black, bold, underline, blink", uint16(0x0000 | 0x0000 | 0x0008 | 0x8000 | 0x0080), "30;40;1;4;5"}, - {"both red, bold, underline, blink", uint16(0x0004 | 0x0040 | 0x0008 | 0x8000 | 0x0080), "31;41;1;4;5"}, - {"both green, bold, underline, blink", uint16(0x0002 | 0x0020 | 0x0008 | 0x8000 | 0x0080), "32;42;1;4;5"}, - {"both yellow, bold, underline, blink", uint16(0x0006 | 0x0060 | 0x0008 | 0x8000 | 0x0080), "33;43;1;4;5"}, - {"both blue, bold, underline, blink", uint16(0x0001 | 0x0010 | 0x0008 | 0x8000 | 0x0080), "34;44;1;4;5"}, - {"both magenta, bold, underline, blink", uint16(0x0005 | 0x0050 | 0x0008 | 0x8000 | 0x0080), "35;45;1;4;5"}, - {"both cyan, bold, underline, blink", uint16(0x0003 | 0x0030 | 0x0008 | 0x8000 | 0x0080), "36;46;1;4;5"}, - {"both white, bold, underline, blink", uint16(0x0007 | 0x0070 | 0x0008 | 0x8000 | 0x0080), "37;47;1;4;5"}, - {"both default, bold, underline, blink", uint16(defaultFgColor | defaultBgColor | 0x0008 | 0x8000 | 0x0080), "39;49;1;4;5"}, - } - - assertTextAttribute := func(expectedText string, expectedAttributes uint16, ansiColor string) { - actualText, actualAttributes, err := writeAnsiColor(expectedText, ansiColor) - if actualText != expectedText { - t.Errorf("Get %q, want %q", actualText, expectedText) - } - if err != nil { - t.Fatal("Could not get ConsoleScreenBufferInfo") - } - if actualAttributes != expectedAttributes { - t.Errorf("Text: %q, Get 0x%04x, want 0x%04x", expectedText, actualAttributes, expectedAttributes) - } - } - - for _, v := range fgParam { - ResetColor() - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } - - for _, v := range bgParam { - ChangeColor(uint16(0x0070 | 0x0007)) - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } - - for _, v := range resetParam { - ChangeColor(uint16(0x0000 | 0x0070 | 0x0008)) - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } - - ResetColor() - for _, v := range boldParam { - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } - - ResetColor() - for _, v := range underscoreParam { - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } - - ResetColor() - for _, v := range blinkParam { - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } - - for _, v := range mixedParam { - ResetColor() - assertTextAttribute(v.text, v.attributes, v.ansiColor) - } -} - -func TestIgnoreUnknownSequences(t *testing.T) { - inner := bytes.NewBufferString("") - w := NewModeAnsiColorWriter(inner, OutputNonColorEscSeq) - - inputText := "\x1b[=decpath mode" - expectedTail := inputText - fmt.Fprintf(w, inputText) - actualTail := inner.String() - inner.Reset() - if actualTail != expectedTail { - t.Errorf("Get %q, want %q", actualTail, expectedTail) - } - - inputText = "\x1b[=tailing esc and bracket\x1b[" - expectedTail = inputText - fmt.Fprintf(w, inputText) - actualTail = inner.String() - inner.Reset() - if actualTail != expectedTail { - t.Errorf("Get %q, want %q", actualTail, expectedTail) - } - - inputText = "\x1b[?tailing esc\x1b" - expectedTail = inputText - fmt.Fprintf(w, inputText) - actualTail = inner.String() - inner.Reset() - if actualTail != expectedTail { - t.Errorf("Get %q, want %q", actualTail, expectedTail) - } - - inputText = "\x1b[1h;3punended color code invalid\x1b3" - expectedTail = inputText - fmt.Fprintf(w, inputText) - actualTail = inner.String() - inner.Reset() - if actualTail != expectedTail { - t.Errorf("Get %q, want %q", actualTail, expectedTail) - } -} diff --git a/logs/conn.go b/logs/conn.go index 6d5bf6bf..afe0cbb7 100644 --- a/logs/conn.go +++ b/logs/conn.go @@ -63,7 +63,7 @@ func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error { defer c.innerWriter.Close() } - c.lg.println(when, msg) + c.lg.writeln(when, msg) return nil } diff --git a/logs/console.go b/logs/console.go index e75f2a1b..3dcaee1d 100644 --- a/logs/console.go +++ b/logs/console.go @@ -17,8 +17,10 @@ package logs import ( "encoding/json" "os" - "runtime" + "strings" "time" + + "github.com/shiena/ansicolor" ) // brush is a color join function @@ -54,9 +56,9 @@ type consoleWriter struct { // NewConsole create ConsoleWriter returning as LoggerInterface. func NewConsole() Logger { cw := &consoleWriter{ - lg: newLogWriter(os.Stdout), + lg: newLogWriter(ansicolor.NewAnsiColorWriter(os.Stdout)), Level: LevelDebug, - Colorful: runtime.GOOS != "windows", + Colorful: true, } return cw } @@ -67,11 +69,7 @@ func (c *consoleWriter) Init(jsonConfig string) error { if len(jsonConfig) == 0 { return nil } - err := json.Unmarshal([]byte(jsonConfig), c) - if runtime.GOOS == "windows" { - c.Colorful = false - } - return err + return json.Unmarshal([]byte(jsonConfig), c) } // WriteMsg write message in console. @@ -80,9 +78,9 @@ func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error { return nil } if c.Colorful { - msg = colors[level](msg) + msg = strings.Replace(msg, levelPrefix[level], colors[level](levelPrefix[level]), 1) } - c.lg.println(when, msg) + c.lg.writeln(when, msg) return nil } diff --git a/logs/log.go b/logs/log.go index a3614165..49f3794f 100644 --- a/logs/log.go +++ b/logs/log.go @@ -47,7 +47,7 @@ import ( // RFC5424 log message levels. const ( - LevelEmergency = iota + LevelEmergency = iota LevelAlert LevelCritical LevelError @@ -92,7 +92,7 @@ type Logger interface { } var adapters = make(map[string]newLoggerFunc) -var levelPrefix = [LevelDebug + 1]string{"[M] ", "[A] ", "[C] ", "[E] ", "[W] ", "[N] ", "[I] ", "[D] "} +var levelPrefix = [LevelDebug + 1]string{"[M]", "[A]", "[C]", "[E]", "[W]", "[N]", "[I]", "[D]"} // Register makes a log provide available by the provided name. // If Register is called twice with the same name or if driver is nil, @@ -187,12 +187,12 @@ func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { } } - log, ok := adapters[adapterName] + logAdapter, ok := adapters[adapterName] if !ok { return fmt.Errorf("logs: unknown adaptername %q (forgotten Register?)", adapterName) } - lg := log() + lg := logAdapter() err := lg.Init(config) if err != nil { fmt.Fprintln(os.Stderr, "logs.BeeLogger.SetLogger: "+err.Error()) @@ -248,7 +248,7 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { } // writeMsg will always add a '\n' character 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 err = bl.writeMsg(levelLoggerImpl, string(p)) @@ -287,7 +287,7 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error // set to emergency to ensure all log will be print out correctly logLevel = LevelEmergency } else { - msg = levelPrefix[logLevel] + msg + msg = levelPrefix[logLevel] + " " + msg } if bl.asynchronous { diff --git a/logs/logger.go b/logs/logger.go index 428d3aa0..c7cf8a56 100644 --- a/logs/logger.go +++ b/logs/logger.go @@ -15,9 +15,8 @@ package logs import ( - "fmt" "io" - "os" + "runtime" "sync" "time" ) @@ -31,47 +30,13 @@ func newLogWriter(wr io.Writer) *logWriter { return &logWriter{writer: wr} } -func (lg *logWriter) println(when time.Time, msg string) { +func (lg *logWriter) writeln(when time.Time, msg string) { lg.Lock() - h, _, _:= formatTimeHeader(when) + h, _, _ := formatTimeHeader(when) lg.writer.Write(append(append(h, msg...), '\n')) lg.Unlock() } -type outputMode int - -// DiscardNonColorEscSeq supports the divided color escape sequence. -// But non-color escape sequence is not output. -// Please use the OutputNonColorEscSeq If you want to output a non-color -// escape sequences such as ncurses. However, it does not support the divided -// color escape sequence. -const ( - _ outputMode = iota - DiscardNonColorEscSeq - OutputNonColorEscSeq -) - -// NewAnsiColorWriter creates and initializes a new ansiColorWriter -// using io.Writer w as its initial contents. -// In the console of Windows, which change the foreground and background -// colors of the text by the escape sequence. -// In the console of other systems, which writes to w all text. -func NewAnsiColorWriter(w io.Writer) io.Writer { - return NewModeAnsiColorWriter(w, DiscardNonColorEscSeq) -} - -// NewModeAnsiColorWriter create and initializes a new ansiColorWriter -// by specifying the outputMode. -func NewModeAnsiColorWriter(w io.Writer, mode outputMode) io.Writer { - if _, ok := w.(*ansiColorWriter); !ok { - return &ansiColorWriter{ - w: w, - mode: mode, - } - } - return w -} - const ( y1 = `0123456789` y2 = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789` @@ -146,63 +111,65 @@ var ( reset = string([]byte{27, 91, 48, 109}) ) +var once sync.Once +var colorMap map[string]string + +func initColor() { + if runtime.GOOS == "windows" { + green = w32Green + white = w32White + yellow = w32Yellow + red = w32Red + blue = w32Blue + magenta = w32Magenta + cyan = w32Cyan + } + colorMap = map[string]string{ + //by color + "green": green, + "white": white, + "yellow": yellow, + "red": red, + //by method + "GET": blue, + "POST": cyan, + "PUT": yellow, + "DELETE": red, + "PATCH": green, + "HEAD": magenta, + "OPTIONS": white, + } +} + // ColorByStatus return color by http code // 2xx return Green // 3xx return White // 4xx return Yellow // 5xx return Red -func ColorByStatus(cond bool, code int) string { +func ColorByStatus(code int) string { + once.Do(initColor) switch { case code >= 200 && code < 300: - return map[bool]string{true: green, false: w32Green}[cond] + return colorMap["green"] case code >= 300 && code < 400: - return map[bool]string{true: white, false: w32White}[cond] + return colorMap["white"] case code >= 400 && code < 500: - return map[bool]string{true: yellow, false: w32Yellow}[cond] + return colorMap["yellow"] default: - return map[bool]string{true: red, false: w32Red}[cond] + return colorMap["red"] } } // ColorByMethod return color by http code -// GET return Blue -// POST return Cyan -// PUT return Yellow -// DELETE return Red -// PATCH return Green -// HEAD return Magenta -// OPTIONS return WHITE -func ColorByMethod(cond bool, method string) string { - switch method { - case "GET": - return map[bool]string{true: blue, false: w32Blue}[cond] - case "POST": - return map[bool]string{true: cyan, false: w32Cyan}[cond] - case "PUT": - return map[bool]string{true: yellow, false: w32Yellow}[cond] - case "DELETE": - return map[bool]string{true: red, false: w32Red}[cond] - case "PATCH": - return map[bool]string{true: green, false: w32Green}[cond] - case "HEAD": - return map[bool]string{true: magenta, false: w32Magenta}[cond] - case "OPTIONS": - return map[bool]string{true: white, false: w32White}[cond] - default: - return reset +func ColorByMethod(method string) string { + once.Do(initColor) + if c := colorMap[method]; c != "" { + return c } + return reset } -// Guard Mutex to guarantee atomic of W32Debug(string) function -var mu sync.Mutex - -// W32Debug Helper method to output colored logs in Windows terminals -func W32Debug(msg string) { - mu.Lock() - defer mu.Unlock() - - current := time.Now() - w := NewAnsiColorWriter(os.Stdout) - - fmt.Fprintf(w, "[beego] %v %s\n", current.Format("2006/01/02 - 15:04:05"), msg) +// ResetColor return reset color +func ResetColor() string { + return reset } diff --git a/logs/logger_test.go b/logs/logger_test.go index 78c67737..15be500d 100644 --- a/logs/logger_test.go +++ b/logs/logger_test.go @@ -15,7 +15,6 @@ package logs import ( - "bytes" "testing" "time" ) @@ -56,20 +55,3 @@ func TestFormatHeader_1(t *testing.T) { tm = tm.Add(dur) } } - -func TestNewAnsiColor1(t *testing.T) { - inner := bytes.NewBufferString("") - w := NewAnsiColorWriter(inner) - if w == inner { - t.Errorf("Get %#v, want %#v", w, inner) - } -} - -func TestNewAnsiColor2(t *testing.T) { - inner := bytes.NewBufferString("") - w1 := NewAnsiColorWriter(inner) - w2 := NewAnsiColorWriter(w1) - if w1 != w2 { - t.Errorf("Get %#v, want %#v", w1, w2) - } -} diff --git a/migration/ddl.go b/migration/ddl.go index 9313acf8..cd2c1c49 100644 --- a/migration/ddl.go +++ b/migration/ddl.go @@ -17,7 +17,7 @@ package migration import ( "fmt" - "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" ) // Index struct defines the structure of Index Columns @@ -316,7 +316,7 @@ func (m *Migration) GetSQL() (sql string) { sql += fmt.Sprintf("ALTER TABLE `%s` ", m.TableName) for index, column := range m.Columns { if !column.remove { - beego.BeeLogger.Info("col") + logs.Info("col") sql += fmt.Sprintf("\n ADD `%s` %s %s %s %s %s", column.Name, column.DataType, column.Unsign, column.Null, column.Inc, column.Default) } else { sql += fmt.Sprintf("\n DROP COLUMN `%s`", column.Name) diff --git a/router.go b/router.go index 52c56632..a9b6f078 100644 --- a/router.go +++ b/router.go @@ -21,7 +21,6 @@ import ( "path" "path/filepath" "reflect" - "runtime" "strconv" "strings" "sync" @@ -900,38 +899,28 @@ Admin: } if FilterMonitorFunc(r.Method, r.URL.Path, timeDur, pattern, statusCode) { + routerName := "" if runRouter != nil { - go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runRouter.Name(), timeDur) - } else { - go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeDur) + routerName = runRouter.Name() } + go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, routerName, timeDur) } } if BConfig.RunMode == DEV && !BConfig.Log.AccessLogs { - var devInfo string - iswin := (runtime.GOOS == "windows") - statusColor := logs.ColorByStatus(iswin, statusCode) - methodColor := logs.ColorByMethod(iswin, r.Method) - resetColor := logs.ColorByMethod(iswin, "") - if findRouter { - if routerInfo != nil { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s r:%s", context.Input.IP(), statusColor, statusCode, - resetColor, timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path, - routerInfo.pattern) - } else { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, - timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path) - } - } else { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, - timeDur.String(), "nomatch", methodColor, r.Method, resetColor, r.URL.Path) - } - if iswin { - logs.W32Debug(devInfo) - } else { - logs.Debug(devInfo) + match := map[bool]string{true: "match", false: "nomatch"} + devInfo := fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", + context.Input.IP(), + logs.ColorByStatus(statusCode), statusCode, logs.ResetColor(), + timeDur.String(), + match[findRouter], + logs.ColorByMethod(r.Method), r.Method, logs.ResetColor(), + r.URL.Path) + if routerInfo != nil { + devInfo += fmt.Sprintf(" r:%s", routerInfo.pattern) } + + logs.Debug(devInfo) } // Call WriteHeader if status code has been set changed if context.Output.Status != 0 {