go中log日志库
callers.go
package log
import (
"path/filepath"
"runtime"
"strconv"
"strings"
"github.com/sirupsen/logrus"
)
const (
depth = 9
)
// CallerHook represents a caller hook of logrus
type CallerHook struct {
}
// Fire adds a callers field in logger instance
func (hook *CallerHook) Fire(entry *logrus.Entry) error {
entry.Data["caller"] = hook.caller()
return nil
}
// Levels returns support levels
func (hook *CallerHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
logrus.WarnLevel,
logrus.InfoLevel,
logrus.DebugLevel,
}
}
func (hook *CallerHook) caller() string {
if _, file, line, ok := runtime.Caller(depth); ok {
return strings.Join([]string{filepath.Base(file), strconv.Itoa(line)}, ":")
}
// not sure what the convention should be here
return ""
}
log.go
package log
import (
"data-merge-rule/util"
"io"
"os"
"github.com/sirupsen/logrus"
)
var (
defaultFormatter = &logrus.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05.000",
FullTimestamp: true,
}
defaultLevel = "debug"
defaultOutput = os.Stderr
)
func init() {
SetFormatter(defaultFormatter)
SetLevel(defaultLevel)
SetOutput(defaultOutput)
}
// Logger wrappers access to logger instance
type Logger interface {
Debug(args ...interface{})
Print(args ...interface{})
Info(args ...interface{})
Warn(args ...interface{})
Warning(args ...interface{})
Error(args ...interface{})
Panic(args ...interface{})
Fatal(args ...interface{})
Debugf(format string, args ...interface{})
Printf(format string, args ...interface{})
Infof(format string, args ...interface{})
Warnf(format string, args ...interface{})
Warningf(format string, args ...interface{})
Errorf(format string, args ...interface{})
Panicf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
Debugln(args ...interface{})
Println(args ...interface{})
Infoln(args ...interface{})
Warnln(args ...interface{})
Warningln(args ...interface{})
Errorln(args ...interface{})
Panicln(args ...interface{})
Fatalln(args ...interface{})
}
func StandardLogger() *logrus.Logger {
return logrus.StandardLogger()
}
// New returns an standard logger or a file system logger according the filename
func New(args ...interface{}) (Logger, error) {
if len(args) == 1 {
if name, ok := args[0].(string); ok {
f, err := util.OpenFile(name)
if err != nil {
return nil, err
}
SetOutput(f)
}
}
return logrus.StandardLogger(), nil
}
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter logrus.Formatter) {
logrus.SetFormatter(formatter)
}
// SetLevel sets the standard logger level.
func SetLevel(lvl string) {
level, err := logrus.ParseLevel(lvl)
if err != nil {
return
}
if level >= logrus.DebugLevel {
AddHook(&CallerHook{})
}
logrus.SetLevel(level)
}
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
logrus.SetOutput(out)
}
// AddHook adds a hook to the standard logger hooks.
func AddHook(hook logrus.Hook) {
logrus.AddHook(hook)
}
// Print logs a message at level Info on the standard logger.
func Print(args ...interface{}) {
logrus.Print(args...)
}
// Info logs a message at level Info on the standard logger.
func Info(args ...interface{}) {
logrus.Info(args...)
}
// Warning logs a message at level Warn on the standard logger.
func Warning(args ...interface{}) {
logrus.Warning(args...)
}
// Error logs a message at level Error on the standard logger.
func Error(args ...interface{}) {
logrus.Error(args...)
}
// Panic logs a message at level Panic on the standard logger.
func Panic(args ...interface{}) {
logrus.Panic(args...)
}
// Fatal logs a message at level Fatal on the standard logger.
func Fatal(args ...interface{}) {
logrus.Fatal(args...)
}
// Printf logs a message at level Info on the standard logger.
func Printf(format string, args ...interface{}) {
logrus.Printf(format, args...)
}
// Infof logs a message at level Info on the standard logger.
func Infof(format string, args ...interface{}) {
logrus.Infof(format, args...)
}
// Errorf logs a message at level Error on the standard logger.
func Errorf(format string, args ...interface{}) {
logrus.Errorf(format, args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
func Fatalf(format string, args ...interface{}) {
logrus.Fatalf(format, args...)
}
// Println logs a message at level Info on the standard logger.
func Println(args ...interface{}) {
logrus.Println(args...)
}
// Fatalln logs a message at level Fatal on the standard logger.
func Fatalln(args ...interface{}) {
logrus.Fatalln(args...)
}
// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
logrus.Debug(args...)
}
log_store.go
package log
import (
"os"
"path/filepath"
"time"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
)
// InitDaysJSONRotationLogger init rotation log config with maxAgeDays and json format.
func InitDaysJSONRotationLogger(filePath, fileName string, maxAgeDays uint) error {
const day = time.Hour * 24
return InitRotationLogger(filePath, fileName, time.Duration(maxAgeDays)*day, day, &logrus.JSONFormatter{})
}
// InitRotationLogger init rotation log config.
func InitRotationLogger(filePath, fileName string, maxAge, rotationTime time.Duration, formatter logrus.Formatter) error {
err := os.MkdirAll(filePath, 0700)
if err != nil {
return err
}
filePath, err = filepath.Abs(filePath + fileName)
if err != nil {
return err
}
writer, err := rotatelogs.New(
filePath+".%Y%m%d%H%M%S",
rotatelogs.WithLinkName(filePath),
rotatelogs.WithMaxAge(maxAge),
rotatelogs.WithRotationTime(rotationTime),
)
if err != nil {
return err
}
logrus.AddHook(lfshook.NewHook(
lfshook.WriterMap{
logrus.DebugLevel: writer,
logrus.InfoLevel: writer,
logrus.WarnLevel: writer,
logrus.ErrorLevel: writer,
logrus.FatalLevel: writer,
logrus.PanicLevel: writer,
},
formatter,
))
return nil
}
type LogWriter struct {
logFunc func(...interface{})
}
func (l *LogWriter) Write(p []byte) (n int, err error) {
if l.logFunc != nil {
l.logFunc(string(p))
}
return len(p), nil
}
io.go
package util
import (
"bufio"
"bytes"
"fmt"
"io"
)
// ReadBytes reads n bytes from reader.
func ReadBytes(reader io.Reader, n int) ([]byte, error) {
if reader == nil || n <= 0 {
return nil, fmt.Errorf("invalid args (%v, %v)", reader, n)
}
buf := make([]byte, n)
pos := 0
for {
m, err := reader.Read(buf[pos:])
if err != nil {
if err == io.EOF {
pos += m
if pos < n {
return buf[:pos], err
}
return buf, nil
}
return nil, err
}
pos += m
if pos >= n {
return buf, nil
}
}
}
// ForeachLine reads string from reader line-by-line.
func ForeachLine(reader io.Reader, fun func(line string) error) error {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
err := fun(scanner.Text())
if err != nil {
return err
}
}
return scanner.Err()
}
// Transformer transforms bytes.
type Transformer interface {
Transform([]byte) ([]byte, error)
}
// CombineTransformer combines multi transformers.
type CombineTransformer []Transformer
func (ts CombineTransformer) Transform(data []byte) ([]byte, error) {
var err error
for i, t := range ts {
if t == nil {
continue
}
data, err = t.Transform(data)
if err != nil {
return nil, fmt.Errorf("perform transformer at index %d failed, %v", i, err)
}
}
return data, nil
}
// The TransformFunc type is an adapter to allow the use of
// ordinary functions as Transformer.
type TransformFunc func([]byte) ([]byte, error)
func (f TransformFunc) Transform(data []byte) ([]byte, error) {
return f(data)
}
// StringReplacer replaces string data.
type StringReplacer map[string]string
func (r StringReplacer) Transform(data []byte) ([]byte, error) {
for old, new := range r {
data = bytes.Replace(data, []byte(old), []byte(new), -1)
}
return data, nil
}
file.go
package util
import (
"bufio"
"fmt"
"io/ioutil"
"os"
)
// OpenFile opens or creates a file
// If the file already exists, open it . If it does not,
// It will create the file with mode 0644.
func OpenFile(path string) (*os.File, error) {
f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
if err != nil {
return nil, err
}
return f, err
}
// FileExist determines whether a file exists
func FileExist(filePath string) bool {
_, err := os.Stat(filePath)
if err != nil && os.IsNotExist(err) {
return false
}
return true
}
// WriteToFile writes data to file.
func WriteToFile(d []byte, fileTo string) error {
err := ioutil.WriteFile(fileTo, d, 0600)
if err != nil {
return err
}
return nil
}
// FileReader is buffed file reader.
type FileReader struct {
fileName string
*bufio.Reader
f *os.File
}
func (r *FileReader) FileName() string {
return r.fileName
}
func (r *FileReader) Open(name string, flag int, perm os.FileMode) error {
f, err := os.OpenFile(name, flag, perm)
if err != nil {
return err
}
r.f = f
r.Reader = bufio.NewReader(f)
r.fileName = name
return nil
}
func (r *FileReader) Close() error {
if r.f == nil {
return nil
}
err := r.f.Close()
if err != nil {
return err
}
r.f = nil
r.Reader = nil
r.fileName = ""
return nil
}
// FileWriter is buffed file writer.
type FileWriter struct {
fileName string
*bufio.Writer
f *os.File
}
func (w *FileWriter) FileName() string {
return w.fileName
}
func (w *FileWriter) Open(name string, flag int, perm os.FileMode) error {
f, err := os.OpenFile(name, flag, perm)
if err != nil {
return err
}
w.f = f
w.Writer = bufio.NewWriter(f)
w.fileName = name
return nil
}
func (w *FileWriter) Close() error {
if w.f == nil {
return nil
}
err := w.Flush()
if err != nil {
return err
}
err = w.f.Close()
if err != nil {
return err
}
w.f = nil
w.Writer = nil
w.fileName = ""
return nil
}
// WithOpenFile opens a file, do something, and close it.
func WithOpenFile(name string, flag int, perm os.FileMode, fun func(*os.File) error) error {
f, err := os.OpenFile(name, flag, perm)
if err != nil {
return err
}
defer f.Close()
return fun(f)
}
// WithReadFile opens a file for read, and close it.
func WithReadFile(name string, fun func(*bufio.Reader) error) error {
return WithOpenFile(name, os.O_RDONLY, 0, func(f *os.File) error {
reader := bufio.NewReader(f)
return fun(reader)
})
}
// WithReadFileLineByLine opens a file, reads string line-by-line.
func WithReadFileLineByLine(name string, fun func(string) error) error {
return WithReadFile(name, func(reader *bufio.Reader) error {
return ForeachLine(reader, fun)
})
}
// WithWriteFile opens a file for write, and close it.
func WithWriteFile(name string, fun func(*bufio.Writer) error) error {
return WithOpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666, func(f *os.File) error {
writer := bufio.NewWriter(f)
err := fun(writer)
if err != nil {
return err
}
return writer.Flush()
})
}
// CopyFile copys and transform data.
func CopyFile(from, to string, transformers ...Transformer) error {
data, err := ioutil.ReadFile(from)
if err != nil {
return fmt.Errorf("read file %s failed, %v", from, err)
}
data, err = CombineTransformer(transformers).Transform(data)
if err != nil {
return err
}
err = ioutil.WriteFile(to, data, 0666)
if err != nil {
return fmt.Errorf("write file %s failed, %v", to, err)
}
return nil
}