github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/log/handler_glog.go (about)

     1  package log
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  	"runtime"
     8  	"strconv"
     9  	"strings"
    10  	"sync"
    11  	"sync/atomic"
    12  )
    13  
    14  var errVmoduleSyntax = errors.New("expect comma-separated list of filename=N")
    15  
    16  var errTraceSyntax = errors.New("expect file.go:234")
    17  
    18  type GlogHandler struct {
    19  	origin Handler
    20  
    21  	level     uint32
    22  	override  uint32
    23  	backtrace uint32
    24  
    25  	patterns  []pattern
    26  	siteCache map[uintptr]Lvl
    27  	location  string
    28  	lock      sync.RWMutex
    29  }
    30  
    31  func NewGlogHandler(h Handler) *GlogHandler {
    32  	return &GlogHandler{
    33  		origin: h,
    34  	}
    35  }
    36  
    37  func (h *GlogHandler) SetHandler(nh Handler) {
    38  	h.origin = nh
    39  }
    40  
    41  type pattern struct {
    42  	pattern *regexp.Regexp
    43  	level   Lvl
    44  }
    45  
    46  func (h *GlogHandler) Verbosity(level Lvl) {
    47  	atomic.StoreUint32(&h.level, uint32(level))
    48  }
    49  
    50  func (h *GlogHandler) Vmodule(ruleset string) error {
    51  	var filter []pattern
    52  	for _, rule := range strings.Split(ruleset, ",") {
    53  
    54  		if len(rule) == 0 {
    55  			continue
    56  		}
    57  
    58  		parts := strings.Split(rule, "=")
    59  		if len(parts) != 2 {
    60  			return errVmoduleSyntax
    61  		}
    62  		parts[0] = strings.TrimSpace(parts[0])
    63  		parts[1] = strings.TrimSpace(parts[1])
    64  		if len(parts[0]) == 0 || len(parts[1]) == 0 {
    65  			return errVmoduleSyntax
    66  		}
    67  
    68  		level, err := strconv.Atoi(parts[1])
    69  		if err != nil {
    70  			return errVmoduleSyntax
    71  		}
    72  		if level <= 0 {
    73  			continue
    74  		}
    75  
    76  		matcher := ".*"
    77  		for _, comp := range strings.Split(parts[0], "/") {
    78  			if comp == "*" {
    79  				matcher += "(/.*)?"
    80  			} else if comp != "" {
    81  				matcher += "/" + regexp.QuoteMeta(comp)
    82  			}
    83  		}
    84  		if !strings.HasSuffix(parts[0], ".go") {
    85  			matcher += "/[^/]+\\.go"
    86  		}
    87  		matcher = matcher + "$"
    88  
    89  		re, _ := regexp.Compile(matcher)
    90  		filter = append(filter, pattern{re, Lvl(level)})
    91  	}
    92  
    93  	h.lock.Lock()
    94  	defer h.lock.Unlock()
    95  
    96  	h.patterns = filter
    97  	h.siteCache = make(map[uintptr]Lvl)
    98  	atomic.StoreUint32(&h.override, uint32(len(filter)))
    99  
   100  	return nil
   101  }
   102  
   103  func (h *GlogHandler) BacktraceAt(location string) error {
   104  
   105  	parts := strings.Split(location, ":")
   106  	if len(parts) != 2 {
   107  		return errTraceSyntax
   108  	}
   109  	parts[0] = strings.TrimSpace(parts[0])
   110  	parts[1] = strings.TrimSpace(parts[1])
   111  	if len(parts[0]) == 0 || len(parts[1]) == 0 {
   112  		return errTraceSyntax
   113  	}
   114  
   115  	if !strings.HasSuffix(parts[0], ".go") {
   116  		return errTraceSyntax
   117  	}
   118  	if _, err := strconv.Atoi(parts[1]); err != nil {
   119  		return errTraceSyntax
   120  	}
   121  
   122  	h.lock.Lock()
   123  	defer h.lock.Unlock()
   124  
   125  	h.location = location
   126  	atomic.StoreUint32(&h.backtrace, uint32(len(location)))
   127  
   128  	return nil
   129  }
   130  
   131  func (h *GlogHandler) Log(r *Record) error {
   132  
   133  	if atomic.LoadUint32(&h.backtrace) > 0 {
   134  
   135  		h.lock.RLock()
   136  		match := h.location == r.Call.String()
   137  		h.lock.RUnlock()
   138  
   139  		if match {
   140  
   141  			r.Lvl = LvlInfo
   142  
   143  			buf := make([]byte, 1024*1024)
   144  			buf = buf[:runtime.Stack(buf, true)]
   145  			r.Msg += "\n\n" + string(buf)
   146  		}
   147  	}
   148  
   149  	if atomic.LoadUint32(&h.level) >= uint32(r.Lvl) {
   150  		return h.origin.Log(r)
   151  	}
   152  
   153  	if atomic.LoadUint32(&h.override) == 0 {
   154  		return nil
   155  	}
   156  
   157  	h.lock.RLock()
   158  	lvl, ok := h.siteCache[r.Call.PC()]
   159  	h.lock.RUnlock()
   160  
   161  	if !ok {
   162  		h.lock.Lock()
   163  		for _, rule := range h.patterns {
   164  			if rule.pattern.MatchString(fmt.Sprintf("%+s", r.Call)) {
   165  				h.siteCache[r.Call.PC()], lvl, ok = rule.level, rule.level, true
   166  				break
   167  			}
   168  		}
   169  
   170  		if !ok {
   171  			h.siteCache[r.Call.PC()] = 0
   172  		}
   173  		h.lock.Unlock()
   174  	}
   175  	if lvl >= r.Lvl {
   176  		return h.origin.Log(r)
   177  	}
   178  	return nil
   179  }