From a1cb00070123ffcdbd461d5b2946c0b7606ce50d Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 14:42:38 +0800 Subject: [PATCH 01/44] remove log package --- logs/conn.go | 17 ++++++------- logs/console.go | 11 +++------ logs/file.go | 10 +++----- logs/log.go | 42 -------------------------------- logs/logger.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 65 deletions(-) create mode 100644 logs/logger.go diff --git a/logs/conn.go b/logs/conn.go index 5d78467b..1db1a427 100644 --- a/logs/conn.go +++ b/logs/conn.go @@ -17,7 +17,6 @@ package logs import ( "encoding/json" "io" - "log" "net" "time" ) @@ -25,7 +24,7 @@ import ( // connWriter implements LoggerInterface. // it writes messages in keep-live tcp connection. type connWriter struct { - lg *log.Logger + lg *logWriter innerWriter io.WriteCloser ReconnectOnMsg bool `json:"reconnectOnMsg"` Reconnect bool `json:"reconnect"` @@ -43,8 +42,8 @@ func NewConn() Logger { // Init init connection writer with json config. // json config only need key "level". -func (c *connWriter) Init(jsonconfig string) error { - return json.Unmarshal([]byte(jsonconfig), c) +func (c *connWriter) Init(jsonConfig string) error { + return json.Unmarshal([]byte(jsonConfig), c) } // WriteMsg write message in connection. @@ -53,7 +52,7 @@ func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error { if level > c.Level { return nil } - if c.neddedConnectOnMsg() { + if c.needToConnectOnMsg() { err := c.connect() if err != nil { return err @@ -64,9 +63,7 @@ func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error { defer c.innerWriter.Close() } - msg = formatLogTime(when) + msg - - c.lg.Println(msg) + c.lg.println(when, msg) return nil } @@ -98,11 +95,11 @@ func (c *connWriter) connect() error { } c.innerWriter = conn - c.lg = log.New(conn, "", 0) + c.lg = newLogWriter(conn) return nil } -func (c *connWriter) neddedConnectOnMsg() bool { +func (c *connWriter) needToConnectOnMsg() bool { if c.Reconnect { c.Reconnect = false return true diff --git a/logs/console.go b/logs/console.go index 3781e6cd..05d08a42 100644 --- a/logs/console.go +++ b/logs/console.go @@ -16,7 +16,6 @@ package logs import ( "encoding/json" - "log" "os" "runtime" "time" @@ -47,7 +46,7 @@ var colors = []brush{ // consoleWriter implements LoggerInterface and writes messages to terminal. type consoleWriter struct { - lg *log.Logger + lg *logWriter Level int `json:"level"` Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color } @@ -55,7 +54,7 @@ type consoleWriter struct { // NewConsole create ConsoleWriter returning as LoggerInterface. func NewConsole() Logger { cw := &consoleWriter{ - lg: log.New(os.Stdout, "", 0), + lg: newLogWriter(os.Stdout), Level: LevelDebug, Colorful: true, } @@ -80,12 +79,10 @@ func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error { if level > c.Level { return nil } - msg = formatLogTime(when) + msg if c.Colorful { - c.lg.Println(colors[level](msg)) - } else { - c.lg.Println(msg) + msg = colors[level](msg) } + c.lg.println(when, msg) return nil } diff --git a/logs/file.go b/logs/file.go index 3a042164..6001b982 100644 --- a/logs/file.go +++ b/logs/file.go @@ -118,13 +118,11 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { if level > w.Level { return nil } - msg = formatLogTime(when) + msg + "\n" - + h, d := formatTimeHeader(when) if w.Rotate { - d := when.Day() - if w.needRotate(len(msg), d) { + if w.needRotate(len(h)+len(msg)+1, d) { w.Lock() - if w.needRotate(len(msg), d) { + if w.needRotate(len(h)+len(msg)+1, d) { if err := w.doRotate(when); err != nil { fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) } @@ -134,7 +132,7 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { } w.Lock() - _, err := w.fileWriter.Write([]byte(msg)) + _, err := w.fileWriter.Write(append(append(h, msg...), '\n')) if err == nil { w.maxLinesCurLines++ w.maxSizeCurSize += len(msg) diff --git a/logs/log.go b/logs/log.go index 2a12ed79..f53d2382 100644 --- a/logs/log.go +++ b/logs/log.go @@ -367,45 +367,3 @@ func (bl *BeeLogger) Close() { } bl.outputs = nil } - -func formatLogTime(when time.Time) string { - y, mo, d := when.Date() - h, mi, s := when.Clock() - //len(2006/01/02 15:03:04)==19 - var buf [20]byte - t := 3 - for y >= 10 { - p := y / 10 - buf[t] = byte('0' + y - p*10) - y = p - t-- - } - buf[0] = byte('0' + y) - buf[4] = '/' - if mo > 9 { - buf[5] = '1' - buf[6] = byte('0' + mo - 9) - } else { - buf[5] = '0' - buf[6] = byte('0' + mo) - } - buf[7] = '/' - t = d / 10 - buf[8] = byte('0' + t) - buf[9] = byte('0' + d - t*10) - buf[10] = ' ' - t = h / 10 - buf[11] = byte('0' + t) - buf[12] = byte('0' + h - t*10) - buf[13] = ':' - t = mi / 10 - buf[14] = byte('0' + t) - buf[15] = byte('0' + mi - t*10) - buf[16] = ':' - t = s / 10 - buf[17] = byte('0' + t) - buf[18] = byte('0' + s - t*10) - buf[19] = ' ' - - return string(buf[0:]) -} diff --git a/logs/logger.go b/logs/logger.go new file mode 100644 index 00000000..ffcead2b --- /dev/null +++ b/logs/logger.go @@ -0,0 +1,65 @@ +package logs + +import ( + "io" + "sync" + "time" +) + +type logWriter struct { + sync.Mutex + writer io.Writer +} + +func newLogWriter(wr io.Writer) *logWriter { + return &logWriter{writer: wr} +} + +func (lg *logWriter) println(when time.Time, msg string) { + lg.Lock() + h, _ := formatTimeHeader(when) + lg.writer.Write(append(append(h, msg...), '\n')) + lg.Unlock() +} + +func formatTimeHeader(when time.Time) ([]byte, int) { + y, mo, d := when.Date() + h, mi, s := when.Clock() + //len(2006/01/02 15:03:04)==19 + var buf [20]byte + t := 3 + for y >= 10 { + p := y / 10 + buf[t] = byte('0' + y - p*10) + y = p + t-- + } + buf[0] = byte('0' + y) + buf[4] = '/' + if mo > 9 { + buf[5] = '1' + buf[6] = byte('0' + mo - 9) + } else { + buf[5] = '0' + buf[6] = byte('0' + mo) + } + buf[7] = '/' + t = d / 10 + buf[8] = byte('0' + t) + buf[9] = byte('0' + d - t*10) + buf[10] = ' ' + t = h / 10 + buf[11] = byte('0' + t) + buf[12] = byte('0' + h - t*10) + buf[13] = ':' + t = mi / 10 + buf[14] = byte('0' + t) + buf[15] = byte('0' + mi - t*10) + buf[16] = ':' + t = s / 10 + buf[17] = byte('0' + t) + buf[18] = byte('0' + s - t*10) + buf[19] = ' ' + + return buf[0:], d +} From 9806a43783f240e0d15f8c2e2fdb92a718b3533c Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 15:03:37 +0800 Subject: [PATCH 02/44] make more fast --- logs/file.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/logs/file.go b/logs/file.go index 6001b982..ae58fc29 100644 --- a/logs/file.go +++ b/logs/file.go @@ -119,10 +119,11 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { return nil } h, d := formatTimeHeader(when) + msg = string(h) + msg + "\n" if w.Rotate { - if w.needRotate(len(h)+len(msg)+1, d) { + if w.needRotate(len(msg), d) { w.Lock() - if w.needRotate(len(h)+len(msg)+1, d) { + if w.needRotate(len(msg), d) { if err := w.doRotate(when); err != nil { fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) } @@ -132,7 +133,7 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { } w.Lock() - _, err := w.fileWriter.Write(append(append(h, msg...), '\n')) + _, err := w.fileWriter.Write([]byte(msg)) if err == nil { w.maxLinesCurLines++ w.maxSizeCurSize += len(msg) From 304a5ccea0945156f68a34b205718a97cabba7af Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 15:06:53 +0800 Subject: [PATCH 03/44] comment fix --- logs/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/file.go b/logs/file.go index ae58fc29..5928d1c4 100644 --- a/logs/file.go +++ b/logs/file.go @@ -55,7 +55,7 @@ type fileLogWriter struct { Perm os.FileMode `json:"perm"` } -// NewFileWriter create a FileLogWriter returning as LoggerInterface. +// newFileWriter create a FileLogWriter returning as LoggerInterface. func newFileWriter() Logger { w := &fileLogWriter{ Filename: "", From 6caa3ecd91ce16b96d21982d951173c35531f348 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 15:31:59 +0800 Subject: [PATCH 04/44] when rotate by date ,there's no num after log file --- logs/file.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/logs/file.go b/logs/file.go index 5928d1c4..6fa2935b 100644 --- a/logs/file.go +++ b/logs/file.go @@ -210,8 +210,13 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { if suffix == "" { suffix = ".log" } - for ; err == nil && num <= 999; num++ { - fName = filenameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, suffix) + if w.MaxLines > 0 || w.MaxSize > 0 { + for ; err == nil && num <= 999; num++ { + fName = filenameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, suffix) + _, err = os.Lstat(fName) + } + } else { + fName = fmt.Sprintf("%s.%s.%s", filenameOnly, logTime.Format("2006-01-02"), suffix) _, err = os.Lstat(fName) } // return error if the last file checked still existed From 68cc53e92b85e58664c0791ad89b436419f79330 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 15:43:15 +0800 Subject: [PATCH 05/44] when rotate by date ,there's no num after log file --- logs/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/file.go b/logs/file.go index 6fa2935b..4f228267 100644 --- a/logs/file.go +++ b/logs/file.go @@ -195,7 +195,7 @@ func (w *fileLogWriter) lines() (int, error) { } // DoRotate means it need to write file in new file. -// new file name like xx.2013-01-01.2.log +// new file name like xx.2013-01-01.log (daily) or xx.001.log (by line or size) func (w *fileLogWriter) doRotate(logTime time.Time) error { _, err := os.Lstat(w.Filename) if err != nil { From 51b1095e73d46eb21d7bb8042285703e7038ec2b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 16:32:59 +0800 Subject: [PATCH 06/44] add files logger --- logs/file.go | 16 +++++++------ logs/files.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ logs/log.go | 4 +++- 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 logs/files.go diff --git a/logs/file.go b/logs/file.go index 4f228267..990a76d8 100644 --- a/logs/file.go +++ b/logs/file.go @@ -53,6 +53,8 @@ type fileLogWriter struct { Level int `json:"level"` Perm os.FileMode `json:"perm"` + + fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix } // newFileWriter create a FileLogWriter returning as LoggerInterface. @@ -89,6 +91,11 @@ func (w *fileLogWriter) Init(jsonConfig string) error { if len(w.Filename) == 0 { return errors.New("jsonconfig must have filename") } + w.suffix = filepath.Ext(w.Filename) + w.fileNameOnly = strings.TrimSuffix(w.Filename, w.suffix) + if w.suffix == "" { + w.suffix = ".log" + } err = w.startLogger() return err } @@ -205,18 +212,13 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { // Find the next available number num := 1 fName := "" - suffix := filepath.Ext(w.Filename) - filenameOnly := strings.TrimSuffix(w.Filename, suffix) - if suffix == "" { - suffix = ".log" - } if w.MaxLines > 0 || w.MaxSize > 0 { for ; err == nil && num <= 999; num++ { - fName = filenameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, suffix) + fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix) _, err = os.Lstat(fName) } } else { - fName = fmt.Sprintf("%s.%s.%s", filenameOnly, logTime.Format("2006-01-02"), suffix) + fName = fmt.Sprintf("%s.%s.%s", w.fileNameOnly, logTime.Format("2006-01-02"), w.suffix) _, err = os.Lstat(fName) } // return error if the last file checked still existed diff --git a/logs/files.go b/logs/files.go new file mode 100644 index 00000000..42528660 --- /dev/null +++ b/logs/files.go @@ -0,0 +1,66 @@ +package logs + +import "time" + +type filesLogWriter struct { + writers [LevelDebug + 1]*fileLogWriter +} + +func (f *filesLogWriter) Init(config string) error { + writer := newFileWriter().(*fileLogWriter) + err := writer.Init(config) + if err != nil { + return err + } + f.writers[0] = writer + + for i := LevelEmergency; i <= f.writers[0].Level; i++ { + writer = newFileWriter().(*fileLogWriter) + writer.Init(config) + writer.Level = i + writer.fileNameOnly += "." + levelNames[i] + f.writers[i+1] = writer + } + + return nil +} + +func (f *filesLogWriter) Destroy() { + for i := 0; i < len(f.writers); i++ { + if f.writers[i] != nil { + f.writers[i].Destroy() + } + } +} + +func (f *filesLogWriter) WriteMsg(when time.Time, msg string, level int) error { + if f.writers[0] != nil { + f.writers[0].WriteMsg(when, msg, level) + } + for i := 1; i < len(f.writers); i++ { + if f.writers[i] != nil { + if level == f.writers[i].Level { + f.writers[i].WriteMsg(when, msg, level) + } + } + } + return nil +} + +func (f *filesLogWriter) Flush() { + for i := 0; i < len(f.writers); i++ { + if f.writers[i] != nil { + f.writers[i].Flush() + } + } +} + + +// newFilesWriter create a FileLogWriter returning as LoggerInterface. +func newFilesWriter() Logger { + return &filesLogWriter{} +} + +func init() { + Register("files", NewConn) +} diff --git a/logs/log.go b/logs/log.go index f53d2382..e5c14dc1 100644 --- a/logs/log.go +++ b/logs/log.go @@ -64,6 +64,8 @@ const ( LevelWarn = LevelWarning ) +var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"} + type loggerType func() Logger // Logger defines the behavior of a log provider. @@ -109,7 +111,7 @@ type nameLogger struct { type logMsg struct { level int msg string - when time.Time + when time.Time } var logMsgPool *sync.Pool From f8c4b3aa4c9a2eee65e5686c99075fa0573c9212 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 17:03:57 +0800 Subject: [PATCH 07/44] add files logger to separate different logs --- logs/files.go | 71 +++++++++++++++++++++++++++++++++++++++++--------- logs/log.go | 2 -- logs/logger.go | 15 +++++++++++ 3 files changed, 73 insertions(+), 15 deletions(-) diff --git a/logs/files.go b/logs/files.go index 42528660..617af1ec 100644 --- a/logs/files.go +++ b/logs/files.go @@ -1,25 +1,71 @@ +// 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 logs -import "time" +import ( + "encoding/json" + "time" +) +// A filesLogWriter manages several fileLogWriter +// filesLogWriter will write logs to the file in json configuration and write the same level log to correspond file +// means if the file name in configuration is project.log filesLogWriter will create project.error.log/project.debug.log +// and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log +// the rotate attribute also acts like fileLogWriter type filesLogWriter struct { - writers [LevelDebug + 1]*fileLogWriter + writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter + fullLogWriter *fileLogWriter + Separate []string `json:"separate"` } +var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"} + +// Init file logger with json config. +// jsonConfig like: +// { +// "filename":"logs/beego.log", +// "maxLines":0, +// "maxsize":0, +// "daily":true, +// "maxDays":15, +// "rotate":true, +// "perm":0600, +// "separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"], +// } + func (f *filesLogWriter) Init(config string) error { writer := newFileWriter().(*fileLogWriter) err := writer.Init(config) if err != nil { return err } - f.writers[0] = writer + f.fullLogWriter = writer + f.writers[LevelDebug+1] = writer - for i := LevelEmergency; i <= f.writers[0].Level; i++ { - writer = newFileWriter().(*fileLogWriter) - writer.Init(config) - writer.Level = i - writer.fileNameOnly += "." + levelNames[i] - f.writers[i+1] = writer + json.Unmarshal([]byte(config), f) + + for i := LevelEmergency; i < LevelDebug+1; i++ { + for _, v := range f.Separate { + if v == levelNames[i] { + writer = newFileWriter().(*fileLogWriter) + writer.Init(config) + writer.Level = i + writer.fileNameOnly += "." + levelNames[i] + f.writers[i] = writer + } + } } return nil @@ -34,10 +80,10 @@ func (f *filesLogWriter) Destroy() { } func (f *filesLogWriter) WriteMsg(when time.Time, msg string, level int) error { - if f.writers[0] != nil { - f.writers[0].WriteMsg(when, msg, level) + if f.fullLogWriter != nil { + f.fullLogWriter.WriteMsg(when, msg, level) } - for i := 1; i < len(f.writers); i++ { + for i := 0; i < len(f.writers)-1; i++ { if f.writers[i] != nil { if level == f.writers[i].Level { f.writers[i].WriteMsg(when, msg, level) @@ -55,7 +101,6 @@ func (f *filesLogWriter) Flush() { } } - // newFilesWriter create a FileLogWriter returning as LoggerInterface. func newFilesWriter() Logger { return &filesLogWriter{} diff --git a/logs/log.go b/logs/log.go index e5c14dc1..b93b276e 100644 --- a/logs/log.go +++ b/logs/log.go @@ -64,8 +64,6 @@ const ( LevelWarn = LevelWarning ) -var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"} - type loggerType func() Logger // Logger defines the behavior of a log provider. diff --git a/logs/logger.go b/logs/logger.go index ffcead2b..323c41c5 100644 --- a/logs/logger.go +++ b/logs/logger.go @@ -1,3 +1,18 @@ +// 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 logs import ( From 1f716dda3e52653a48cdf9777ba965cd47feafa7 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 3 Feb 2016 17:54:58 +0800 Subject: [PATCH 08/44] add test files and bug fixed --- logs/files.go | 15 ++++++--- logs/files_test.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 logs/files_test.go diff --git a/logs/files.go b/logs/files.go index 617af1ec..816d42e3 100644 --- a/logs/files.go +++ b/logs/files.go @@ -17,6 +17,7 @@ package logs import ( "encoding/json" "time" + "fmt" ) // A filesLogWriter manages several fileLogWriter @@ -56,14 +57,20 @@ func (f *filesLogWriter) Init(config string) error { json.Unmarshal([]byte(config), f) + jsonMap := map[string]interface{}{} + + json.Unmarshal([]byte(config), &jsonMap) + for i := LevelEmergency; i < LevelDebug+1; i++ { for _, v := range f.Separate { if v == levelNames[i] { + jsonMap["filename"] = f.fullLogWriter.fileNameOnly + "." + levelNames[i] + f.fullLogWriter.suffix + jsonMap["level"] = i + bs, _ := json.Marshal(jsonMap) writer = newFileWriter().(*fileLogWriter) - writer.Init(config) - writer.Level = i - writer.fileNameOnly += "." + levelNames[i] + writer.Init(string(bs)) f.writers[i] = writer + fmt.Println(writer.Filename) } } } @@ -107,5 +114,5 @@ func newFilesWriter() Logger { } func init() { - Register("files", NewConn) + Register("files", newFilesWriter) } diff --git a/logs/files_test.go b/logs/files_test.go new file mode 100644 index 00000000..058ba902 --- /dev/null +++ b/logs/files_test.go @@ -0,0 +1,78 @@ +// 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 logs + +import ( + "bufio" + "os" + "strconv" + "strings" + "testing" +) + +func TestFiles_1(t *testing.T) { + log := NewLogger(10000) + log.SetLogger("files", `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`) + log.Debug("debug") + log.Informational("info") + log.Notice("notice") + log.Warning("warning") + log.Error("error") + log.Alert("alert") + log.Critical("critical") + log.Emergency("emergency") + fns := []string{""} + fns = append(fns, levelNames[0:]...) + name := "test" + suffix := ".log" + for _, fn := range fns { + + file := name + suffix + if fn != "" { + file = name + "." + fn + suffix + } + f, err := os.Open(file) + if err != nil { + t.Fatal(err) + } + b := bufio.NewReader(f) + lineNum := 0 + lastLine := "" + for { + line, _, err := b.ReadLine() + if err != nil { + break + } + if len(line) > 0 { + lastLine = string(line) + lineNum++ + } + } + var expected = 1 + if fn == "" { + expected = LevelDebug + 1 + } + if lineNum != expected { + t.Fatal(file, "has", lineNum, "lines not "+strconv.Itoa(expected)+" lines") + } + if lineNum == 1 { + if !strings.Contains(lastLine, fn) { + t.Fatal(file + " " + lastLine + " not contains the log msg " + fn) + } + } + os.Remove(file) + } + +} From 810f6db8d2399fb515157024b54c3745df5385d3 Mon Sep 17 00:00:00 2001 From: ysqi Date: Fri, 12 Feb 2016 11:27:59 +0800 Subject: [PATCH 09/44] fix #1669 write empty body panic error --- context/context.go | 10 ++++++++++ context/output.go | 3 +-- router_test.go | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/context/context.go b/context/context.go index db790ff2..5f095f1a 100644 --- a/context/context.go +++ b/context/context.go @@ -24,11 +24,13 @@ package context import ( "bufio" + "bytes" "crypto/hmac" "crypto/sha1" "encoding/base64" "errors" "fmt" + "io" "net" "net/http" "strconv" @@ -184,6 +186,14 @@ func (w *Response) Write(p []byte) (int, error) { return w.ResponseWriter.Write(p) } +// Write writes the data to the connection as part of an HTTP reply, +// and sets `started` to true. +// started means the response has sent out. +func (w *Response) Copy(buf *bytes.Buffer) (int64, error) { + w.Started = true + return io.Copy(w.ResponseWriter, buf) +} + // WriteHeader sends an HTTP response header with status code, // and sets `started` to true. func (w *Response) WriteHeader(code int) { diff --git a/context/output.go b/context/output.go index 2d756e27..aa00244b 100644 --- a/context/output.go +++ b/context/output.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "html/template" - "io" "mime" "net/http" "path/filepath" @@ -75,7 +74,7 @@ func (output *BeegoOutput) Body(content []byte) { output.Status = 0 } - io.Copy(output.Context.ResponseWriter, buf) + output.Context.ResponseWriter.Copy(buf) } // Cookie sets cookie value via given key. diff --git a/router_test.go b/router_test.go index b0ae7a18..f26f0c86 100644 --- a/router_test.go +++ b/router_test.go @@ -65,6 +65,11 @@ func (tc *TestController) GetManyRouter() { tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page")) } +func (tc *TestController) GetEmptyBody() { + var res []byte + tc.Ctx.Output.Body(res) +} + type ResStatus struct { Code int Msg string @@ -239,6 +244,21 @@ func TestManyRoute(t *testing.T) { } } +// Test for issue #1669 +func TestEmptyResponse(t *testing.T) { + + r, _ := http.NewRequest("GET", "/beego-empty.html", nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/beego-empty.html", &TestController{}, "get:GetEmptyBody") + handler.ServeHTTP(w, r) + + if body := w.Body.String(); body != "" { + t.Error("want empty body") + } +} + func TestNotFound(t *testing.T) { r, _ := http.NewRequest("GET", "/", nil) w := httptest.NewRecorder() From d35c50a8e0bf0ace2c5567d8a21fbbe55643589c Mon Sep 17 00:00:00 2001 From: ysqi Date: Fri, 12 Feb 2016 11:36:25 +0800 Subject: [PATCH 10/44] return write body error --- context/output.go | 14 ++++++-------- controller.go | 3 +-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/context/output.go b/context/output.go index aa00244b..066859f2 100644 --- a/context/output.go +++ b/context/output.go @@ -56,7 +56,7 @@ func (output *BeegoOutput) Header(key, val string) { // Body sets response body content. // if EnableGzip, compress content string. // it sends out response body directly. -func (output *BeegoOutput) Body(content []byte) { +func (output *BeegoOutput) Body(content []byte) error { var encoding string var buf = &bytes.Buffer{} if output.EnableGzip { @@ -74,7 +74,8 @@ func (output *BeegoOutput) Body(content []byte) { output.Status = 0 } - output.Context.ResponseWriter.Copy(buf) + _, err := output.Context.ResponseWriter.Copy(buf) + return err } // Cookie sets cookie value via given key. @@ -185,8 +186,7 @@ func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) e if coding { content = []byte(stringsToJSON(string(content))) } - output.Body(content) - return nil + return output.Body(content) } // JSONP writes jsonp to response body. @@ -211,8 +211,7 @@ func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error { callbackContent.WriteString("(") callbackContent.Write(content) callbackContent.WriteString(");\r\n") - output.Body(callbackContent.Bytes()) - return nil + return output.Body(callbackContent.Bytes()) } // XML writes xml string to response body. @@ -229,8 +228,7 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { http.Error(output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError) return err } - output.Body(content) - return nil + return output.Body(content) } // Download forces response for download file. diff --git a/controller.go b/controller.go index a2943d42..b23f7617 100644 --- a/controller.go +++ b/controller.go @@ -185,8 +185,7 @@ func (c *Controller) Render() error { return err } c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8") - c.Ctx.Output.Body(rb) - return nil + return c.Ctx.Output.Body(rb) } // RenderString returns the rendered template string. Do not send out response. From 23860e680785757a28d3920492c421e8d857f63c Mon Sep 17 00:00:00 2001 From: ysqi Date: Fri, 12 Feb 2016 11:36:59 +0800 Subject: [PATCH 11/44] go fmt --- config.go | 2 +- staticfile_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index ffe92f06..e7f3ee98 100644 --- a/config.go +++ b/config.go @@ -15,11 +15,11 @@ package beego import ( + "fmt" "html/template" "os" "path/filepath" "strings" - "fmt" "github.com/astaxie/beego/config" "github.com/astaxie/beego/session" diff --git a/staticfile_test.go b/staticfile_test.go index e7003366..a043b4fd 100644 --- a/staticfile_test.go +++ b/staticfile_test.go @@ -7,8 +7,8 @@ import ( "io" "io/ioutil" "os" - "testing" "path/filepath" + "testing" ) var currentWorkDir, _ = os.Getwd() From d5f07d65bb55f6b77390ec4aa1da5229d28653b9 Mon Sep 17 00:00:00 2001 From: ysqi Date: Sun, 14 Feb 2016 18:54:40 +0800 Subject: [PATCH 12/44] panic parse config error --- config.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index ffe92f06..92fb8914 100644 --- a/config.go +++ b/config.go @@ -193,7 +193,9 @@ func init() { return } - parseConfig(appConfigPath) + if err := parseConfig(appConfigPath); err != nil { + panic(err) + } } // now only support ini, next will support json. From 891016a0a25cdda21b119d07972bddf0a2f995ea Mon Sep 17 00:00:00 2001 From: ysqi Date: Sun, 14 Feb 2016 18:55:42 +0800 Subject: [PATCH 13/44] ignore parse include config file error --- config/ini.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/ini.go b/config/ini.go index da6f2b3a..2cec7baa 100644 --- a/config/ini.go +++ b/config/ini.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "os" "path" "strconv" @@ -134,7 +135,9 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) { } i, err := ini.parseFile(otherfile) if err != nil { - return nil, err + // ignore error + log.Printf("[warn] handle config %q error, %s \n", key, err.Error()) + continue } for sec, dt := range i.data { if _, ok := cfg.data[sec]; !ok { From 9119f766d29e6b4a79892e7afed2e828e68d3428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20GALLARD?= Date: Mon, 22 Feb 2016 13:35:54 +0100 Subject: [PATCH 14/44] Fix cookies in accordance with the "net / http" and Flash usage Fixed issue of Flash cookies that are deleted before being read Max-age parameter conform to "net/http" Cookie --- context/output.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/context/output.go b/context/output.go index 2d756e27..f27bba17 100644 --- a/context/output.go +++ b/context/output.go @@ -97,9 +97,10 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface maxAge = v } - if maxAge > 0 { + switch { + case maxAge > 0: fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge) - } else { + case maxAge < 0: fmt.Fprintf(&b, "; Max-Age=0") } } From ffbb45e567a7616540f0dfdfaeeeffd7617b53d4 Mon Sep 17 00:00:00 2001 From: ysqi Date: Sat, 27 Feb 2016 20:18:59 +0800 Subject: [PATCH 15/44] Revert "ignore parse include config file error" This reverts commit 891016a0a25cdda21b119d07972bddf0a2f995ea. --- config/ini.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/config/ini.go b/config/ini.go index 2cec7baa..da6f2b3a 100644 --- a/config/ini.go +++ b/config/ini.go @@ -21,7 +21,6 @@ import ( "fmt" "io" "io/ioutil" - "log" "os" "path" "strconv" @@ -135,9 +134,7 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) { } i, err := ini.parseFile(otherfile) if err != nil { - // ignore error - log.Printf("[warn] handle config %q error, %s \n", key, err.Error()) - continue + return nil, err } for sec, dt := range i.data { if _, ok := cfg.data[sec]; !ok { From 477de9a3f3f37a608c225b4e4addb18f183d87ca Mon Sep 17 00:00:00 2001 From: iexploree Date: Tue, 1 Mar 2016 10:51:47 +0800 Subject: [PATCH 16/44] fix bug: session id undecoded when destroy and sesssion memory provider push wrong --- session/sess_mem.go | 6 ++++-- session/session.go | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/session/sess_mem.go b/session/sess_mem.go index dd61ef57..8d75d2c6 100644 --- a/session/sess_mem.go +++ b/session/sess_mem.go @@ -102,7 +102,8 @@ func (pder *MemProvider) SessionRead(sid string) (Store, error) { pder.lock.RUnlock() pder.lock.Lock() newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} - element := pder.list.PushBack(newsess) + // fix bug: new session should be pushed into the head of list(more fresh) + element := pder.list.PushFront(newsess) pder.sessions[sid] = element pder.lock.Unlock() return newsess, nil @@ -134,7 +135,8 @@ func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (Store, error) { pder.lock.RUnlock() pder.lock.Lock() newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} - element := pder.list.PushBack(newsess) + // fix bug: new session should be pushed into the head of list(more fresh) + element := pder.list.PushFront(newsess) pder.sessions[sid] = element pder.lock.Unlock() return newsess, nil diff --git a/session/session.go b/session/session.go index 39d475fc..4c422906 100644 --- a/session/session.go +++ b/session/session.go @@ -201,7 +201,9 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { if err != nil || cookie.Value == "" { return } - manager.provider.SessionDestroy(cookie.Value) + // fix bug: cookie.Value has been urlencoded, so should be decoded here + sid, _ := url.QueryUnescape(cookie.Value) + manager.provider.SessionDestroy(sid) if manager.config.EnableSetCookie { expiration := time.Now() cookie = &http.Cookie{Name: manager.config.CookieName, From a144f117a3ecefe54ec5fd16f3229c47a988ca2b Mon Sep 17 00:00:00 2001 From: iexploree Date: Tue, 1 Mar 2016 13:39:36 +0800 Subject: [PATCH 17/44] remove comment --- session/sess_mem.go | 2 -- session/session.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/session/sess_mem.go b/session/sess_mem.go index 8d75d2c6..64d8b056 100644 --- a/session/sess_mem.go +++ b/session/sess_mem.go @@ -102,7 +102,6 @@ func (pder *MemProvider) SessionRead(sid string) (Store, error) { pder.lock.RUnlock() pder.lock.Lock() newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} - // fix bug: new session should be pushed into the head of list(more fresh) element := pder.list.PushFront(newsess) pder.sessions[sid] = element pder.lock.Unlock() @@ -135,7 +134,6 @@ func (pder *MemProvider) SessionRegenerate(oldsid, sid string) (Store, error) { pder.lock.RUnlock() pder.lock.Lock() newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})} - // fix bug: new session should be pushed into the head of list(more fresh) element := pder.list.PushFront(newsess) pder.sessions[sid] = element pder.lock.Unlock() diff --git a/session/session.go b/session/session.go index 4c422906..9fe99a17 100644 --- a/session/session.go +++ b/session/session.go @@ -201,7 +201,7 @@ func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { if err != nil || cookie.Value == "" { return } - // fix bug: cookie.Value has been urlencoded, so should be decoded here + sid, _ := url.QueryUnescape(cookie.Value) manager.provider.SessionDestroy(sid) if manager.config.EnableSetCookie { From 26cc040f9aa2dd354ff623a7c6c38d2883817315 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 1 Mar 2016 17:00:24 +0800 Subject: [PATCH 18/44] daily log name dot fixed --- logs/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/file.go b/logs/file.go index 990a76d8..cdea1457 100644 --- a/logs/file.go +++ b/logs/file.go @@ -218,7 +218,7 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { _, err = os.Lstat(fName) } } else { - fName = fmt.Sprintf("%s.%s.%s", w.fileNameOnly, logTime.Format("2006-01-02"), w.suffix) + fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, logTime.Format("2006-01-02"), w.suffix) _, err = os.Lstat(fName) } // return error if the last file checked still existed From 387dd6ec0e751faa82c5d911f2cfc23cfff1ba4a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 1 Mar 2016 17:12:21 +0800 Subject: [PATCH 19/44] add a line of comment --- logs/files.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/logs/files.go b/logs/files.go index 816d42e3..6a0fbd7e 100644 --- a/logs/files.go +++ b/logs/files.go @@ -55,10 +55,10 @@ func (f *filesLogWriter) Init(config string) error { f.fullLogWriter = writer f.writers[LevelDebug+1] = writer + //unmarshal "separate" field to f.Separate json.Unmarshal([]byte(config), f) jsonMap := map[string]interface{}{} - json.Unmarshal([]byte(config), &jsonMap) for i := LevelEmergency; i < LevelDebug+1; i++ { @@ -70,7 +70,6 @@ func (f *filesLogWriter) Init(config string) error { writer = newFileWriter().(*fileLogWriter) writer.Init(string(bs)) f.writers[i] = writer - fmt.Println(writer.Filename) } } } From ca3c57fbc68881d3a109dea755e11359ae8bd5dc Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 1 Mar 2016 17:13:50 +0800 Subject: [PATCH 20/44] add a line of comment --- logs/files.go | 1 - 1 file changed, 1 deletion(-) diff --git a/logs/files.go b/logs/files.go index 6a0fbd7e..b312041c 100644 --- a/logs/files.go +++ b/logs/files.go @@ -17,7 +17,6 @@ package logs import ( "encoding/json" "time" - "fmt" ) // A filesLogWriter manages several fileLogWriter From 8ff74e71cbd61556878fd822e23ba061de6bb841 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 2 Mar 2016 22:44:20 +0800 Subject: [PATCH 21/44] Fixed #1735 Return empty []string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need return empty []string if config value is empty. split `“”` ==> []string{}, Not []string{“”} --- config/ini.go | 6 +++++- config/ini_test.go | 1 + config/xml/xml.go | 6 +++++- config/xml/xml_test.go | 3 +++ config/yaml/yaml.go | 6 +++++- config/yaml/yaml_test.go | 4 ++++ 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/config/ini.go b/config/ini.go index da6f2b3a..a690ede0 100644 --- a/config/ini.go +++ b/config/ini.go @@ -270,7 +270,11 @@ func (c *IniConfigContainer) DefaultString(key string, defaultval string) string // Strings returns the []string value for a given key. func (c *IniConfigContainer) Strings(key string) []string { - return strings.Split(c.String(key), ";") + v := c.String(key) + if v == "" { + return []string{} + } + return strings.Split(v, ";") } // DefaultStrings returns the []string value for a given key. diff --git a/config/ini_test.go b/config/ini_test.go index 11063d99..93fce61f 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -71,6 +71,7 @@ peers = one;two;three "null": "", "demo2::key1": "", "error": "", + "emptystrings": []string{}, } ) diff --git a/config/xml/xml.go b/config/xml/xml.go index ffb32862..2757b0bc 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -174,7 +174,11 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string { // Strings returns the []string value for a given key. func (c *ConfigContainer) Strings(key string) []string { - return strings.Split(c.String(key), ";") + v := c.String(key) + if v == "" { + return []string{} + } + return strings.Split(v, ";") } // DefaultStrings returns the []string value for a given key. diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index fa3c17f1..308e257d 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -82,4 +82,7 @@ func TestXML(t *testing.T) { if xmlconf.String("name") != "astaxie" { t.Fatal("get name error") } + if len(xmlconf.Strings("emptystrings")) != 0 { + t.Fatal("get emtpy strings error") + } } diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index 9a96ac92..9a4fb2e9 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -211,7 +211,11 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string { // Strings returns the []string value for a given key. func (c *ConfigContainer) Strings(key string) []string { - return strings.Split(c.String(key), ";") + v := c.String(key) + if v == "" { + return []string{} + } + return strings.Split(v, ";") } // DefaultStrings returns the []string value for a given key. diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index 19ecdca1..3bbaaa32 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -79,4 +79,8 @@ func TestYaml(t *testing.T) { if yamlconf.String("name") != "astaxie" { t.Fatal("get name error") } + + if len(yamlconf.Strings("emptystrings")) != 0 { + t.Fatal("get emtpy strings error") + } } From 19d921d3f51321851ec1f301b56748f5e209077b Mon Sep 17 00:00:00 2001 From: ysqi Date: Thu, 3 Mar 2016 20:03:23 +0800 Subject: [PATCH 22/44] Return nil not empty []string{} Return nil if config value does not exist or is empty --- config/fake.go | 8 ++++++-- config/ini.go | 5 +++-- config/json.go | 4 ++-- config/xml/xml.go | 4 ++-- config/xml/xml_test.go | 2 +- config/yaml/yaml.go | 4 ++-- config/yaml/yaml_test.go | 2 +- 7 files changed, 17 insertions(+), 12 deletions(-) diff --git a/config/fake.go b/config/fake.go index 6daaca2c..7e362608 100644 --- a/config/fake.go +++ b/config/fake.go @@ -46,12 +46,16 @@ func (c *fakeConfigContainer) DefaultString(key string, defaultval string) strin } func (c *fakeConfigContainer) Strings(key string) []string { - return strings.Split(c.getData(key), ";") + v := c.getData(key) + if v == "" { + return nil + } + return strings.Split(v, ";") } func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) - if len(v) == 0 { + if v == nil { return defaultval } return v diff --git a/config/ini.go b/config/ini.go index a690ede0..9c19b9b1 100644 --- a/config/ini.go +++ b/config/ini.go @@ -269,10 +269,11 @@ func (c *IniConfigContainer) DefaultString(key string, defaultval string) string } // Strings returns the []string value for a given key. +// Return nil if config value does not exist or is empty. func (c *IniConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { - return []string{} + return nil } return strings.Split(v, ";") } @@ -281,7 +282,7 @@ func (c *IniConfigContainer) Strings(key string) []string { // if err != nil return defaltval func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) - if len(v) == 0 { + if v == nil { return defaultval } return v diff --git a/config/json.go b/config/json.go index 0bc1d456..fce517eb 100644 --- a/config/json.go +++ b/config/json.go @@ -173,7 +173,7 @@ func (c *JSONConfigContainer) DefaultString(key string, defaultval string) strin func (c *JSONConfigContainer) Strings(key string) []string { stringVal := c.String(key) if stringVal == "" { - return []string{} + return nil } return strings.Split(c.String(key), ";") } @@ -181,7 +181,7 @@ func (c *JSONConfigContainer) Strings(key string) []string { // DefaultStrings returns the []string value for a given key. // if err != nil return defaltval func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string { - if v := c.Strings(key); len(v) > 0 { + if v := c.Strings(key); v != nil { return v } return defaultval diff --git a/config/xml/xml.go b/config/xml/xml.go index 2757b0bc..b5291bf4 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -176,7 +176,7 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string { func (c *ConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { - return []string{} + return nil } return strings.Split(v, ";") } @@ -185,7 +185,7 @@ func (c *ConfigContainer) Strings(key string) []string { // if err != nil return defaltval func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) - if len(v) == 0 { + if v == nil { return defaultval } return v diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index 308e257d..60dcba54 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -82,7 +82,7 @@ func TestXML(t *testing.T) { if xmlconf.String("name") != "astaxie" { t.Fatal("get name error") } - if len(xmlconf.Strings("emptystrings")) != 0 { + if xmlconf.Strings("emptystrings") != nil { t.Fatal("get emtpy strings error") } } diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index 9a4fb2e9..7e1d0426 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -213,7 +213,7 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string { func (c *ConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { - return []string{} + return nil } return strings.Split(v, ";") } @@ -222,7 +222,7 @@ func (c *ConfigContainer) Strings(key string) []string { // if err != nil return defaltval func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) - if len(v) == 0 { + if v == nil { return defaultval } return v diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index 3bbaaa32..80cbb8fe 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -80,7 +80,7 @@ func TestYaml(t *testing.T) { t.Fatal("get name error") } - if len(yamlconf.Strings("emptystrings")) != 0 { + if yamlconf.Strings("emptystrings") != nil { t.Fatal("get emtpy strings error") } } From 3379a2b7ed6381eac5a2b5fcfb22f0a3c02dc613 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 4 Mar 2016 10:43:57 +0800 Subject: [PATCH 23/44] remove file bug fixed remove file by filename and file suffix --- logs/file.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/logs/file.go b/logs/file.go index cdea1457..9d3f78a0 100644 --- a/logs/file.go +++ b/logs/file.go @@ -256,7 +256,8 @@ func (w *fileLogWriter) deleteOldLog() { }() if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.MaxDays) { - if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) { + if strings.HasPrefix(filepath.Base(path), w.fileNameOnly) && + strings.HasSuffix(filepath.Base(path), w.suffix) { os.Remove(path) } } From 226e54e0d8d81b287a67949d9559572be5ccc363 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 4 Mar 2016 10:15:59 +0800 Subject: [PATCH 24/44] static file map race bug fixed --- staticfile.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/staticfile.go b/staticfile.go index 9534ce91..0aad2c81 100644 --- a/staticfile.go +++ b/staticfile.go @@ -93,12 +93,14 @@ type serveContentHolder struct { var ( staticFileMap = make(map[string]*serveContentHolder) - mapLock sync.Mutex + mapLock sync.RWMutex ) func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, error) { mapKey := acceptEncoding + ":" + filePath + mapLock.RLock() mapFile, _ := staticFileMap[mapKey] + mapLock.RUnlock() if isOk(mapFile, fi) { return mapFile.encoding != "", mapFile.encoding, mapFile, nil } From 8bd1be8e29d210ecb54099180c6059ce06718812 Mon Sep 17 00:00:00 2001 From: FlamingTree Date: Fri, 4 Mar 2016 11:16:47 +0800 Subject: [PATCH 25/44] Update validators.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加178号段 --- validation/validators.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/validators.go b/validation/validators.go index ebff2191..9b04c5ce 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -588,7 +588,7 @@ func (b Base64) GetLimitValue() interface{} { } // just for chinese mobile phone number -var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][0679]|[4][579]))\\d{8}$") +var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\\d{8}$") // Mobile check struct type Mobile struct { From 1f46c1d231dfe36543e99d3a28ceb87b0fefae4a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 4 Mar 2016 12:00:43 +0800 Subject: [PATCH 26/44] add template read lock when dev mode --- controller.go | 33 ++++++++++++++++++--------------- template.go | 27 +++++++++++++++++---------- template_test.go | 8 ++++---- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/controller.go b/controller.go index a2943d42..54da81ec 100644 --- a/controller.go +++ b/controller.go @@ -199,6 +199,7 @@ func (c *Controller) RenderString() (string, error) { func (c *Controller) RenderBytes() ([]byte, error) { //if the controller has set layout, then first get the tplname's content set the content to the layout var buf bytes.Buffer + var err error if c.Layout != "" { if c.TplName == "" { c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt @@ -216,13 +217,14 @@ func (c *Controller) RenderBytes() ([]byte, error) { } BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...) } - if _, ok := BeeTemplates[c.TplName]; !ok { + if t := getTemplateByName(c.TplName); t == nil { panic("can't find templatefile in the path:" + c.TplName) - } - err := BeeTemplates[c.TplName].ExecuteTemplate(&buf, c.TplName, c.Data) - if err != nil { - Trace("template Execute err:", err) - return nil, err + } else { + err = t.ExecuteTemplate(&buf, c.TplName, c.Data) + if err != nil { + Trace("template Execute err:", err) + return nil, err + } } c.Data["LayoutContent"] = template.HTML(buf.String()) @@ -234,7 +236,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - err = BeeTemplates[sectionTpl].ExecuteTemplate(&buf, sectionTpl, c.Data) + err = getTemplateByName(sectionTpl).ExecuteTemplate(&buf, sectionTpl, c.Data) if err != nil { Trace("template Execute err:", err) return nil, err @@ -244,7 +246,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - err = BeeTemplates[c.Layout].ExecuteTemplate(&buf, c.Layout, c.Data) + err = getTemplateByName(c.Layout).ExecuteTemplate(&buf, c.Layout, c.Data) if err != nil { Trace("template Execute err:", err) return nil, err @@ -258,14 +260,15 @@ func (c *Controller) RenderBytes() ([]byte, error) { if BConfig.RunMode == DEV { BuildTemplate(BConfig.WebConfig.ViewsPath, c.TplName) } - if _, ok := BeeTemplates[c.TplName]; !ok { + if t := getTemplateByName(c.TplName); t == nil { panic("can't find templatefile in the path:" + c.TplName) - } - buf.Reset() - err := BeeTemplates[c.TplName].ExecuteTemplate(&buf, c.TplName, c.Data) - if err != nil { - Trace("template Execute err:", err) - return nil, err + } else { + buf.Reset() + err = t.ExecuteTemplate(&buf, c.TplName, c.Data) + if err != nil { + Trace("template Execute err:", err) + return nil, err + } } return buf.Bytes(), nil } diff --git a/template.go b/template.go index 9954cf32..da79d383 100644 --- a/template.go +++ b/template.go @@ -30,13 +30,21 @@ import ( var ( beegoTplFuncMap = make(template.FuncMap) - // BeeTemplates caching map and supported template file extensions. - BeeTemplates = make(map[string]*template.Template) - templatesLock sync.Mutex - // BeeTemplateExt stores the template extension which will build - BeeTemplateExt = []string{"tpl", "html"} + // beeTemplates caching map and supported template file extensions. + beeTemplates = make(map[string]*template.Template) + templatesLock sync.RWMutex + // beeTemplateExt stores the template extension which will build + beeTemplateExt = []string{"tpl", "html"} ) +func getTemplateByName(name string) *template.Template { + if BConfig.RunMode == "dev" { + templatesLock.RLock() + defer templatesLock.RUnlock() + } + return beeTemplates[name] +} + func init() { beegoTplFuncMap["dateformat"] = DateFormat beegoTplFuncMap["date"] = Date @@ -55,7 +63,6 @@ func init() { beegoTplFuncMap["config"] = GetConfig beegoTplFuncMap["map_get"] = MapGet - // go1.2 added template funcs // Comparisons beegoTplFuncMap["eq"] = eq // == beegoTplFuncMap["ge"] = ge // >= @@ -103,7 +110,7 @@ func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error { // HasTemplateExt return this path contains supported template extension of beego or not. func HasTemplateExt(paths string) bool { - for _, v := range BeeTemplateExt { + for _, v := range beeTemplateExt { if strings.HasSuffix(paths, "."+v) { return true } @@ -113,12 +120,12 @@ func HasTemplateExt(paths string) bool { // AddTemplateExt add new extension for template. func AddTemplateExt(ext string) { - for _, v := range BeeTemplateExt { + for _, v := range beeTemplateExt { if v == ext { return } } - BeeTemplateExt = append(BeeTemplateExt, ext) + beeTemplateExt = append(beeTemplateExt, ext) } // BuildTemplate will build all template files in a directory. @@ -149,7 +156,7 @@ func BuildTemplate(dir string, files ...string) error { if err != nil { Trace("parse template err:", file, err) } else { - BeeTemplates[file] = t + beeTemplates[file] = t } templatesLock.Unlock() } diff --git a/template_test.go b/template_test.go index 2e222efc..4f13736c 100644 --- a/template_test.go +++ b/template_test.go @@ -70,10 +70,10 @@ func TestTemplate(t *testing.T) { if err := BuildTemplate(dir); err != nil { t.Fatal(err) } - if len(BeeTemplates) != 3 { - t.Fatalf("should be 3 but got %v", len(BeeTemplates)) + if len(beeTemplates) != 3 { + t.Fatalf("should be 3 but got %v", len(beeTemplates)) } - if err := BeeTemplates["index.tpl"].ExecuteTemplate(os.Stdout, "index.tpl", nil); err != nil { + if err := beeTemplates["index.tpl"].ExecuteTemplate(os.Stdout, "index.tpl", nil); err != nil { t.Fatal(err) } for _, name := range files { @@ -126,7 +126,7 @@ func TestRelativeTemplate(t *testing.T) { if err := BuildTemplate(dir, files[1]); err != nil { t.Fatal(err) } - if err := BeeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil { + if err := beeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil { t.Fatal(err) } for _, name := range files { From 6747c55a8115486e6fd7884e4773739cdb402a60 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 4 Mar 2016 12:01:04 +0800 Subject: [PATCH 27/44] remove unused cache --- config.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/config.go b/config.go index 876dbe01..2761e7cb 100644 --- a/config.go +++ b/config.go @@ -16,7 +16,6 @@ package beego import ( "fmt" - "html/template" "os" "path/filepath" "strings" @@ -106,8 +105,6 @@ var ( AppConfig *beegoAppConfig // AppPath is the absolute path to the app AppPath string - // TemplateCache stores template caching - TemplateCache map[string]*template.Template // GlobalSessions is the instance for the session manager GlobalSessions *session.Manager From f5adec31c65f562f8d79871d724bf7a9163173dc Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 4 Mar 2016 14:49:16 +0800 Subject: [PATCH 28/44] improve the template reader function --- controller.go | 68 ++++++++++++++------------------------------------- template.go | 14 ++++++++--- 2 files changed, 30 insertions(+), 52 deletions(-) diff --git a/controller.go b/controller.go index 54da81ec..372d8c0f 100644 --- a/controller.go +++ b/controller.go @@ -197,35 +197,9 @@ func (c *Controller) RenderString() (string, error) { // RenderBytes returns the bytes of rendered template string. Do not send out response. func (c *Controller) RenderBytes() ([]byte, error) { - //if the controller has set layout, then first get the tplname's content set the content to the layout - var buf bytes.Buffer - var err error - if c.Layout != "" { - if c.TplName == "" { - c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt - } - - if BConfig.RunMode == DEV { - buildFiles := []string{c.TplName} - if c.LayoutSections != nil { - for _, sectionTpl := range c.LayoutSections { - if sectionTpl == "" { - continue - } - buildFiles = append(buildFiles, sectionTpl) - } - } - BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...) - } - if t := getTemplateByName(c.TplName); t == nil { - panic("can't find templatefile in the path:" + c.TplName) - } else { - err = t.ExecuteTemplate(&buf, c.TplName, c.Data) - if err != nil { - Trace("template Execute err:", err) - return nil, err - } - } + buf, err := c.renderTemplate() + //if the controller has set layout, then first get the tplName's content set the content to the layout + if err == nil && c.Layout != "" { c.Data["LayoutContent"] = template.HTML(buf.String()) if c.LayoutSections != nil { @@ -234,11 +208,9 @@ func (c *Controller) RenderBytes() ([]byte, error) { c.Data[sectionName] = "" continue } - buf.Reset() - err = getTemplateByName(sectionTpl).ExecuteTemplate(&buf, sectionTpl, c.Data) + err = executeTemplate(&buf, sectionTpl, c.Data) if err != nil { - Trace("template Execute err:", err) return nil, err } c.Data[sectionName] = template.HTML(buf.String()) @@ -246,31 +218,29 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - err = getTemplateByName(c.Layout).ExecuteTemplate(&buf, c.Layout, c.Data) - if err != nil { - Trace("template Execute err:", err) - return nil, err - } - return buf.Bytes(), nil + executeTemplate(&buf, c.Layout, c.Data) } + return buf.Bytes(), err +} +func (c *Controller) renderTemplate() (bytes.Buffer, error) { + var buf bytes.Buffer if c.TplName == "" { c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt } if BConfig.RunMode == DEV { - BuildTemplate(BConfig.WebConfig.ViewsPath, c.TplName) - } - if t := getTemplateByName(c.TplName); t == nil { - panic("can't find templatefile in the path:" + c.TplName) - } else { - buf.Reset() - err = t.ExecuteTemplate(&buf, c.TplName, c.Data) - if err != nil { - Trace("template Execute err:", err) - return nil, err + buildFiles := []string{c.TplName} + if c.Layout != "" && c.LayoutSections != nil { + for _, sectionTpl := range c.LayoutSections { + if sectionTpl == "" { + continue + } + buildFiles = append(buildFiles, sectionTpl) + } } + BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...) } - return buf.Bytes(), nil + return buf, executeTemplate(&buf, c.TplName, c.Data) } // Redirect sends the redirection response to url with status code. diff --git a/template.go b/template.go index da79d383..e6c43f87 100644 --- a/template.go +++ b/template.go @@ -18,6 +18,7 @@ import ( "errors" "fmt" "html/template" + "io" "io/ioutil" "os" "path/filepath" @@ -37,12 +38,19 @@ var ( beeTemplateExt = []string{"tpl", "html"} ) -func getTemplateByName(name string) *template.Template { - if BConfig.RunMode == "dev" { +func executeTemplate(wr io.Writer, name string, data interface{}) error { + if BConfig.RunMode == DEV { templatesLock.RLock() defer templatesLock.RUnlock() } - return beeTemplates[name] + if t, ok := beeTemplates[name]; ok { + err := t.ExecuteTemplate(wr, name, data) + if err != nil { + Trace("template Execute err:", err) + } + return err + } + panic("can't find templatefile in the path:" + name) } func init() { From 292d8f2c006d66404c3270f724eda3c9dff8d93c Mon Sep 17 00:00:00 2001 From: liuchun Date: Sun, 6 Mar 2016 13:17:16 +0800 Subject: [PATCH 29/44] add ssdb cache adapter --- cache/ssdb/ssdb.go | 239 ++++++++++++++++++++++++++++++++++++++++ cache/ssdb/ssdb_test.go | 103 +++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 cache/ssdb/ssdb.go create mode 100644 cache/ssdb/ssdb_test.go diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go new file mode 100644 index 00000000..5a73aebb --- /dev/null +++ b/cache/ssdb/ssdb.go @@ -0,0 +1,239 @@ +package ssdb + +import ( + "encoding/json" + "errors" + "strconv" + "strings" + + "github.com/ssdb/gossdb/ssdb" + "time" + + "github.com/astaxie/beego/cache" +) + +// Cache SSDB adapter +type Cache struct { + conn *ssdb.Client + conninfo []string +} + +//NewSsdbCache create new ssdb adapter. +func NewSsdbCache() cache.Cache { + return &Cache{} +} + +// Get get value from memcache. +func (rc *Cache) Get(key string) interface{} { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + panic(err) + } + } + value, err := rc.conn.Get(key) + if err == nil { + return value + } + return nil +} + +// GetMulti get value from memcache. +func (rc *Cache) GetMulti(keys []string) []interface{} { + size := len(keys) + var values []interface{} + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + for i := 0; i < size; i++ { + values = append(values, err) + } + return values + } + } + res, err := rc.conn.Do("multi_get", keys) + if err == nil { + for i := 1; i < size*2; i += 2 { + values = append(values, string(res[i+1])) + } + return values + } + for i := 0; i < size; i++ { + values = append(values, err) + } + return values +} + +// DelMulti get value from memcache. +func (rc *Cache) DelMulti(keys []string) error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + _, err := rc.conn.Do("multi_del", keys) + if err != nil { + return err + } + return nil +} + +// Put put value to memcache. only support string. +func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + v, ok := value.(string) + if !ok { + return errors.New("value must string") + } + var resp []string + var err error + ttl := int(timeout / time.Second) + if ttl < 0 { + resp, err = rc.conn.Do("set", key, v) + } else { + resp, err = rc.conn.Do("setx", key, v, ttl) + } + if err != nil { + return err + } + if len(resp) == 2 && resp[0] == "ok" { + return nil + } + return errors.New("bad response") +} + +// Delete delete value in memcache. +func (rc *Cache) Delete(key string) error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + _, err := rc.conn.Del(key) + if err != nil { + return err + } + return nil +} + +// Incr increase counter. +func (rc *Cache) Incr(key string) error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + _, err := rc.conn.Do("incr", key, 1) + return err +} + +// Decr decrease counter. +func (rc *Cache) Decr(key string) error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + _, err := rc.conn.Do("incr", key, -1) + return err +} + +// IsExist check value exists in memcache. +func (rc *Cache) IsExist(key string) bool { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return false + } + } + resp, err := rc.conn.Do("exists", key) + if err != nil { + return false + } + if resp[1] == "1" { + return true + } else { + return false + } +} + +// ClearAll clear all cached in memcache. +func (rc *Cache) ClearAll() error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + key_start, key_end, limit := "", "", 50 + resp, err := rc.Scan(key_start, key_end, limit) + for err == nil { + size := len(resp) + if size == 1 { + return nil + } + keys := []string{} + for i := 1; i < size; i += 2 { + keys = append(keys, string(resp[i])) + } + _, e := rc.conn.Do("multi_del", keys) + if e != nil { + return e + } + key_start = resp[size-2] + resp, err = rc.Scan(key_start, key_end, limit) + } + return err +} + +// Scan key all cached in ssdb. +func (rc *Cache) Scan(key_start string, key_end string, limit int) ([]string, error) { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return nil, err + } + } + resp, err := rc.conn.Do("scan", key_start, key_end, limit) + if err != nil { + return nil, err + } + return resp, nil +} + +// StartAndGC start memcache adapter. +// config string is like {"conn":"connection info"}. +// if connecting error, return. +func (rc *Cache) StartAndGC(config string) error { + var cf map[string]string + json.Unmarshal([]byte(config), &cf) + if _, ok := cf["conn"]; !ok { + return errors.New("config has no conn key") + } + rc.conninfo = strings.Split(cf["conn"], ";") + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + return nil +} + +// connect to memcache and keep the connection. +func (rc *Cache) connectInit() error { + conninfo_array := strings.Split(rc.conninfo[0], ":") + host := conninfo_array[0] + port, e := strconv.Atoi(conninfo_array[1]) + if e != nil { + return e + } + var err error + rc.conn, err = ssdb.Connect(host, port) + if err != nil { + return err + } + return nil +} + +func init() { + cache.Register("ssdb", NewSsdbCache) +} diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go new file mode 100644 index 00000000..ed6d4db3 --- /dev/null +++ b/cache/ssdb/ssdb_test.go @@ -0,0 +1,103 @@ +package ssdb + +import ( + "github.com/astaxie/beego/cache" + "strconv" + "testing" + "time" +) + +func TestMemcacheCache(t *testing.T) { + ssdb, err := cache.NewCache("ssdb", `{"conn": "127.0.0.1:8888"}`) + if err != nil { + t.Error("init err") + } + + // test put and exist + if ssdb.IsExist("ssdb") { + t.Error("check err") + } + timeoutDuration := 10 * time.Second + //timeoutDuration := -10*time.Second if timeoutDuration is negtive,it means permanent + if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil { + t.Error("set Error", err) + } + if !ssdb.IsExist("ssdb") { + t.Error("check err") + } + + // Get test done + if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil { + t.Error("set Error", err) + } + + if v := ssdb.Get("ssdb"); v != "ssdb" { + t.Error("get Error") + } + + //inc/dec test done + if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil { + t.Error("set Error", err) + } + if err = ssdb.Incr("ssdb"); err != nil { + t.Error("incr Error", err) + } + + if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 { + t.Error("get err") + } + + if err = ssdb.Decr("ssdb"); err != nil { + t.Error("decr error") + } + + // test del + if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil { + t.Error("set Error", err) + } + if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 { + t.Error("get err") + } + if err := ssdb.Delete("ssdb"); err == nil { + if ssdb.IsExist("ssdb") { + t.Error("delete err") + } + } + + //test string + if err = ssdb.Put("ssdb", "ssdb", -10*time.Second); err != nil { + t.Error("set Error", err) + } + if !ssdb.IsExist("ssdb") { + t.Error("check err") + } + if v := ssdb.Get("ssdb").(string); v != "ssdb" { + t.Error("get err") + } + + //test GetMulti done + if err = ssdb.Put("ssdb1", "ssdb1", -10*time.Second); err != nil { + t.Error("set Error", err) + } + if !ssdb.IsExist("ssdb1") { + t.Error("check err") + } + vv := ssdb.GetMulti([]string{"ssdb", "ssdb1"}) + if len(vv) != 2 { + t.Error("getmulti error") + } + if vv[0].(string) != "ssdb" { + t.Error("getmulti error") + } + if vv[1].(string) != "ssdb1" { + t.Error("getmulti error") + } + + // test clear all done + if err = ssdb.ClearAll(); err != nil { + t.Error("clear all err") + } + if ssdb.IsExist("ssdb") || ssdb.IsExist("ssdb1") { + t.Error("check err") + } +} From 48ec7f736e974c35c03889b2f20547b5410d3105 Mon Sep 17 00:00:00 2001 From: liuchun Date: Sun, 6 Mar 2016 14:46:13 +0800 Subject: [PATCH 30/44] fix GetMulti bug --- cache/ssdb/ssdb.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go index 5a73aebb..d329149c 100644 --- a/cache/ssdb/ssdb.go +++ b/cache/ssdb/ssdb.go @@ -50,8 +50,9 @@ func (rc *Cache) GetMulti(keys []string) []interface{} { } } res, err := rc.conn.Do("multi_get", keys) + res_size := len(res) if err == nil { - for i := 1; i < size*2; i += 2 { + for i := 1; i < res_size; i += 2 { values = append(values, string(res[i+1])) } return values From 90344a7b8f47d8890ff3db56cab49fe10b35c986 Mon Sep 17 00:00:00 2001 From: ysqi Date: Sun, 6 Mar 2016 21:25:43 +0800 Subject: [PATCH 31/44] fix conflicts --- config.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config.go b/config.go index 4f85ce02..2761e7cb 100644 --- a/config.go +++ b/config.go @@ -16,10 +16,6 @@ package beego import ( "fmt" -<<<<<<< HEAD - "html/template" -======= ->>>>>>> astaxie/develop "os" "path/filepath" "strings" From b39830dff3886b234595a0019769f8f1bfae958d Mon Sep 17 00:00:00 2001 From: liuchun Date: Mon, 7 Mar 2016 10:31:56 +0800 Subject: [PATCH 32/44] add .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3a6c9f84..c732aac0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ install: - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - go get github.com/golang/lint/golint + - go get github.com/ssdb/gossdb/ssdb before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" From 22e3900403ae59821743bb398c861f9d0f52520a Mon Sep 17 00:00:00 2001 From: liuchun Date: Mon, 7 Mar 2016 14:34:40 +0800 Subject: [PATCH 33/44] add .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c732aac0..8c6805fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ services: - mysql - postgresql - memcached + - ssdb env: - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db - ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8" From 0caadb9b665ccc0774cc60918eada939382456f8 Mon Sep 17 00:00:00 2001 From: liuchun Date: Mon, 7 Mar 2016 14:45:45 +0800 Subject: [PATCH 34/44] rename vars --- .travis.yml | 1 - cache/ssdb/ssdb.go | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c6805fc..c732aac0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ services: - mysql - postgresql - memcached - - ssdb env: - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db - ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8" diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go index d329149c..128314a6 100644 --- a/cache/ssdb/ssdb.go +++ b/cache/ssdb/ssdb.go @@ -50,9 +50,9 @@ func (rc *Cache) GetMulti(keys []string) []interface{} { } } res, err := rc.conn.Do("multi_get", keys) - res_size := len(res) + resSize := len(res) if err == nil { - for i := 1; i < res_size; i += 2 { + for i := 1; i < resSize; i += 2 { values = append(values, string(res[i+1])) } return values @@ -154,9 +154,9 @@ func (rc *Cache) IsExist(key string) bool { } if resp[1] == "1" { return true - } else { - return false } + return false + } // ClearAll clear all cached in memcache. @@ -166,8 +166,8 @@ func (rc *Cache) ClearAll() error { return err } } - key_start, key_end, limit := "", "", 50 - resp, err := rc.Scan(key_start, key_end, limit) + keyStart, keyEnd, limit := "", "", 50 + resp, err := rc.Scan(keyStart, keyEnd, limit) for err == nil { size := len(resp) if size == 1 { @@ -181,20 +181,20 @@ func (rc *Cache) ClearAll() error { if e != nil { return e } - key_start = resp[size-2] - resp, err = rc.Scan(key_start, key_end, limit) + keyStart = resp[size-2] + resp, err = rc.Scan(keyStart, keyEnd, limit) } return err } // Scan key all cached in ssdb. -func (rc *Cache) Scan(key_start string, key_end string, limit int) ([]string, error) { +func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, error) { if rc.conn == nil { if err := rc.connectInit(); err != nil { return nil, err } } - resp, err := rc.conn.Do("scan", key_start, key_end, limit) + resp, err := rc.conn.Do("scan", keyStart, keyEnd, limit) if err != nil { return nil, err } @@ -221,9 +221,9 @@ func (rc *Cache) StartAndGC(config string) error { // connect to memcache and keep the connection. func (rc *Cache) connectInit() error { - conninfo_array := strings.Split(rc.conninfo[0], ":") - host := conninfo_array[0] - port, e := strconv.Atoi(conninfo_array[1]) + conninfoArray := strings.Split(rc.conninfo[0], ":") + host := conninfoArray[0] + port, e := strconv.Atoi(conninfoArray[1]) if e != nil { return e } From e29f4b57a3b9bc80b2ae1fd262ff7b28eefe4229 Mon Sep 17 00:00:00 2001 From: liuchun Date: Mon, 7 Mar 2016 14:53:36 +0800 Subject: [PATCH 35/44] fix travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c732aac0..ffc78d1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,7 @@ install: - go get golang.org/x/tools/cmd/vet - go get github.com/golang/lint/golint - go get github.com/ssdb/gossdb/ssdb + - go get github.com/astaxie/beego/cache before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" From 9ddc2f5474379f56d1f1f58d57cc7f0d675b9770 Mon Sep 17 00:00:00 2001 From: liuchun Date: Mon, 7 Mar 2016 15:00:03 +0800 Subject: [PATCH 36/44] fix panic err --- cache/ssdb/ssdb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go index 128314a6..0f8fdf00 100644 --- a/cache/ssdb/ssdb.go +++ b/cache/ssdb/ssdb.go @@ -27,7 +27,7 @@ func NewSsdbCache() cache.Cache { func (rc *Cache) Get(key string) interface{} { if rc.conn == nil { if err := rc.connectInit(); err != nil { - panic(err) + return nil } } value, err := rc.conn.Get(key) From 1ddb1ce2fe0c4c722d78cc7d3c1d07f4133b6a55 Mon Sep 17 00:00:00 2001 From: liuchun Date: Mon, 7 Mar 2016 15:50:13 +0800 Subject: [PATCH 37/44] add ssdb travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ffc78d1b..60ef36bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ services: - mysql - postgresql - memcached + - ssdb env: - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db - ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8" From 662bea352f598e7c8e67a16cc033b9fc4b02e1aa Mon Sep 17 00:00:00 2001 From: liuchun Date: Tue, 8 Mar 2016 12:45:54 +0800 Subject: [PATCH 38/44] modify travis --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.travis.yml b/.travis.yml index 60ef36bc..45358f36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,11 @@ env: - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db - ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8" - ORM_DRIVER=postgres ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable" +before_install: + - git clone git://github.com/ideawu/ssdb.git + - cd ssdb + - make + - cd .. install: - go get github.com/lib/pq - go get github.com/go-sql-driver/mysql @@ -35,6 +40,11 @@ before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi" + - mkdir -p res/var + - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d +after_script: + -killall -w ssdb-server + - rm -rf ./res/var/* script: - go vet -x ./... - $HOME/gopath/bin/golint ./... From 0a0fc351e7d1a747e37903ed8f7ae4195009a22e Mon Sep 17 00:00:00 2001 From: liuchun Date: Tue, 8 Mar 2016 12:59:19 +0800 Subject: [PATCH 39/44] fix ssdb_test --- cache/ssdb/ssdb_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go index ed6d4db3..e03ba343 100644 --- a/cache/ssdb/ssdb_test.go +++ b/cache/ssdb/ssdb_test.go @@ -7,7 +7,7 @@ import ( "time" ) -func TestMemcacheCache(t *testing.T) { +func TestSsdbcacheCache(t *testing.T) { ssdb, err := cache.NewCache("ssdb", `{"conn": "127.0.0.1:8888"}`) if err != nil { t.Error("init err") From 14be252d2a81c7b17d48012a3ca0b9a4adc1a480 Mon Sep 17 00:00:00 2001 From: liuchun Date: Tue, 8 Mar 2016 14:01:33 +0800 Subject: [PATCH 40/44] fix travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 45358f36..9001589e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ install: - go get golang.org/x/tools/cmd/vet - go get github.com/golang/lint/golint - go get github.com/ssdb/gossdb/ssdb - - go get github.com/astaxie/beego/cache before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" From ef59a0ed638da872643aa9a22783f3e5f5124347 Mon Sep 17 00:00:00 2001 From: liuchun Date: Tue, 8 Mar 2016 14:03:33 +0800 Subject: [PATCH 41/44] fix travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9001589e..4452012e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ services: - mysql - postgresql - memcached - - ssdb env: - ORM_DRIVER=sqlite3 ORM_SOURCE=$TRAVIS_BUILD_DIR/orm_test.db - ORM_DRIVER=mysql ORM_SOURCE="root:@/orm_test?charset=utf8" From bd04be447074094ada01a33e502d17d634166a62 Mon Sep 17 00:00:00 2001 From: liuchun Date: Tue, 8 Mar 2016 14:44:37 +0800 Subject: [PATCH 42/44] move time to the top --- cache/ssdb/ssdb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go index 0f8fdf00..bfee69ce 100644 --- a/cache/ssdb/ssdb.go +++ b/cache/ssdb/ssdb.go @@ -5,9 +5,9 @@ import ( "errors" "strconv" "strings" + "time" "github.com/ssdb/gossdb/ssdb" - "time" "github.com/astaxie/beego/cache" ) From 54b5120a647cc2f53b0ae5043e4e19d78504903a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 8 Mar 2016 18:43:09 +0800 Subject: [PATCH 43/44] rename files to mulitfile --- logs/{files.go => mulitfile.go} | 2 +- logs/{files_test.go => mulitfile_test.go} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename logs/{files.go => mulitfile.go} (98%) rename logs/{files_test.go => mulitfile_test.go} (92%) diff --git a/logs/files.go b/logs/mulitfile.go similarity index 98% rename from logs/files.go rename to logs/mulitfile.go index b312041c..599870f8 100644 --- a/logs/files.go +++ b/logs/mulitfile.go @@ -112,5 +112,5 @@ func newFilesWriter() Logger { } func init() { - Register("files", newFilesWriter) + Register("mulitfile", newFilesWriter) } diff --git a/logs/files_test.go b/logs/mulitfile_test.go similarity index 92% rename from logs/files_test.go rename to logs/mulitfile_test.go index 058ba902..5e1e3f06 100644 --- a/logs/files_test.go +++ b/logs/mulitfile_test.go @@ -24,7 +24,7 @@ import ( func TestFiles_1(t *testing.T) { log := NewLogger(10000) - log.SetLogger("files", `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`) + log.SetLogger("mulitfile", `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`) log.Debug("debug") log.Informational("info") log.Notice("notice") From b2f071395bcc3305687aa061dc1e57402f4d26fe Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 8 Mar 2016 18:44:39 +0800 Subject: [PATCH 44/44] rename files to mulitfile --- logs/mulitfile.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/logs/mulitfile.go b/logs/mulitfile.go index 599870f8..cf22f7a8 100644 --- a/logs/mulitfile.go +++ b/logs/mulitfile.go @@ -24,7 +24,7 @@ import ( // means if the file name in configuration is project.log filesLogWriter will create project.error.log/project.debug.log // and write the error-level logs to project.error.log and write the debug-level logs to project.debug.log // the rotate attribute also acts like fileLogWriter -type filesLogWriter struct { +type mulitFileLogWriter struct { writers [LevelDebug + 1 + 1]*fileLogWriter // the last one for fullLogWriter fullLogWriter *fileLogWriter Separate []string `json:"separate"` @@ -45,7 +45,7 @@ var levelNames = [...]string{"emergency", "alert", "critical", "error", "warning // "separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"], // } -func (f *filesLogWriter) Init(config string) error { +func (f *mulitFileLogWriter) Init(config string) error { writer := newFileWriter().(*fileLogWriter) err := writer.Init(config) if err != nil { @@ -76,7 +76,7 @@ func (f *filesLogWriter) Init(config string) error { return nil } -func (f *filesLogWriter) Destroy() { +func (f *mulitFileLogWriter) Destroy() { for i := 0; i < len(f.writers); i++ { if f.writers[i] != nil { f.writers[i].Destroy() @@ -84,7 +84,7 @@ func (f *filesLogWriter) Destroy() { } } -func (f *filesLogWriter) WriteMsg(when time.Time, msg string, level int) error { +func (f *mulitFileLogWriter) WriteMsg(when time.Time, msg string, level int) error { if f.fullLogWriter != nil { f.fullLogWriter.WriteMsg(when, msg, level) } @@ -98,7 +98,7 @@ func (f *filesLogWriter) WriteMsg(when time.Time, msg string, level int) error { return nil } -func (f *filesLogWriter) Flush() { +func (f *mulitFileLogWriter) Flush() { for i := 0; i < len(f.writers); i++ { if f.writers[i] != nil { f.writers[i].Flush() @@ -108,7 +108,7 @@ func (f *filesLogWriter) Flush() { // newFilesWriter create a FileLogWriter returning as LoggerInterface. func newFilesWriter() Logger { - return &filesLogWriter{} + return &mulitFileLogWriter{} } func init() {