forked from mirror/ledisdb
use go-log and adjust some param name
go-log now has a well document. it can be used directly. limit may cause confused, use count instead
This commit is contained in:
parent
94b3f335ec
commit
38f741ddb1
|
@ -2,4 +2,4 @@
|
|||
|
||||
. ./dev.sh
|
||||
|
||||
#nothing to do now
|
||||
go get -u github.com/siddontang/go-log/log
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/log"
|
||||
"github.com/siddontang/go-log/log"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
|
|
@ -3,8 +3,8 @@ package ledis
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/siddontang/go-log/log"
|
||||
"github.com/siddontang/ledisdb/leveldb"
|
||||
"github.com/siddontang/ledisdb/log"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/siddontang/ledisdb/log"
|
||||
"github.com/siddontang/go-log/log"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
|
|
@ -492,23 +492,23 @@ func (db *DB) zrank(key []byte, member []byte, reverse bool) (int64, error) {
|
|||
return -1, nil
|
||||
}
|
||||
|
||||
func (db *DB) zIterator(key []byte, min int64, max int64, offset int, limit int, reverse bool) *leveldb.RangeLimitIterator {
|
||||
func (db *DB) zIterator(key []byte, min int64, max int64, offset int, count int, reverse bool) *leveldb.RangeLimitIterator {
|
||||
minKey := db.zEncodeStartScoreKey(key, min)
|
||||
maxKey := db.zEncodeStopScoreKey(key, max)
|
||||
|
||||
if !reverse {
|
||||
return db.db.RangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
|
||||
return db.db.RangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, count)
|
||||
} else {
|
||||
return db.db.RevRangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
|
||||
return db.db.RevRangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, count)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) zRemRange(t *tx, key []byte, min int64, max int64, offset int, limit int) (int64, error) {
|
||||
func (db *DB) zRemRange(t *tx, key []byte, min int64, max int64, offset int, count int) (int64, error) {
|
||||
if len(key) > MaxKeySize {
|
||||
return 0, errKeySize
|
||||
}
|
||||
|
||||
it := db.zIterator(key, min, max, offset, limit, false)
|
||||
it := db.zIterator(key, min, max, offset, count, false)
|
||||
var num int64 = 0
|
||||
for ; it.Valid(); it.Next() {
|
||||
sk := it.Key()
|
||||
|
@ -534,7 +534,7 @@ func (db *DB) zRemRange(t *tx, key []byte, min int64, max int64, offset int, lim
|
|||
return num, nil
|
||||
}
|
||||
|
||||
func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, reverse bool) ([]ScorePair, error) {
|
||||
func (db *DB) zRange(key []byte, min int64, max int64, offset int, count int, reverse bool) ([]ScorePair, error) {
|
||||
if len(key) > MaxKeySize {
|
||||
return nil, errKeySize
|
||||
}
|
||||
|
@ -544,20 +544,20 @@ func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, re
|
|||
}
|
||||
|
||||
nv := 64
|
||||
if limit > 0 {
|
||||
nv = limit
|
||||
if count > 0 {
|
||||
nv = count
|
||||
}
|
||||
|
||||
v := make([]ScorePair, 0, nv)
|
||||
|
||||
var it *leveldb.RangeLimitIterator
|
||||
|
||||
//if reverse and offset is 0, limit < 0, we may use forward iterator then reverse
|
||||
//if reverse and offset is 0, count < 0, we may use forward iterator then reverse
|
||||
//because leveldb iterator prev is slower than next
|
||||
if !reverse || (offset == 0 && limit < 0) {
|
||||
it = db.zIterator(key, min, max, offset, limit, false)
|
||||
if !reverse || (offset == 0 && count < 0) {
|
||||
it = db.zIterator(key, min, max, offset, count, false)
|
||||
} else {
|
||||
it = db.zIterator(key, min, max, offset, limit, true)
|
||||
it = db.zIterator(key, min, max, offset, count, true)
|
||||
}
|
||||
|
||||
for ; it.Valid(); it.Next() {
|
||||
|
@ -571,7 +571,7 @@ func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, re
|
|||
}
|
||||
it.Close()
|
||||
|
||||
if reverse && (offset == 0 && limit < 0) {
|
||||
if reverse && (offset == 0 && count < 0) {
|
||||
for i, j := 0, len(v)-1; i < j; i, j = i+1, j-1 {
|
||||
v[i], v[j] = v[j], v[i]
|
||||
}
|
||||
|
@ -580,7 +580,7 @@ func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, re
|
|||
return v, nil
|
||||
}
|
||||
|
||||
func (db *DB) zParseLimit(key []byte, start int, stop int) (offset int, limit int, err error) {
|
||||
func (db *DB) zParseLimit(key []byte, start int, stop int) (offset int, count int, err error) {
|
||||
if start < 0 || stop < 0 {
|
||||
//refer redis implementation
|
||||
var size int64
|
||||
|
@ -614,7 +614,7 @@ func (db *DB) zParseLimit(key []byte, start int, stop int) (offset int, limit in
|
|||
}
|
||||
|
||||
offset = start
|
||||
limit = (stop - start) + 1
|
||||
count = (stop - start) + 1
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -663,7 +663,7 @@ func (db *DB) ZRank(key []byte, member []byte) (int64, error) {
|
|||
}
|
||||
|
||||
func (db *DB) ZRemRangeByRank(key []byte, start int, stop int) (int64, error) {
|
||||
offset, limit, err := db.zParseLimit(key, start, stop)
|
||||
offset, count, err := db.zParseLimit(key, start, stop)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -674,7 +674,7 @@ func (db *DB) ZRemRangeByRank(key []byte, start int, stop int) (int64, error) {
|
|||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
rmCnt, err = db.zRemRange(t, key, MinScore, MaxScore, offset, limit)
|
||||
rmCnt, err = db.zRemRange(t, key, MinScore, MaxScore, offset, count)
|
||||
if err == nil {
|
||||
err = t.Commit()
|
||||
}
|
||||
|
@ -711,12 +711,12 @@ func (db *DB) ZRevRangeByScore(key []byte, min int64, max int64, offset int, cou
|
|||
}
|
||||
|
||||
func (db *DB) ZRangeGeneric(key []byte, start int, stop int, reverse bool) ([]ScorePair, error) {
|
||||
offset, limit, err := db.zParseLimit(key, start, stop)
|
||||
offset, count, err := db.zParseLimit(key, start, stop)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db.zRange(key, MinScore, MaxScore, offset, limit, reverse)
|
||||
return db.zRange(key, MinScore, MaxScore, offset, count, reverse)
|
||||
}
|
||||
|
||||
//min and max must be inclusive
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//a wrapper for c++ leveldb
|
||||
package leveldb
|
||||
|
||||
/*
|
||||
|
@ -156,7 +157,7 @@ func (db *DB) initOptions(cfg *Config) {
|
|||
db.syncWriteOpts.SetSync(true)
|
||||
}
|
||||
|
||||
func (db *DB) Close() {
|
||||
func (db *DB) Close() error {
|
||||
if db.db != nil {
|
||||
C.leveldb_close(db.db)
|
||||
db.db = nil
|
||||
|
@ -176,6 +177,8 @@ func (db *DB) Close() {
|
|||
db.writeOpts.Close()
|
||||
db.iteratorOpts.Close()
|
||||
db.syncWriteOpts.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) Destroy() error {
|
||||
|
@ -274,23 +277,23 @@ func (db *DB) NewIterator() *Iterator {
|
|||
}
|
||||
|
||||
func (db *DB) RangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorForward)
|
||||
return NewRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||
}
|
||||
|
||||
func (db *DB) RevRangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorBackward)
|
||||
return NewRevRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||
}
|
||||
|
||||
//limit < 0, unlimit
|
||||
//count < 0, unlimit
|
||||
//offset must >= 0, if < 0, will get nothing
|
||||
func (db *DB) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorForward)
|
||||
func (db *DB) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||
return NewRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||
}
|
||||
|
||||
//limit < 0, unlimit
|
||||
//count < 0, unlimit
|
||||
//offset must >= 0, if < 0, will get nothing
|
||||
func (db *DB) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorBackward)
|
||||
func (db *DB) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||
return NewRevRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||
}
|
||||
|
||||
func (db *DB) put(wo *WriteOptions, key, value []byte) error {
|
||||
|
|
|
@ -35,6 +35,11 @@ type Range struct {
|
|||
Type uint8
|
||||
}
|
||||
|
||||
type Limit struct {
|
||||
Offset int
|
||||
Count int
|
||||
}
|
||||
|
||||
type Iterator struct {
|
||||
it *C.leveldb_iterator_t
|
||||
}
|
||||
|
@ -107,9 +112,7 @@ type RangeLimitIterator struct {
|
|||
it *Iterator
|
||||
|
||||
r *Range
|
||||
|
||||
offset int
|
||||
limit int
|
||||
l *Limit
|
||||
|
||||
step int
|
||||
|
||||
|
@ -126,11 +129,11 @@ func (it *RangeLimitIterator) Value() []byte {
|
|||
}
|
||||
|
||||
func (it *RangeLimitIterator) Valid() bool {
|
||||
if it.offset < 0 {
|
||||
if it.l.Offset < 0 {
|
||||
return false
|
||||
} else if !it.it.Valid() {
|
||||
return false
|
||||
} else if it.limit >= 0 && it.step >= it.limit {
|
||||
} else if it.l.Count >= 0 && it.step >= it.l.Count {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -171,19 +174,26 @@ func (it *RangeLimitIterator) Close() {
|
|||
it.it.Close()
|
||||
}
|
||||
|
||||
func newRangeLimitIterator(i *Iterator, r *Range, offset int, limit int, direction uint8) *RangeLimitIterator {
|
||||
func NewRangeLimitIterator(i *Iterator, r *Range, l *Limit) *RangeLimitIterator {
|
||||
return rangeLimitIterator(i, r, l, IteratorForward)
|
||||
}
|
||||
|
||||
func NewRevRangeLimitIterator(i *Iterator, r *Range, l *Limit) *RangeLimitIterator {
|
||||
return rangeLimitIterator(i, r, l, IteratorBackward)
|
||||
}
|
||||
|
||||
func rangeLimitIterator(i *Iterator, r *Range, l *Limit, direction uint8) *RangeLimitIterator {
|
||||
it := new(RangeLimitIterator)
|
||||
|
||||
it.it = i
|
||||
|
||||
it.r = r
|
||||
it.offset = offset
|
||||
it.limit = limit
|
||||
it.l = l
|
||||
it.direction = direction
|
||||
|
||||
it.step = 0
|
||||
|
||||
if offset < 0 {
|
||||
if l.Offset < 0 {
|
||||
return it
|
||||
}
|
||||
|
||||
|
@ -221,7 +231,7 @@ func newRangeLimitIterator(i *Iterator, r *Range, offset int, limit int, directi
|
|||
}
|
||||
}
|
||||
|
||||
for i := 0; i < offset; i++ {
|
||||
for i := 0; i < l.Offset; i++ {
|
||||
if it.it.Valid() {
|
||||
if it.direction == IteratorForward {
|
||||
it.it.Next()
|
||||
|
|
|
@ -34,21 +34,21 @@ func (s *Snapshot) NewIterator() *Iterator {
|
|||
}
|
||||
|
||||
func (s *Snapshot) RangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorForward)
|
||||
return NewRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||
}
|
||||
|
||||
func (s *Snapshot) RevRangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorBackward)
|
||||
return NewRevRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||
}
|
||||
|
||||
//limit < 0, unlimit
|
||||
//count < 0, unlimit
|
||||
//offset must >= 0, if < 0, will get nothing
|
||||
func (s *Snapshot) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorForward)
|
||||
func (s *Snapshot) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||
return NewRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||
}
|
||||
|
||||
//limit < 0, unlimit
|
||||
//count < 0, unlimit
|
||||
//offset must >= 0, if < 0, will get nothing
|
||||
func (s *Snapshot) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorBackward)
|
||||
func (s *Snapshot) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||
return NewRevRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||
}
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FileHandler struct {
|
||||
fd *os.File
|
||||
}
|
||||
|
||||
func NewFileHandler(fileName string, flag int) (*FileHandler, error) {
|
||||
dir := path.Dir(fileName)
|
||||
os.Mkdir(dir, 0777)
|
||||
|
||||
f, err := os.OpenFile(fileName, flag, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := new(FileHandler)
|
||||
|
||||
h.fd = f
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *FileHandler) Write(b []byte) (n int, err error) {
|
||||
return h.fd.Write(b)
|
||||
}
|
||||
|
||||
func (h *FileHandler) Close() error {
|
||||
return h.fd.Close()
|
||||
}
|
||||
|
||||
type RotatingFileHandler struct {
|
||||
fd *os.File
|
||||
|
||||
fileName string
|
||||
maxBytes int
|
||||
backupCount int
|
||||
}
|
||||
|
||||
func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) {
|
||||
dir := path.Dir(fileName)
|
||||
os.Mkdir(dir, 0777)
|
||||
|
||||
h := new(RotatingFileHandler)
|
||||
|
||||
if maxBytes <= 0 {
|
||||
return nil, fmt.Errorf("invalid max bytes")
|
||||
}
|
||||
|
||||
h.fileName = fileName
|
||||
h.maxBytes = maxBytes
|
||||
h.backupCount = backupCount
|
||||
|
||||
var err error
|
||||
h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *RotatingFileHandler) Write(p []byte) (n int, err error) {
|
||||
h.doRollover()
|
||||
return h.fd.Write(p)
|
||||
}
|
||||
|
||||
func (h *RotatingFileHandler) Close() error {
|
||||
if h.fd != nil {
|
||||
return h.fd.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *RotatingFileHandler) doRollover() {
|
||||
f, err := h.fd.Stat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if h.maxBytes <= 0 {
|
||||
return
|
||||
} else if f.Size() < int64(h.maxBytes) {
|
||||
return
|
||||
}
|
||||
|
||||
if h.backupCount > 0 {
|
||||
h.fd.Close()
|
||||
|
||||
for i := h.backupCount - 1; i > 0; i-- {
|
||||
sfn := fmt.Sprintf("%s.%d", h.fileName, i)
|
||||
dfn := fmt.Sprintf("%s.%d", h.fileName, i+1)
|
||||
|
||||
os.Rename(sfn, dfn)
|
||||
}
|
||||
|
||||
dfn := fmt.Sprintf("%s.1", h.fileName)
|
||||
os.Rename(h.fileName, dfn)
|
||||
|
||||
h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
}
|
||||
}
|
||||
|
||||
//refer: http://docs.python.org/2/library/logging.handlers.html
|
||||
//same like python TimedRotatingFileHandler
|
||||
|
||||
type TimeRotatingFileHandler struct {
|
||||
fd *os.File
|
||||
|
||||
baseName string
|
||||
interval int64
|
||||
suffix string
|
||||
rolloverAt int64
|
||||
}
|
||||
|
||||
const (
|
||||
WhenSecond = iota
|
||||
WhenMinute
|
||||
WhenHour
|
||||
WhenDay
|
||||
)
|
||||
|
||||
func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
|
||||
dir := path.Dir(baseName)
|
||||
os.Mkdir(dir, 0777)
|
||||
|
||||
h := new(TimeRotatingFileHandler)
|
||||
|
||||
h.baseName = baseName
|
||||
|
||||
switch when {
|
||||
case WhenSecond:
|
||||
h.interval = 1
|
||||
h.suffix = "2006-01-02_15-04-05"
|
||||
case WhenMinute:
|
||||
h.interval = 60
|
||||
h.suffix = "2006-01-02_15-04"
|
||||
case WhenHour:
|
||||
h.interval = 3600
|
||||
h.suffix = "2006-01-02_15"
|
||||
case WhenDay:
|
||||
h.interval = 3600 * 24
|
||||
h.suffix = "2006-01-02"
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid when_rotate: %d", when)
|
||||
}
|
||||
|
||||
h.interval = h.interval * int64(interval)
|
||||
|
||||
var err error
|
||||
h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fInfo, _ := h.fd.Stat()
|
||||
h.rolloverAt = fInfo.ModTime().Unix() + h.interval
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *TimeRotatingFileHandler) doRollover() {
|
||||
//refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
|
||||
now := time.Now()
|
||||
|
||||
if h.rolloverAt <= now.Unix() {
|
||||
fName := h.baseName + now.Format(h.suffix)
|
||||
h.fd.Close()
|
||||
e := os.Rename(h.baseName, fName)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
|
||||
h.rolloverAt = time.Now().Unix() + h.interval
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
|
||||
h.doRollover()
|
||||
return h.fd.Write(b)
|
||||
}
|
||||
|
||||
func (h *TimeRotatingFileHandler) Close() error {
|
||||
return h.fd.Close()
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type Handler interface {
|
||||
Write(p []byte) (n int, err error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
type StreamHandler struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func NewStreamHandler(w io.Writer) (*StreamHandler, error) {
|
||||
h := new(StreamHandler)
|
||||
|
||||
h.w = w
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *StreamHandler) Write(b []byte) (n int, err error) {
|
||||
return h.w.Write(b)
|
||||
}
|
||||
|
||||
func (h *StreamHandler) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullHandler struct {
|
||||
}
|
||||
|
||||
func NewNullHandler() (*NullHandler, error) {
|
||||
return new(NullHandler), nil
|
||||
}
|
||||
|
||||
func (h *NullHandler) Write(b []byte) (n int, err error) {
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (h *NullHandler) Close() {
|
||||
|
||||
}
|
226
log/log.go
226
log/log.go
|
@ -1,226 +0,0 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
LevelTrace = iota
|
||||
LevelDebug
|
||||
LevelInfo
|
||||
LevelWarn
|
||||
LevelError
|
||||
LevelFatal
|
||||
)
|
||||
|
||||
const (
|
||||
Ltime = 1 << iota //time format "2006/01/02 15:04:05"
|
||||
Lfile //file.go:123
|
||||
Llevel //[Trace|Debug|Info...]
|
||||
)
|
||||
|
||||
var LevelName [6]string = [6]string{"Trace", "Debug", "Info", "Warn", "Error", "Fatal"}
|
||||
|
||||
const TimeFormat = "2006/01/02 15:04:05"
|
||||
|
||||
const maxBufPoolSize = 16
|
||||
|
||||
type Logger struct {
|
||||
sync.Mutex
|
||||
|
||||
level int
|
||||
flag int
|
||||
|
||||
handler Handler
|
||||
|
||||
quit chan struct{}
|
||||
msg chan []byte
|
||||
|
||||
bufs [][]byte
|
||||
}
|
||||
|
||||
func New(handler Handler, flag int) *Logger {
|
||||
var l = new(Logger)
|
||||
|
||||
l.level = LevelInfo
|
||||
l.handler = handler
|
||||
|
||||
l.flag = flag
|
||||
|
||||
l.quit = make(chan struct{})
|
||||
|
||||
l.msg = make(chan []byte, 1024)
|
||||
|
||||
l.bufs = make([][]byte, 0, 16)
|
||||
|
||||
go l.run()
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func NewDefault(handler Handler) *Logger {
|
||||
return New(handler, Ltime|Lfile|Llevel)
|
||||
}
|
||||
|
||||
func newStdHandler() *StreamHandler {
|
||||
h, _ := NewStreamHandler(os.Stdout)
|
||||
return h
|
||||
}
|
||||
|
||||
var std = NewDefault(newStdHandler())
|
||||
|
||||
func (l *Logger) run() {
|
||||
for {
|
||||
select {
|
||||
case msg := <-l.msg:
|
||||
l.handler.Write(msg)
|
||||
l.putBuf(msg)
|
||||
case <-l.quit:
|
||||
l.handler.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) popBuf() []byte {
|
||||
l.Lock()
|
||||
var buf []byte
|
||||
if len(l.bufs) == 0 {
|
||||
buf = make([]byte, 0, 1024)
|
||||
} else {
|
||||
buf = l.bufs[len(l.bufs)-1]
|
||||
l.bufs = l.bufs[0 : len(l.bufs)-1]
|
||||
}
|
||||
l.Unlock()
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
func (l *Logger) putBuf(buf []byte) {
|
||||
l.Lock()
|
||||
if len(l.bufs) < maxBufPoolSize {
|
||||
buf = buf[0:0]
|
||||
l.bufs = append(l.bufs, buf)
|
||||
}
|
||||
l.Unlock()
|
||||
}
|
||||
|
||||
func (l *Logger) Close() {
|
||||
if l.quit == nil {
|
||||
return
|
||||
}
|
||||
|
||||
close(l.quit)
|
||||
l.quit = nil
|
||||
}
|
||||
|
||||
func (l *Logger) SetLevel(level int) {
|
||||
l.level = level
|
||||
}
|
||||
|
||||
func (l *Logger) Output(callDepth int, level int, format string, v ...interface{}) {
|
||||
if l.level > level {
|
||||
return
|
||||
}
|
||||
|
||||
buf := l.popBuf()
|
||||
|
||||
if l.flag&Ltime > 0 {
|
||||
now := time.Now().Format(TimeFormat)
|
||||
buf = append(buf, '[')
|
||||
buf = append(buf, now...)
|
||||
buf = append(buf, "] "...)
|
||||
}
|
||||
|
||||
if l.flag&Lfile > 0 {
|
||||
_, file, line, ok := runtime.Caller(callDepth)
|
||||
if !ok {
|
||||
file = "???"
|
||||
line = 0
|
||||
} else {
|
||||
for i := len(file) - 1; i > 0; i-- {
|
||||
if file[i] == '/' {
|
||||
file = file[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf = append(buf, file...)
|
||||
buf = append(buf, ':')
|
||||
|
||||
strconv.AppendInt(buf, int64(line), 10)
|
||||
}
|
||||
|
||||
if l.flag&Llevel > 0 {
|
||||
buf = append(buf, '[')
|
||||
buf = append(buf, LevelName[level]...)
|
||||
buf = append(buf, "] "...)
|
||||
}
|
||||
|
||||
s := fmt.Sprintf(format, v...)
|
||||
|
||||
buf = append(buf, s...)
|
||||
|
||||
if s[len(s)-1] != '\n' {
|
||||
buf = append(buf, '\n')
|
||||
}
|
||||
|
||||
l.msg <- buf
|
||||
}
|
||||
|
||||
func (l *Logger) Trace(format string, v ...interface{}) {
|
||||
l.Output(2, LevelTrace, format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(format string, v ...interface{}) {
|
||||
l.Output(2, LevelDebug, format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Info(format string, v ...interface{}) {
|
||||
l.Output(2, LevelInfo, format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Warn(format string, v ...interface{}) {
|
||||
l.Output(2, LevelWarn, format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Error(format string, v ...interface{}) {
|
||||
l.Output(2, LevelError, format, v...)
|
||||
}
|
||||
|
||||
func (l *Logger) Fatal(format string, v ...interface{}) {
|
||||
l.Output(2, LevelFatal, format, v...)
|
||||
}
|
||||
|
||||
func SetLevel(level int) {
|
||||
std.SetLevel(level)
|
||||
}
|
||||
|
||||
func Trace(format string, v ...interface{}) {
|
||||
std.Output(2, LevelTrace, format, v...)
|
||||
}
|
||||
|
||||
func Debug(format string, v ...interface{}) {
|
||||
std.Output(2, LevelDebug, format, v...)
|
||||
}
|
||||
|
||||
func Info(format string, v ...interface{}) {
|
||||
std.Output(2, LevelInfo, format, v...)
|
||||
}
|
||||
|
||||
func Warn(format string, v ...interface{}) {
|
||||
std.Output(2, LevelWarn, format, v...)
|
||||
}
|
||||
|
||||
func Error(format string, v ...interface{}) {
|
||||
std.Output(2, LevelError, format, v...)
|
||||
}
|
||||
|
||||
func Fatal(format string, v ...interface{}) {
|
||||
std.Output(2, LevelFatal, format, v...)
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStdStreamLog(t *testing.T) {
|
||||
h, _ := NewStreamHandler(os.Stdout)
|
||||
s := NewDefault(h)
|
||||
s.Info("hello world")
|
||||
|
||||
s.Close()
|
||||
|
||||
Info("hello world")
|
||||
}
|
||||
|
||||
func TestRotatingFileLog(t *testing.T) {
|
||||
path := "./test_log"
|
||||
os.RemoveAll(path)
|
||||
|
||||
os.Mkdir(path, 0777)
|
||||
fileName := path + "/test"
|
||||
|
||||
h, err := NewRotatingFileHandler(fileName, 10, 2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf := make([]byte, 10)
|
||||
|
||||
h.Write(buf)
|
||||
|
||||
h.Write(buf)
|
||||
|
||||
if _, err := os.Stat(fileName + ".1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(fileName + ".2"); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h.Write(buf)
|
||||
if _, err := os.Stat(fileName + ".2"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h.Close()
|
||||
|
||||
os.RemoveAll(path)
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SocketHandler struct {
|
||||
c net.Conn
|
||||
protocol string
|
||||
addr string
|
||||
}
|
||||
|
||||
func NewSocketHandler(protocol string, addr string) (*SocketHandler, error) {
|
||||
s := new(SocketHandler)
|
||||
|
||||
s.protocol = protocol
|
||||
s.addr = addr
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (h *SocketHandler) Write(p []byte) (n int, err error) {
|
||||
if err = h.connect(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, len(p)+4)
|
||||
|
||||
binary.BigEndian.PutUint32(buf, uint32(len(p)))
|
||||
|
||||
copy(buf[4:], p)
|
||||
|
||||
n, err = h.c.Write(buf)
|
||||
if err != nil {
|
||||
h.c.Close()
|
||||
h.c = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (h *SocketHandler) Close() error {
|
||||
if h.c != nil {
|
||||
h.c.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SocketHandler) connect() error {
|
||||
if h.c != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
h.c, err = net.DialTimeout(h.protocol, h.addr, 20*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/log"
|
||||
"github.com/siddontang/go-log/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/siddontang/go-log/log"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"github.com/siddontang/ledisdb/log"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/siddontang/go-log/log"
|
||||
"github.com/siddontang/ledisdb/ledis"
|
||||
"github.com/siddontang/ledisdb/log"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
|
|
Loading…
Reference in New Issue