github.com/amazechain/amc@v0.1.3/log/logrus.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The AmazeChain library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package log
    18  
    19  import (
    20  	"fmt"
    21  	"github.com/go-stack/stack"
    22  	"github.com/sirupsen/logrus"
    23  	"golang.org/x/exp/maps"
    24  	"os"
    25  	"sync"
    26  )
    27  
    28  var (
    29  	std = logrus.StandardLogger()
    30  )
    31  
    32  type logger struct {
    33  	ctx     []interface{}
    34  	mapPool sync.Pool
    35  }
    36  
    37  func (l *logger) newMap() map[string]interface{} {
    38  	m, ok := l.mapPool.Get().(map[string]interface{})
    39  	if ok {
    40  		return m
    41  	}
    42  
    43  	return map[string]interface{}{}
    44  }
    45  
    46  func (l *logger) returnMap(m map[string]interface{}) {
    47  	maps.Clear(m)
    48  	l.mapPool.Put(m)
    49  }
    50  
    51  func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) {
    52  	field := l.newMap()
    53  	defer l.returnMap(field)
    54  	var prepareFields = func() {
    55  		field["prefix"] = fmt.Sprintf("%k", stack.Caller(skip))
    56  		ctx = newContext(l.ctx, ctx)
    57  		for i := 0; i < len(ctx); i += 2 {
    58  			k, ok := ctx[i].(string)
    59  			if !ok {
    60  
    61  			}
    62  			if s, ok := ctx[i+1].(TerminalStringer); ok {
    63  				field[k] = s.TerminalString()
    64  			} else {
    65  				field[k] = ctx[i+1]
    66  			}
    67  		}
    68  	}
    69  
    70  	if terminal.IsLevelEnabled(logrus.Level(lvl)) {
    71  		prepareFields()
    72  		terminal.WithFields(field).Log(logrus.Level(lvl), msg)
    73  	}
    74  
    75  	if std.IsLevelEnabled(logrus.Level(lvl)) {
    76  		prepareFields()
    77  		std.WithFields(field).Log(logrus.Level(lvl), msg)
    78  	}
    79  	//switch lvl {
    80  	//case LvlCrit:
    81  	//	terminal.WithFields(field).Panic(msg)
    82  	//	std.WithFields(field).Panic(msg)
    83  	//case LvlError:
    84  	//	terminal.WithFields(field).Error(msg)
    85  	//	std.WithFields(field).Error(msg)
    86  	//case LvlWarn:
    87  	//	terminal.WithFields(field).Warn(msg)
    88  	//	std.WithFields(field).Warn(msg)
    89  	//case LvlInfo:
    90  	//	terminal.WithFields(field).Info(msg)
    91  	//	std.WithFields(field).Info(msg)
    92  	//case LvlDebug:
    93  	//	terminal.WithFields(field).Debug(msg)
    94  	//	std.WithFields(field).Debug(msg)
    95  	//case LvlTrace:
    96  	//	terminal.WithFields(field).Trace(msg)
    97  	//	std.WithFields(field).Trace(msg)
    98  	//}
    99  }
   100  
   101  func (l *logger) New(ctx ...interface{}) Logger {
   102  	child := &logger{ctx: newContext(l.ctx, ctx)}
   103  	return child
   104  }
   105  
   106  func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
   107  	normalizedSuffix := normalize(suffix)
   108  	newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
   109  	n := copy(newCtx, prefix)
   110  	copy(newCtx[n:], normalizedSuffix)
   111  	return newCtx
   112  }
   113  
   114  func (l *logger) Trace(msg string, ctx ...interface{}) {
   115  	l.write(msg, LvlTrace, ctx, skipLevel)
   116  }
   117  
   118  func (l *logger) Debug(msg string, ctx ...interface{}) {
   119  	l.write(msg, LvlDebug, ctx, skipLevel)
   120  }
   121  
   122  func (l *logger) Info(msg string, ctx ...interface{}) {
   123  	l.write(msg, LvlInfo, ctx, skipLevel)
   124  }
   125  
   126  func (l *logger) Warn(msg string, ctx ...interface{}) {
   127  	l.write(msg, LvlWarn, ctx, skipLevel)
   128  }
   129  
   130  func (l *logger) Error(msg string, ctx ...interface{}) {
   131  	l.write(msg, LvlError, ctx, skipLevel)
   132  }
   133  
   134  func (l *logger) Crit(msg string, ctx ...interface{}) {
   135  	l.write(msg, LvlCrit, ctx, skipLevel)
   136  	os.Exit(1)
   137  }
   138  
   139  func normalize(ctx []interface{}) []interface{} {
   140  	// if the caller passed a Ctx object, then expand it
   141  	if len(ctx) == 1 {
   142  		if ctxMap, ok := ctx[0].(Ctx); ok {
   143  			ctx = ctxMap.toArray()
   144  		}
   145  	}
   146  
   147  	// ctx needs to be even because it's a series of key/value pairs
   148  	// no one wants to check for errors on logging functions,
   149  	// so instead of erroring on bad input, we'll just make sure
   150  	// that things are the right length and users can fix bugs
   151  	// when they see the output looks wrong
   152  	if len(ctx)%2 != 0 {
   153  		ctx = append(ctx, nil)
   154  	}
   155  
   156  	return ctx
   157  }
   158  
   159  // Ctx is a map of key/value pairs to pass as context to a log function
   160  // Use this only if you really need greater safety around the arguments you pass
   161  // to the logging functions.
   162  type Ctx map[string]interface{}
   163  
   164  func (c Ctx) toArray() []interface{} {
   165  	arr := make([]interface{}, len(c)*2)
   166  
   167  	i := 0
   168  	for k, v := range c {
   169  		arr[i] = k
   170  		arr[i+1] = v
   171  		i += 2
   172  	}
   173  
   174  	return arr
   175  }