mirror of
https://github.com/eiblog/eiblog.git
synced 2026-02-09 16:12:26 +08:00
update vendor
This commit is contained in:
1
vendor/github.com/deepzz0/logd/.gitignore
generated
vendored
Normal file
1
vendor/github.com/deepzz0/logd/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
149
vendor/github.com/deepzz0/logd/README.md
generated
vendored
Normal file
149
vendor/github.com/deepzz0/logd/README.md
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
# Logd
|
||||
高性能日志系统:每日24时自动打包前一天数据,自动删除过期数据(30天),自动邮件告警。
|
||||
|
||||
#### Bechmark
|
||||
```
|
||||
BenchmarkLogFileChan-8 500000 2265 ns/op
|
||||
BenchmarkLogFile-8 300000 4393 ns/op
|
||||
BenchmarkStandardFile-8 1000000 2216 ns/op
|
||||
|
||||
BenchmarkLogFileChanMillion-8 1000000 2319 ns/op
|
||||
BenchmarkLogFileMillion-8 1000000 4397 ns/op
|
||||
BenchmarkStandardFileMillion-8 1000000 2232 ns/op
|
||||
```
|
||||
|
||||
#### Print Level
|
||||
```
|
||||
Ldebug = 1 << iota //
|
||||
Linfo //
|
||||
Lwarn //
|
||||
Lerror //
|
||||
Lfatal //
|
||||
|
||||
logd.Printf()
|
||||
logd.Print()
|
||||
logd.Debugf()
|
||||
logd.Debug()
|
||||
logd.Infof()
|
||||
logd.Info()
|
||||
logd.Warnf()
|
||||
logd.Warn()
|
||||
logd.Errorf()
|
||||
logd.Error()
|
||||
logd.Fatalf()
|
||||
logd.Fatal()
|
||||
```
|
||||
5种日志等级,12种打印方法,完全理解你记录日志的需求。
|
||||
|
||||
```
|
||||
Ldebug < Linfo < Lwarn < Lerror < Lfatal
|
||||
```
|
||||
通过`SetLevel()`方法设置,如:logd.SetLevel(Lwarn),系统只会打印大于等于Lwarn的日志。
|
||||
|
||||
> 注意:logd.Printf() 和 logd.Print() 不论等级为什么都会输出,请悉知。
|
||||
|
||||
#### Print Option
|
||||
系统提供多种格式输出选项:
|
||||
```
|
||||
Lasync // 异步输出日志
|
||||
Ldate // like 2006/01/02
|
||||
Ltime // like 15:04:05
|
||||
Lmicroseconds // like 15:04:05.123123
|
||||
Llongfile // like /a/b/c/d.go:23
|
||||
Lshortfile // like d.go:23
|
||||
LUTC // 时间utc输出
|
||||
Ldaily // 按天归档
|
||||
|
||||
默认提供:
|
||||
LstdFlags // 2006/01/02 15:04:05.123123, /a/b/c/d.go:23
|
||||
```
|
||||
|
||||
#### 使用方法
|
||||
1、默认方式
|
||||
|
||||
默认方式使用以下配置选项:
|
||||
```
|
||||
// 2006/01/02 15:04:05.123123, /a/b/c/d.go:23
|
||||
Lall = Ldebug | Linfo | Lwarn | Lerror | Lfatal
|
||||
LstdFlags = Lall | Ldate | Lmicroseconds | Lshortfile
|
||||
```
|
||||
这里会打印所有等级日志,打印日志格式为`2006/01/02 15:04:05.123123, /a/b/c/d.go:23`
|
||||
|
||||
可以通过`logd.SetLevel(level)`方式调整日志等级。`logd.SetOutput(writer)`输出日志到别的地方。例子:
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/deepzz0/logd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logd.Printf("Printf: foo\n")
|
||||
logd.Print("Print: foo")
|
||||
|
||||
logd.Debugf("Debugf: foo\n")
|
||||
logd.Debug("Debug: foo")
|
||||
|
||||
logd.Errorf("Errorf: foo\n")
|
||||
logd.Error("Error: foo")
|
||||
|
||||
// 改变输出等级
|
||||
logd.SetLevel(logd.Lerror)
|
||||
// 不论等级如何都会输出
|
||||
fmt.Println("----- 改变日志等级为Lerror -----")
|
||||
logd.Printf("Printf: foo\n")
|
||||
logd.Print("Print: foo")
|
||||
|
||||
logd.Debugf("Debugf: foo\n")
|
||||
logd.Debug("Debug: foo")
|
||||
|
||||
logd.Errorf("Errorf: foo\n")
|
||||
logd.Error("Error: foo")
|
||||
|
||||
fmt.Println("----- 日志等级为Lerror并写入到test.log中 -----")
|
||||
f, err := os.Create("./test.log")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
logd.SetOutput(f)
|
||||
|
||||
logd.Printf("Printf: foo\n")
|
||||
logd.Print("Print: foo")
|
||||
|
||||
logd.Debugf("Debugf: foo\n")
|
||||
logd.Debug("Debug: foo")
|
||||
|
||||
logd.Errorf("Errorf: foo\n")
|
||||
logd.Error("Error: foo")
|
||||
}
|
||||
```
|
||||
输出如下:
|
||||

|
||||
|
||||
|
||||
1、自定义配置
|
||||
推荐需要将日志保存下来的用户使用。
|
||||
|
||||
```
|
||||
Flags := Lwarn | Lerror | Lfatal | Ldate | Ltime | Lshortfile | Ldaily | Lasync
|
||||
|
||||
f, _ := os.OpenFile("testdata/onlyfile.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
|
||||
log := New(LogOption{
|
||||
Out: f,
|
||||
Flag: Flags,
|
||||
LogDir: "testdata",
|
||||
ChannelLen: 1000,
|
||||
})
|
||||
```
|
||||
|
||||
* 输出日志等级:Lwarn | Lerror | Lfatal
|
||||
* 输出日志格式:Ldate | Ltime | Lshortfile
|
||||
* 按日归档:Ldaily
|
||||
* 异步输出:Lasync
|
||||
|
||||
它会将每天的日志,采用 gzip 压缩,并保留 30 天以内的日志。自动删除 30 以前的日志。
|
||||
489
vendor/github.com/deepzz0/logd/logd.go
generated
vendored
Normal file
489
vendor/github.com/deepzz0/logd/logd.go
generated
vendored
Normal file
@@ -0,0 +1,489 @@
|
||||
package logd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Ldebug = 1 << iota //
|
||||
Linfo //
|
||||
Lwarn //
|
||||
Lerror //
|
||||
Lfatal //
|
||||
Ldate // 如:2006/01/02
|
||||
Ltime // 如:15:04:05
|
||||
Lmicroseconds // 如:15:04:05.123123
|
||||
Llongfile // 如:/a/b/c/d.go:23
|
||||
Lshortfile // 如:d.go:23
|
||||
LUTC // 时间utc输出
|
||||
LAsync // 异步输出日志
|
||||
LDaily // 按日归档,保留30天
|
||||
|
||||
//
|
||||
// 建议标准格式为: LVEVL | FORMAT | ROTATE | ASYNC
|
||||
//
|
||||
Lall = Ldebug | Linfo | Lwarn | Lerror | Lfatal
|
||||
|
||||
// 2006/01/02 15:04:05.123123, d.go:23
|
||||
LstdFlags = Lall | Ldate | Lmicroseconds | Lshortfile
|
||||
// 2006/01/02 15:04:05, d.go:23
|
||||
LwarnFlags = Lwarn | Lerror | Lfatal | Ldate | Ltime | Lshortfile | LDaily | LAsync
|
||||
)
|
||||
|
||||
// 等级显示字符串
|
||||
var levelMaps = map[int]string{
|
||||
Ldebug: "DEBUG",
|
||||
Linfo: "INFO",
|
||||
Lwarn: "WARN",
|
||||
Lerror: "ERROR",
|
||||
Lfatal: "FATAL",
|
||||
}
|
||||
|
||||
// 日志结构体
|
||||
type Logger struct {
|
||||
mu sync.Mutex
|
||||
obj string // 打印日志对象
|
||||
out io.Writer // 输出
|
||||
in chan []byte // channel
|
||||
dir string // 输出目录
|
||||
flag int // 标志
|
||||
mails Emailer // 告警邮件
|
||||
}
|
||||
|
||||
// 日志配置项
|
||||
type LogOption struct {
|
||||
Out io.Writer // 输出writer
|
||||
LogDir string // 日志输出目录,为空不输出到文件
|
||||
ChannelLen int // channel
|
||||
Flag int // 标志位
|
||||
Mails Emailer // 告警邮件
|
||||
}
|
||||
|
||||
// 新建日志打印器
|
||||
func New(option LogOption) *Logger {
|
||||
wd, _ := os.Getwd()
|
||||
index := strings.LastIndex(wd, "/")
|
||||
logger := &Logger{
|
||||
obj: wd[index+1:],
|
||||
out: option.Out,
|
||||
in: make(chan []byte, option.ChannelLen),
|
||||
dir: option.LogDir,
|
||||
flag: option.Flag,
|
||||
mails: option.Mails,
|
||||
}
|
||||
if logger.flag|LAsync != 0 {
|
||||
go logger.receive()
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
func (l *Logger) receive() {
|
||||
today := time.Now()
|
||||
var file *os.File
|
||||
var err error
|
||||
for data := range l.in {
|
||||
if l.dir != "" && (file == nil || today.Day() != time.Now().Day()) {
|
||||
l.mu.Lock()
|
||||
today = time.Now()
|
||||
file, err = os.OpenFile(fmt.Sprintf("%s/%s_%s.log", l.dir, l.obj, today.Format("2006-01-02")), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
l.mu.Unlock()
|
||||
if l.flag&LDaily != 0 {
|
||||
go l.rotate(today)
|
||||
}
|
||||
}
|
||||
if file != nil {
|
||||
file.Write(data)
|
||||
}
|
||||
if l.out != nil {
|
||||
l.out.Write(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 压缩
|
||||
func (l *Logger) rotate(t time.Time) {
|
||||
filepath.Walk(l.dir, func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if int(t.Sub(f.ModTime()).Hours()) > 24 {
|
||||
if strings.HasSuffix(f.Name(), ".log") {
|
||||
cmd := exec.Command("gzip", path)
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if int(t.Sub(f.ModTime()).Hours()) > 24*30 {
|
||||
if err := os.Remove(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// 日志基本格式: date, time(hour:minute:second:microsecond), level, module, shortfile:line, <content>
|
||||
func (l *Logger) Output(lvl int, calldepth int, content string) error {
|
||||
_, file, line, ok := runtime.Caller(calldepth)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
l.formatHeader(&buf, lvl, time.Now(), file, line)
|
||||
buf = append(buf, content...)
|
||||
|
||||
if l.mails != nil && lvl >= Lwarn {
|
||||
go l.mails.SendMail(l.obj, buf)
|
||||
}
|
||||
|
||||
// 异步输出
|
||||
if l.flag&LAsync != 0 {
|
||||
l.in <- buf
|
||||
} else {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.out.Write(buf)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 整理日志header
|
||||
func (l *Logger) formatHeader(buf *[]byte, lvl int, t time.Time, file string, line int) {
|
||||
if l.flag&LUTC != 0 {
|
||||
t = t.UTC()
|
||||
}
|
||||
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
|
||||
if l.flag&Ldate != 0 {
|
||||
year, month, day := t.Date()
|
||||
itoa(buf, year, 4)
|
||||
*buf = append(*buf, '/')
|
||||
itoa(buf, int(month), 2)
|
||||
*buf = append(*buf, '/')
|
||||
itoa(buf, day, 2)
|
||||
*buf = append(*buf, ' ')
|
||||
}
|
||||
if l.flag&(Ltime|Lmicroseconds) != 0 {
|
||||
hour, min, sec := t.Clock()
|
||||
itoa(buf, hour, 2)
|
||||
*buf = append(*buf, ':')
|
||||
itoa(buf, min, 2)
|
||||
*buf = append(*buf, ':')
|
||||
itoa(buf, sec, 2)
|
||||
if l.flag&Lmicroseconds != 0 {
|
||||
*buf = append(*buf, '.')
|
||||
itoa(buf, t.Nanosecond()/1e3, 6)
|
||||
}
|
||||
*buf = append(*buf, ' ')
|
||||
}
|
||||
}
|
||||
*buf = append(*buf, getColorLevel(levelMaps[lvl])...)
|
||||
*buf = append(*buf, ' ')
|
||||
if l.flag&(Lshortfile|Llongfile) != 0 {
|
||||
if l.flag&Lshortfile != 0 {
|
||||
short := file
|
||||
for i := len(file) - 1; i > 0; i-- {
|
||||
if file[i] == '/' {
|
||||
short = file[i+1:]
|
||||
break
|
||||
}
|
||||
}
|
||||
file = short
|
||||
}
|
||||
*buf = append(*buf, file...)
|
||||
*buf = append(*buf, ':')
|
||||
itoa(buf, line, -1)
|
||||
*buf = append(*buf, ":"...)
|
||||
}
|
||||
}
|
||||
|
||||
// 等待flush channel
|
||||
func (l *Logger) WaitFlush() {
|
||||
for {
|
||||
if len(l.in) > 0 {
|
||||
time.Sleep(time.Nanosecond * 50)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print
|
||||
func (l *Logger) Printf(format string, v ...interface{}) {
|
||||
l.Output(Linfo, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func (l *Logger) Print(v ...interface{}) {
|
||||
l.Output(Linfo, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
|
||||
// debug
|
||||
func (l *Logger) Debugf(format string, v ...interface{}) {
|
||||
if Ldebug&l.flag != 0 {
|
||||
l.Output(Ldebug, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(v ...interface{}) {
|
||||
if Ldebug&l.flag != 0 {
|
||||
l.Output(Ldebug, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
}
|
||||
|
||||
// info
|
||||
func (l *Logger) Infof(format string, v ...interface{}) {
|
||||
if Linfo&l.flag != 0 {
|
||||
l.Output(Linfo, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Info(v ...interface{}) {
|
||||
if Linfo&l.flag != 0 {
|
||||
l.Output(Linfo, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
}
|
||||
|
||||
// warn
|
||||
func (l *Logger) Warnf(format string, v ...interface{}) {
|
||||
if Lwarn&l.flag != 0 {
|
||||
l.Output(Lwarn, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Warn(v ...interface{}) {
|
||||
if Lwarn&l.flag != 0 {
|
||||
l.Output(Lwarn, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
func (l *Logger) Errorf(format string, v ...interface{}) {
|
||||
if Lerror&l.flag != 0 {
|
||||
l.Output(Lerror, 2, fmt.Sprintf(format, v...)+CallerStack())
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Error(v ...interface{}) {
|
||||
if Lerror&l.flag != 0 {
|
||||
l.Output(Lerror, 2, fmt.Sprintf(smartFormat(v...), v...)+CallerStack())
|
||||
}
|
||||
}
|
||||
|
||||
// fatal
|
||||
func (l *Logger) Fatalf(format string, v ...interface{}) {
|
||||
l.Output(Lfatal, 2, fmt.Sprintf(format, v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (l *Logger) Fatal(v ...interface{}) {
|
||||
l.Output(Lfatal, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (l *Logger) Breakpoint() {
|
||||
l.Output(Ldebug, 3, fmt.Sprintln("breakpoint"))
|
||||
}
|
||||
|
||||
// 设置日志目录
|
||||
func (l *Logger) SetLogDir(dir string) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.dir = dir
|
||||
}
|
||||
|
||||
// 设置日志对象名称
|
||||
func (l *Logger) SetObj(obj string) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.obj = obj
|
||||
}
|
||||
|
||||
// 改变日志输出writer
|
||||
func (l *Logger) SetOutput(out io.Writer) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
l.out = out
|
||||
}
|
||||
|
||||
// 设置日志等级
|
||||
func (l *Logger) SetLevel(lvl int) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
var i uint
|
||||
for i = 0; i < uint(len(levelMaps)); i++ {
|
||||
if lvl&1 != 0 {
|
||||
break
|
||||
}
|
||||
lvl >>= 1
|
||||
}
|
||||
l.flag = (l.flag >> i) | (Lall >> i)
|
||||
l.flag <<= i
|
||||
}
|
||||
|
||||
// standard wrapper
|
||||
var Std = New(LogOption{Out: os.Stdout, Flag: LstdFlags})
|
||||
|
||||
func Printf(format string, v ...interface{}) {
|
||||
Std.Output(Linfo, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func Print(v ...interface{}) {
|
||||
Std.Output(Linfo, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
if Ldebug&Std.flag != 0 {
|
||||
Std.Output(Ldebug, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
if Ldebug&Std.flag != 0 {
|
||||
Std.Output(Ldebug, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Infof(format string, v ...interface{}) {
|
||||
if Linfo&Std.flag != 0 {
|
||||
Std.Output(Linfo, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Info(v ...interface{}) {
|
||||
if Linfo&Std.flag != 0 {
|
||||
Std.Output(Linfo, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Warnf(format string, v ...interface{}) {
|
||||
if Lwarn&Std.flag != 0 {
|
||||
Std.Output(Lwarn, 2, fmt.Sprintf(format, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Warn(v ...interface{}) {
|
||||
if Lwarn&Std.flag != 0 {
|
||||
Std.Output(Lwarn, 2, fmt.Sprintf(smartFormat(v...), v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Errorf(format string, v ...interface{}) {
|
||||
if Lerror&Std.flag != 0 {
|
||||
Std.Output(Lerror, 2, fmt.Sprintf(format, v...)+CallerStack())
|
||||
}
|
||||
}
|
||||
|
||||
func Error(v ...interface{}) {
|
||||
if Lerror&Std.flag != 0 {
|
||||
Std.Output(Lerror, 2, fmt.Sprintf(smartFormat(v...), v...)+CallerStack())
|
||||
}
|
||||
}
|
||||
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
Std.Output(Lfatal, 2, fmt.Sprintf(format, v...)+CallerStack())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func Fatal(v ...interface{}) {
|
||||
Std.Output(Lfatal, 2, fmt.Sprintf(smartFormat(v...), v...)+CallerStack())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func Breakpoint() {
|
||||
Std.Breakpoint()
|
||||
}
|
||||
|
||||
func SetLevel(lvl int) {
|
||||
Std.SetLevel(lvl)
|
||||
}
|
||||
|
||||
func SetOutput(w io.Writer) {
|
||||
Std.SetOutput(w)
|
||||
}
|
||||
|
||||
func SetObj(obj string) {
|
||||
Std.SetObj(obj)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
func smartFormat(v ...interface{}) string {
|
||||
format := ""
|
||||
for i := 0; i < len(v); i++ {
|
||||
format += " %v"
|
||||
}
|
||||
format += "\n"
|
||||
return format
|
||||
}
|
||||
|
||||
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
|
||||
func itoa(buf *[]byte, i int, wid int) {
|
||||
// Assemble decimal in reverse order.
|
||||
var b [20]byte
|
||||
bp := len(b) - 1
|
||||
for i >= 10 || wid > 1 {
|
||||
wid--
|
||||
q := i / 10
|
||||
b[bp] = byte('0' + i - q*10)
|
||||
bp--
|
||||
i = q
|
||||
}
|
||||
// i < 10
|
||||
b[bp] = byte('0' + i)
|
||||
*buf = append(*buf, b[bp:]...)
|
||||
}
|
||||
|
||||
const (
|
||||
Gray = uint8(iota + 90)
|
||||
Red
|
||||
Green
|
||||
Yellow
|
||||
Blue
|
||||
Magenta
|
||||
)
|
||||
|
||||
// getColorLevel returns colored level string by given level.
|
||||
func getColorLevel(level string) string {
|
||||
level = strings.ToUpper(level)
|
||||
switch level {
|
||||
case "DEBUG":
|
||||
return fmt.Sprintf("\033[%dm[%5s]\033[0m", Green, level)
|
||||
case "INFO":
|
||||
return fmt.Sprintf("\033[%dm[%5s]\033[0m", Blue, level)
|
||||
case "WARN":
|
||||
return fmt.Sprintf("\033[%dm[%5s]\033[0m", Magenta, level)
|
||||
case "ERROR":
|
||||
return fmt.Sprintf("\033[%dm[%5s]\033[0m", Yellow, level)
|
||||
case "FATAL":
|
||||
return fmt.Sprintf("\033[%dm[%5s]\033[0m", Red, level)
|
||||
default:
|
||||
return level
|
||||
}
|
||||
}
|
||||
|
||||
func CallerStack() string {
|
||||
var caller_str string
|
||||
for skip := 2; ; skip++ {
|
||||
// 获取调用者的信息
|
||||
pc, file, line, ok := runtime.Caller(skip)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
func_name := runtime.FuncForPC(pc).Name()
|
||||
caller_str += "Func : " + func_name + "\nFile:" + file + ":" + fmt.Sprint(line) + "\n"
|
||||
}
|
||||
return caller_str
|
||||
}
|
||||
107
vendor/github.com/deepzz0/logd/logd_test.go
generated
vendored
Normal file
107
vendor/github.com/deepzz0/logd/logd_test.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
package logd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
Printf("Printf: foo\n")
|
||||
Print("Print: foo")
|
||||
|
||||
SetLevel(Ldebug)
|
||||
|
||||
Debugf("Debugf: foo\n")
|
||||
Debug("Debug: foo")
|
||||
|
||||
Infof("Infof: foo\n")
|
||||
Info("Info: foo")
|
||||
|
||||
Errorf("Errorf: foo\n")
|
||||
Error("Error: foo")
|
||||
|
||||
SetLevel(Lerror)
|
||||
|
||||
Debugf("Debugf: foo\n")
|
||||
Debug("Debug: foo")
|
||||
|
||||
Infof("Infof: foo\n")
|
||||
Info("Info: foo")
|
||||
|
||||
Errorf("Errorf: foo\n")
|
||||
Error("Error: foo")
|
||||
}
|
||||
|
||||
func BenchmarkLogFileChan(b *testing.B) {
|
||||
log := New(LogOption{
|
||||
Flag: LAsync | Ldate | Ltime | Lshortfile,
|
||||
LogDir: "testdata",
|
||||
ChannelLen: 1000,
|
||||
})
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Print("testing this is a testing about benchmark")
|
||||
}
|
||||
log.WaitFlush()
|
||||
}
|
||||
|
||||
func BenchmarkLogFile(b *testing.B) {
|
||||
f, _ := os.OpenFile("testdata/onlyfile.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
|
||||
log := New(LogOption{
|
||||
Out: f,
|
||||
Flag: Ldate | Ltime | Lshortfile,
|
||||
LogDir: "testdata",
|
||||
ChannelLen: 1000,
|
||||
})
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Print("testing this is a testing about benchmark")
|
||||
}
|
||||
log.WaitFlush()
|
||||
}
|
||||
|
||||
func BenchmarkStandardFile(b *testing.B) {
|
||||
f, _ := os.OpenFile("testdata/logfile.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
|
||||
log := log.New(f, "", log.LstdFlags)
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Print("testing this is a testing about benchmark")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLogFileChanMillion(b *testing.B) {
|
||||
log := New(LogOption{
|
||||
Flag: LAsync | Ldate | Ltime | Lshortfile,
|
||||
LogDir: "testdata",
|
||||
ChannelLen: 1000,
|
||||
})
|
||||
b.N = 1000000
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Print("testing this is a testing about benchmark")
|
||||
}
|
||||
log.WaitFlush()
|
||||
}
|
||||
|
||||
func BenchmarkLogFileMillion(b *testing.B) {
|
||||
f, _ := os.OpenFile("testdata/onlyfilemillion.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
|
||||
log := New(LogOption{
|
||||
Out: f,
|
||||
Flag: Ldate | Ltime | Lshortfile,
|
||||
LogDir: "testdata",
|
||||
ChannelLen: 1000,
|
||||
})
|
||||
b.N = 1000000
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Print("testing this is a testing about benchmark")
|
||||
}
|
||||
log.WaitFlush()
|
||||
}
|
||||
|
||||
func BenchmarkStandardFileMillion(b *testing.B) {
|
||||
f, _ := os.OpenFile("testdata/logfilemillion.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
|
||||
log := log.New(f, "", log.LstdFlags)
|
||||
b.N = 1000000
|
||||
for i := 0; i < b.N; i++ {
|
||||
log.Print("testing this is a testing about benchmark")
|
||||
}
|
||||
}
|
||||
80
vendor/github.com/deepzz0/logd/mail.go
generated
vendored
Normal file
80
vendor/github.com/deepzz0/logd/mail.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package logd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Emailer interface {
|
||||
SendMail(fromname string, msg []byte) error
|
||||
}
|
||||
|
||||
type Smtp struct {
|
||||
From string // 发件箱:number@qq.com
|
||||
Key string // 发件密钥:peerdmnoqirqbiaa
|
||||
Host string // 主机地址:smtp.example.com
|
||||
Port string // 主机端口:465
|
||||
To []string // 发送给:object@163.com
|
||||
Subject string // 标题:警告邮件[goblog]
|
||||
}
|
||||
|
||||
func (s *Smtp) SendMail(fromname string, msg []byte) error {
|
||||
// 新建连接
|
||||
conn, err := tls.Dial("tcp", s.Host+":"+s.Port, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 新建客户端
|
||||
client, err := smtp.NewClient(conn, s.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取授权
|
||||
auth := smtp.PlainAuth("", s.From, s.Key, s.Host)
|
||||
if err = client.Auth(auth); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 向服务器发送MAIL命令
|
||||
if err = client.Mail(s.From); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 准备数据
|
||||
str := fmt.Sprint(
|
||||
"To:", strings.Join(s.To, ","),
|
||||
"\r\nFrom:", fmt.Sprintf("%s<%s>", fromname, s.From),
|
||||
"\r\nSubject:", s.Subject,
|
||||
"\r\n", "Content-Type:text/plain;charset=UTF-8",
|
||||
"\r\n\r\n",
|
||||
)
|
||||
data := make([]byte, len(str)+len(msg))
|
||||
copy(data, []byte(str))
|
||||
copy(data[len(str):], msg)
|
||||
|
||||
// RCPT
|
||||
for _, d := range s.To {
|
||||
if err := client.Rcpt(d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 获取WriteCloser
|
||||
wc, err := client.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 写入数据
|
||||
_, err = wc.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wc.Close()
|
||||
|
||||
return client.Quit()
|
||||
}
|
||||
20
vendor/github.com/deepzz0/logd/mail_test.go
generated
vendored
Normal file
20
vendor/github.com/deepzz0/logd/mail_test.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Package logd provides ...
|
||||
package logd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSmtpSendMail(t *testing.T) {
|
||||
s := &Smtp{
|
||||
From: "120735581@qq.com",
|
||||
Key: "peerdmnoqirqbiaa",
|
||||
Host: "smtp.qq.com",
|
||||
Port: "465",
|
||||
To: []string{"a120735581@foxmail.com"},
|
||||
Subject: "test email from logd",
|
||||
}
|
||||
|
||||
err := s.SendMail("test", []byte("hello world"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
4
vendor/github.com/garyburd/redigo/redis/conn.go
generated
vendored
4
vendor/github.com/garyburd/redigo/redis/conn.go
generated
vendored
@@ -370,6 +370,10 @@ func (c *conn) writeCommand(cmd string, args []interface{}) (err error) {
|
||||
}
|
||||
case nil:
|
||||
err = c.writeString("")
|
||||
case Argument:
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, arg.RedisArg())
|
||||
err = c.writeBytes(buf.Bytes())
|
||||
default:
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, arg)
|
||||
|
||||
14
vendor/github.com/garyburd/redigo/redis/conn_test.go
generated
vendored
14
vendor/github.com/garyburd/redigo/redis/conn_test.go
generated
vendored
@@ -46,6 +46,14 @@ func dialTestConn(r io.Reader, w io.Writer) redis.DialOption {
|
||||
})
|
||||
}
|
||||
|
||||
type durationArg struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (t durationArg) RedisArg() interface{} {
|
||||
return t.Seconds()
|
||||
}
|
||||
|
||||
var writeTests = []struct {
|
||||
args []interface{}
|
||||
expected string
|
||||
@@ -82,6 +90,10 @@ var writeTests = []struct {
|
||||
[]interface{}{"SET", "key", nil},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"SET", "key", durationArg{time.Minute}},
|
||||
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$2\r\n60\r\n",
|
||||
},
|
||||
{
|
||||
[]interface{}{"ECHO", true, false},
|
||||
"*3\r\n$4\r\nECHO\r\n$1\r\n1\r\n$1\r\n0\r\n",
|
||||
@@ -447,7 +459,7 @@ var dialErrors = []struct {
|
||||
"localhost",
|
||||
"invalid redis URL scheme",
|
||||
},
|
||||
// The error message for invalid hosts is diffferent in different
|
||||
// The error message for invalid hosts is different in different
|
||||
// versions of Go, so just check that there is an error message.
|
||||
{
|
||||
"redis://weird url",
|
||||
|
||||
2
vendor/github.com/garyburd/redigo/redis/pool_test.go
generated
vendored
2
vendor/github.com/garyburd/redigo/redis/pool_test.go
generated
vendored
@@ -437,8 +437,8 @@ func startGoroutines(p *redis.Pool, cmd string, args ...interface{}) chan error
|
||||
go func() {
|
||||
c := p.Get()
|
||||
_, err := c.Do(cmd, args...)
|
||||
errs <- err
|
||||
c.Close()
|
||||
errs <- err
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
18
vendor/github.com/garyburd/redigo/redis/redis.go
generated
vendored
18
vendor/github.com/garyburd/redigo/redis/redis.go
generated
vendored
@@ -39,3 +39,21 @@ type Conn interface {
|
||||
// Receive receives a single reply from the Redis server
|
||||
Receive() (reply interface{}, err error)
|
||||
}
|
||||
|
||||
// Argument is implemented by types which want to control how their value is
|
||||
// interpreted when used as an argument to a redis command.
|
||||
type Argument interface {
|
||||
// RedisArg returns the interface that represents the value to be used
|
||||
// in redis commands.
|
||||
RedisArg() interface{}
|
||||
}
|
||||
|
||||
// Scanner is implemented by types which want to control how their value is
|
||||
// interpreted when read from redis.
|
||||
type Scanner interface {
|
||||
// RedisScan assigns a value from a redis value.
|
||||
//
|
||||
// An error should be returned if the value cannot be stored without
|
||||
// loss of information.
|
||||
RedisScan(src interface{}) error
|
||||
}
|
||||
|
||||
28
vendor/github.com/garyburd/redigo/redis/scan.go
generated
vendored
28
vendor/github.com/garyburd/redigo/redis/scan.go
generated
vendored
@@ -110,6 +110,25 @@ func convertAssignInt(d reflect.Value, s int64) (err error) {
|
||||
}
|
||||
|
||||
func convertAssignValue(d reflect.Value, s interface{}) (err error) {
|
||||
if d.Kind() != reflect.Ptr {
|
||||
if d.CanAddr() {
|
||||
d2 := d.Addr()
|
||||
if d2.CanInterface() {
|
||||
if scanner, ok := d2.Interface().(Scanner); ok {
|
||||
return scanner.RedisScan(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if d.CanInterface() {
|
||||
// Already a reflect.Ptr
|
||||
if d.IsNil() {
|
||||
d.Set(reflect.New(d.Type().Elem()))
|
||||
}
|
||||
if scanner, ok := d.Interface().(Scanner); ok {
|
||||
return scanner.RedisScan(s)
|
||||
}
|
||||
}
|
||||
|
||||
switch s := s.(type) {
|
||||
case []byte:
|
||||
err = convertAssignBulkString(d, s)
|
||||
@@ -135,11 +154,15 @@ func convertAssignArray(d reflect.Value, s []interface{}) error {
|
||||
}
|
||||
|
||||
func convertAssign(d interface{}, s interface{}) (err error) {
|
||||
if scanner, ok := d.(Scanner); ok {
|
||||
return scanner.RedisScan(s)
|
||||
}
|
||||
|
||||
// Handle the most common destination types using type switches and
|
||||
// fall back to reflection for all other types.
|
||||
switch s := s.(type) {
|
||||
case nil:
|
||||
// ingore
|
||||
// ignore
|
||||
case []byte:
|
||||
switch d := d.(type) {
|
||||
case *string:
|
||||
@@ -219,6 +242,8 @@ func convertAssign(d interface{}, s interface{}) (err error) {
|
||||
|
||||
// Scan copies from src to the values pointed at by dest.
|
||||
//
|
||||
// Scan uses RedisScan if available otherwise:
|
||||
//
|
||||
// The values pointed at by dest must be an integer, float, boolean, string,
|
||||
// []byte, interface{} or slices of these types. Scan uses the standard strconv
|
||||
// package to convert bulk strings to numeric and boolean types.
|
||||
@@ -359,6 +384,7 @@ var errScanStructValue = errors.New("redigo.ScanStruct: value must be non-nil po
|
||||
//
|
||||
// Fields with the tag redis:"-" are ignored.
|
||||
//
|
||||
// Each field uses RedisScan if available otherwise:
|
||||
// Integer, float, boolean, string and []byte fields are supported. Scan uses the
|
||||
// standard strconv package to convert bulk string values to numeric and
|
||||
// boolean types.
|
||||
|
||||
58
vendor/github.com/garyburd/redigo/redis/scan_test.go
generated
vendored
58
vendor/github.com/garyburd/redigo/redis/scan_test.go
generated
vendored
@@ -19,10 +19,32 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
)
|
||||
|
||||
type durationScan struct {
|
||||
time.Duration `redis:"sd"`
|
||||
}
|
||||
|
||||
func (t *durationScan) RedisScan(src interface{}) (err error) {
|
||||
if t == nil {
|
||||
return fmt.Errorf("nil pointer")
|
||||
}
|
||||
switch src := src.(type) {
|
||||
case string:
|
||||
t.Duration, err = time.ParseDuration(src)
|
||||
case []byte:
|
||||
t.Duration, err = time.ParseDuration(string(src))
|
||||
case int64:
|
||||
t.Duration = time.Duration(src)
|
||||
default:
|
||||
err = fmt.Errorf("cannot convert from %T to %T", src, t)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var scanConversionTests = []struct {
|
||||
src interface{}
|
||||
dest interface{}
|
||||
@@ -59,6 +81,11 @@ var scanConversionTests = []struct {
|
||||
{[]interface{}{[]byte("1"), []byte("2")}, []float64{1, 2}},
|
||||
{[]interface{}{[]byte("1")}, []byte{1}},
|
||||
{[]interface{}{[]byte("1")}, []bool{true}},
|
||||
{"1m", durationScan{Duration: time.Minute}},
|
||||
{[]byte("1m"), durationScan{Duration: time.Minute}},
|
||||
{time.Minute.Nanoseconds(), durationScan{Duration: time.Minute}},
|
||||
{[]interface{}{[]byte("1m")}, []durationScan{durationScan{Duration: time.Minute}}},
|
||||
{[]interface{}{[]byte("1m")}, []*durationScan{&durationScan{Duration: time.Minute}}},
|
||||
}
|
||||
|
||||
func TestScanConversion(t *testing.T) {
|
||||
@@ -86,6 +113,8 @@ var scanConversionErrorTests = []struct {
|
||||
{int64(-1), byte(0)},
|
||||
{[]byte("junk"), false},
|
||||
{redis.Error("blah"), false},
|
||||
{redis.Error("blah"), durationScan{Duration: time.Minute}},
|
||||
{"invalid", durationScan{Duration: time.Minute}},
|
||||
}
|
||||
|
||||
func TestScanConversionError(t *testing.T) {
|
||||
@@ -158,6 +187,8 @@ type s1 struct {
|
||||
Bt bool
|
||||
Bf bool
|
||||
s0
|
||||
Sd durationScan `redis:"sd"`
|
||||
Sdp *durationScan `redis:"sdp"`
|
||||
}
|
||||
|
||||
var scanStructTests = []struct {
|
||||
@@ -166,8 +197,31 @@ var scanStructTests = []struct {
|
||||
value interface{}
|
||||
}{
|
||||
{"basic",
|
||||
[]string{"i", "-1234", "u", "5678", "s", "hello", "p", "world", "b", "t", "Bt", "1", "Bf", "0", "X", "123", "y", "456"},
|
||||
&s1{I: -1234, U: 5678, S: "hello", P: []byte("world"), B: true, Bt: true, Bf: false, s0: s0{X: 123, Y: 456}},
|
||||
[]string{
|
||||
"i", "-1234",
|
||||
"u", "5678",
|
||||
"s", "hello",
|
||||
"p", "world",
|
||||
"b", "t",
|
||||
"Bt", "1",
|
||||
"Bf", "0",
|
||||
"X", "123",
|
||||
"y", "456",
|
||||
"sd", "1m",
|
||||
"sdp", "1m",
|
||||
},
|
||||
&s1{
|
||||
I: -1234,
|
||||
U: 5678,
|
||||
S: "hello",
|
||||
P: []byte("world"),
|
||||
B: true,
|
||||
Bt: true,
|
||||
Bf: false,
|
||||
s0: s0{X: 123, Y: 456},
|
||||
Sd: durationScan{Duration: time.Minute},
|
||||
Sdp: &durationScan{Duration: time.Minute},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user