diff --git a/app.go b/app.go index 67fea98c..f17d9a74 100644 --- a/app.go +++ b/app.go @@ -39,7 +39,7 @@ func (app *App) Run() { l, err = net.Listen("tcp", addr) } if err != nil { - BeeLogger.Fatal("Listen: ", err) + BeeLogger.Critical("Listen: ", err) } err = fcgi.Serve(l, app.Handlers) } else { @@ -51,7 +51,7 @@ func (app *App) Run() { } laddr, err := net.ResolveTCPAddr("tcp", addr) if nil != err { - BeeLogger.Fatal("ResolveTCPAddr:", err) + BeeLogger.Critical("ResolveTCPAddr:", err) } l, err = GetInitListner(laddr) theStoppable = newStoppable(l) @@ -73,7 +73,7 @@ func (app *App) Run() { } } if err != nil { - BeeLogger.Fatal("ListenAndServe: ", err) + BeeLogger.Critical("ListenAndServe: ", err) } } diff --git a/cache.go b/cache.go deleted file mode 100644 index f5e05e25..00000000 --- a/cache.go +++ /dev/null @@ -1,133 +0,0 @@ -package beego - -import ( - "errors" - "fmt" - "strconv" - "sync" - "time" -) - -var ( - DefaultEvery int = 60 // 1 minute -) - -type BeeItem struct { - val interface{} - Lastaccess time.Time - expired int -} - -func (itm *BeeItem) Access() interface{} { - itm.Lastaccess = time.Now() - return itm.val -} - -type BeeCache struct { - lock sync.RWMutex - dur time.Duration - items map[string]*BeeItem - Every int // Run an expiration check Every seconds -} - -// NewDefaultCache returns a new FileCache with sane defaults. -func NewBeeCache() *BeeCache { - cache := BeeCache{dur: time.Since(time.Now()), - Every: DefaultEvery} - return &cache -} - -func (bc *BeeCache) Get(name string) interface{} { - bc.lock.RLock() - defer bc.lock.RUnlock() - itm, ok := bc.items[name] - if !ok { - return nil - } - return itm.Access() -} - -func (bc *BeeCache) Put(name string, value interface{}, expired int) error { - bc.lock.Lock() - defer bc.lock.Unlock() - t := BeeItem{val: value, Lastaccess: time.Now(), expired: expired} - if _, ok := bc.items[name]; ok { - return errors.New("the key is exist") - } else { - bc.items[name] = &t - } - return nil -} - -func (bc *BeeCache) Delete(name string) (ok bool, err error) { - bc.lock.Lock() - defer bc.lock.Unlock() - if _, ok = bc.items[name]; !ok { - return - } - delete(bc.items, name) - _, valid := bc.items[name] - if valid { - ok = false - } - return -} - -// Return all of the item in a BeeCache -func (bc *BeeCache) Items() map[string]*BeeItem { - return bc.items -} - -func (bc *BeeCache) IsExist(name string) bool { - bc.lock.RLock() - defer bc.lock.RUnlock() - _, ok := bc.items[name] - return ok -} - -// Start activates the file cache; it will -func (bc *BeeCache) Start() error { - dur, err := time.ParseDuration(fmt.Sprintf("%ds", bc.Every)) - if err != nil { - return err - } - bc.dur = dur - bc.items = make(map[string]*BeeItem, 0) - go bc.vaccuum() - return nil -} - -func (bc *BeeCache) vaccuum() { - if bc.Every < 1 { - return - } - for { - <-time.After(time.Duration(bc.dur)) - if bc.items == nil { - return - } - for name, _ := range bc.items { - bc.item_expired(name) - } - } -} - -// item_expired returns true if an item is expired. -func (bc *BeeCache) item_expired(name string) bool { - bc.lock.Lock() - defer bc.lock.Unlock() - itm, ok := bc.items[name] - if !ok { - return true - } - dur := time.Now().Sub(itm.Lastaccess) - sec, err := strconv.Atoi(fmt.Sprintf("%0.0f", dur.Seconds())) - if err != nil { - delete(bc.items, name) - return true - } else if sec >= itm.expired { - delete(bc.items, name) - return true - } - return false -} diff --git a/context.go b/context.go deleted file mode 100644 index 3b3c7c15..00000000 --- a/context.go +++ /dev/null @@ -1,129 +0,0 @@ -package beego - -import ( - "bytes" - "fmt" - "mime" - "net/http" - "strings" -) - -type Context struct { - ResponseWriter http.ResponseWriter - Request *http.Request - RequestBody []byte - Params map[string]string -} - -func (ctx *Context) WriteString(content string) { - ctx.ResponseWriter.Write([]byte(content)) -} - -func (ctx *Context) Abort(status int, body string) { - ctx.ResponseWriter.WriteHeader(status) - ctx.ResponseWriter.Write([]byte(body)) -} - -func (ctx *Context) Redirect(status int, url_ string) { - ctx.ResponseWriter.Header().Set("Location", url_) - ctx.ResponseWriter.WriteHeader(status) -} - -func (ctx *Context) NotModified() { - ctx.ResponseWriter.WriteHeader(304) -} - -func (ctx *Context) NotFound(message string) { - ctx.ResponseWriter.WriteHeader(404) - ctx.ResponseWriter.Write([]byte(message)) -} - -//Sets the content type by extension, as defined in the mime package. -//For example, ctx.ContentType("json") sets the content-type to "application/json" -func (ctx *Context) ContentType(ext string) { - if !strings.HasPrefix(ext, ".") { - ext = "." + ext - } - ctype := mime.TypeByExtension(ext) - if ctype != "" { - ctx.ResponseWriter.Header().Set("Content-Type", ctype) - } -} - -func (ctx *Context) SetHeader(hdr string, val string, unique bool) { - if unique { - ctx.ResponseWriter.Header().Set(hdr, val) - } else { - ctx.ResponseWriter.Header().Add(hdr, val) - } -} - -//Sets a cookie -- duration is the amount of time in seconds. 0 = forever - -//params: -//string name -//string value -//int64 expire = 0 -//string $path -//string $domain -//bool $secure = false -//bool $httponly = false -func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { - var b bytes.Buffer - fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) - if len(others) > 0 { - switch others[0].(type) { - case int: - if others[0].(int) > 0 { - fmt.Fprintf(&b, "; Max-Age=%d", others[0].(int)) - } else if others[0].(int) < 0 { - fmt.Fprintf(&b, "; Max-Age=0") - } - case int64: - if others[0].(int64) > 0 { - fmt.Fprintf(&b, "; Max-Age=%d", others[0].(int64)) - } else if others[0].(int64) < 0 { - fmt.Fprintf(&b, "; Max-Age=0") - } - case int32: - if others[0].(int32) > 0 { - fmt.Fprintf(&b, "; Max-Age=%d", others[0].(int32)) - } else if others[0].(int32) < 0 { - fmt.Fprintf(&b, "; Max-Age=0") - } - } - } - if len(others) > 1 { - fmt.Fprintf(&b, "; Path=%s", sanitizeValue(others[1].(string))) - } - if len(others) > 2 { - fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(others[2].(string))) - } - if len(others) > 3 { - fmt.Fprintf(&b, "; Secure") - } - if len(others) > 4 { - fmt.Fprintf(&b, "; HttpOnly") - } - ctx.SetHeader("Set-Cookie", b.String(), false) -} - -var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") - -func sanitizeName(n string) string { - return cookieNameSanitizer.Replace(n) -} - -var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ") - -func sanitizeValue(v string) string { - return cookieValueSanitizer.Replace(v) -} - -func (ctx *Context) GetCookie(key string) string { - keycookie, err := ctx.Request.Cookie(key) - if err != nil { - return "" - } - return keycookie.Value -} diff --git a/controller.go b/controller.go index 3a0909b7..3e85d813 100644 --- a/controller.go +++ b/controller.go @@ -36,7 +36,7 @@ type Controller struct { } type ControllerInterface interface { - Init(ct *Context, childName string) + Init(ct *context.Context, childName string) Prepare() Get() Post() diff --git a/log.go b/log.go index 7e0e84b2..6f768f7d 100644 --- a/log.go +++ b/log.go @@ -1,215 +1,9 @@ package beego import ( - "fmt" - "io/ioutil" - "log" - "os" - "path" - "path/filepath" - "strings" - "sync" - "time" + "github.com/astaxie/beego/logs" ) -type FileLogWriter struct { - *log.Logger - mw *MuxWriter - // The opened file - filename string - - maxlines int - maxlines_curlines int - - // Rotate at size - maxsize int - maxsize_cursize int - - // Rotate daily - daily bool - maxdays int64 - daily_opendate int - - rotate bool - - startLock sync.Mutex // Only one log can write to the file -} - -type MuxWriter struct { - sync.Mutex - fd *os.File -} - -func (l *MuxWriter) Write(b []byte) (int, error) { - l.Lock() - defer l.Unlock() - return l.fd.Write(b) -} - -func (l *MuxWriter) SetFd(fd *os.File) { - if l.fd != nil { - l.fd.Close() - } - l.fd = fd -} - -func NewFileWriter(fname string, rotate bool) *FileLogWriter { - w := &FileLogWriter{ - filename: fname, - maxlines: 1000000, - maxsize: 1 << 28, //256 MB - daily: true, - maxdays: 7, - rotate: rotate, - } - // use MuxWriter instead direct use os.File for lock write when rotate - w.mw = new(MuxWriter) - // set MuxWriter as Logger's io.Writer - w.Logger = log.New(w.mw, "", log.Ldate|log.Ltime) - return w -} - -// Set rotate at linecount (chainable). Must be called before call StartLogger -func (w *FileLogWriter) SetRotateLines(maxlines int) *FileLogWriter { - w.maxlines = maxlines - return w -} - -// Set rotate at size (chainable). Must be called before call StartLogger -func (w *FileLogWriter) SetRotateSize(maxsize int) *FileLogWriter { - w.maxsize = maxsize - return w -} - -// Set rotate daily (chainable). Must be called before call StartLogger -func (w *FileLogWriter) SetRotateDaily(daily bool) *FileLogWriter { - w.daily = daily - return w -} - -// Set rotate daily's log keep for maxdays, other will delete -func (w *FileLogWriter) SetRotateMaxDays(maxdays int64) *FileLogWriter { - w.maxdays = maxdays - return w -} - -func (w *FileLogWriter) StartLogger() error { - fd, err := w.createLogFile() - if err != nil { - return err - } - w.mw.SetFd(fd) - err = w.initFd() - if err != nil { - return err - } - BeeLogger = w - return nil -} - -func (w *FileLogWriter) docheck(size int) { - w.startLock.Lock() - defer w.startLock.Unlock() - if (w.maxlines > 0 && w.maxlines_curlines >= w.maxlines) || - (w.maxsize > 0 && w.maxsize_cursize >= w.maxsize) || - (w.daily && time.Now().Day() != w.daily_opendate) { - if err := w.DoRotate(); err != nil { - fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.filename, err) - return - } - } - w.maxlines_curlines++ - w.maxsize_cursize += size -} - -func (w *FileLogWriter) Printf(format string, v ...interface{}) { - // Perform the write - str := fmt.Sprintf(format, v...) - n := 24 + len(str) // 24 stand for the length "2013/06/23 21:00:22 [T] " - - w.docheck(n) - w.Logger.Printf(format, v...) -} - -func (w *FileLogWriter) createLogFile() (*os.File, error) { - // Open the log file - fd, err := os.OpenFile(w.filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) - return fd, err -} - -func (w *FileLogWriter) initFd() error { - fd := w.mw.fd - finfo, err := fd.Stat() - if err != nil { - return fmt.Errorf("get stat err: %s\n", err) - } - w.maxsize_cursize = int(finfo.Size()) - w.daily_opendate = time.Now().Day() - if finfo.Size() > 0 { - content, err := ioutil.ReadFile(w.filename) - if err != nil { - fmt.Println(err) - } - w.maxlines_curlines = len(strings.Split(string(content), "\n")) - } else { - w.maxlines_curlines = 0 - } - return nil -} - -func (w *FileLogWriter) DoRotate() error { - _, err := os.Lstat(w.filename) - if err == nil { // file exists - // Find the next available number - num := 1 - fname := "" - for ; err == nil && num <= 999; num++ { - fname = w.filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num) - _, err = os.Lstat(fname) - } - // return error if the last file checked still existed - if err == nil { - return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.filename) - } - - // block Logger's io.Writer - w.mw.Lock() - defer w.mw.Unlock() - - fd := w.mw.fd - fd.Close() - - // close fd before rename - // Rename the file to its newfound home - err = os.Rename(w.filename, fname) - if err != nil { - return fmt.Errorf("Rotate: %s\n", err) - } - - // re-start logger - err = w.StartLogger() - if err != nil { - return fmt.Errorf("Rotate StartLogger: %s\n", err) - } - - go w.deleteOldLog() - } - - return nil -} - -func (w *FileLogWriter) deleteOldLog() { - dir := path.Dir(w.filename) - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.maxdays) { - if strings.HasPrefix(filepath.Base(path), filepath.Base(w.filename)) { - os.Remove(path) - } - } - return nil - }) -} - // Log levels to control the logging output. const ( LevelTrace = iota @@ -220,88 +14,51 @@ const ( LevelCritical ) -// logLevel controls the global log level used by the logger. -var level = LevelTrace - -// LogLevel returns the global log level and can be used in -// own implementations of the logger interface. -func Level() int { - return level -} - // SetLogLevel sets the global log level used by the simple // logger. func SetLevel(l int) { - level = l -} - -type IBeeLogger interface { - Fatal(v ...interface{}) - Fatalf(format string, v ...interface{}) - Fatalln(v ...interface{}) - Flags() int - Output(calldepth int, s string) error - Panic(v ...interface{}) - Panicf(format string, v ...interface{}) - Panicln(v ...interface{}) - Prefix() string - Print(v ...interface{}) - Printf(format string, v ...interface{}) - Println(v ...interface{}) - SetFlags(flag int) - SetPrefix(prefix string) + BeeLogger.SetLevel(l) } // logger references the used application logger. -var BeeLogger IBeeLogger +var BeeLogger *logs.BeeLogger func init() { - BeeLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime) + BeeLogger = logs.NewLogger(10000) + BeeLogger.SetLogger("console", "") } // SetLogger sets a new logger. -func SetLogger(l *log.Logger) { - BeeLogger = l +func SetLogger(adaptername string, config string) { + BeeLogger.SetLogger(adaptername, config) } // Trace logs a message at trace level. func Trace(v ...interface{}) { - if level <= LevelTrace { - BeeLogger.Printf("[T] %v\n", v) - } + BeeLogger.Trace("%v", v...) } // Debug logs a message at debug level. func Debug(v ...interface{}) { - if level <= LevelDebug { - BeeLogger.Printf("[D] %v\n", v) - } + BeeLogger.Debug("%v", v...) } // Info logs a message at info level. func Info(v ...interface{}) { - if level <= LevelInfo { - BeeLogger.Printf("[I] %v\n", v) - } + BeeLogger.Info("%v", v...) } // Warning logs a message at warning level. func Warn(v ...interface{}) { - if level <= LevelWarning { - BeeLogger.Printf("[W] %v\n", v) - } + BeeLogger.Warn("%v", v...) } // Error logs a message at error level. func Error(v ...interface{}) { - if level <= LevelError { - BeeLogger.Printf("[E] %v\n", v) - } + BeeLogger.Error("%v", v...) } // Critical logs a message at critical level. func Critical(v ...interface{}) { - if level <= LevelCritical { - BeeLogger.Printf("[C] %v\n", v) - } + BeeLogger.Critical("%v", v...) }