github.com/jxskiss/gopkg@v0.17.3/zlog/filter.go (about)

     1  package zlog
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  )
     8  
     9  type perLoggerLevelFunc func(name string) (Level, bool)
    10  
    11  func buildPerLoggerLevelFunc(levelRules []string) (*levelTree, perLoggerLevelFunc, error) {
    12  	if len(levelRules) == 0 {
    13  		return nil, nil, nil
    14  	}
    15  	tree := &levelTree{}
    16  	for _, rule := range levelRules {
    17  		tmp := strings.Split(rule, "=")
    18  		if len(tmp) != 2 {
    19  			return nil, nil, fmt.Errorf("invalid per logger level rule: %s", rule)
    20  		}
    21  		name, levelName := tmp[0], tmp[1]
    22  		var level Level
    23  		if !level.unmarshalText([]byte(levelName)) {
    24  			return nil, nil, fmt.Errorf("unrecognized level: %s", levelName)
    25  		}
    26  		tree.root.insert(name, level)
    27  	}
    28  	return tree, tree.search, nil
    29  }
    30  
    31  type levelTree struct {
    32  	root radixNode
    33  }
    34  
    35  func (p *levelTree) search(name string) (Level, bool) {
    36  	level, found := p.root.search(name)
    37  	return level, found
    38  }
    39  
    40  type radixNode struct {
    41  	prefix     string
    42  	level      *Level
    43  	childNodes childNodes
    44  }
    45  
    46  type childNodes struct {
    47  	labels []byte
    48  	nodes  []*radixNode
    49  }
    50  
    51  func (nodes *childNodes) Len() int { return len(nodes.labels) }
    52  
    53  func (nodes *childNodes) Less(i, j int) bool { return nodes.labels[i] < nodes.labels[j] }
    54  
    55  func (nodes *childNodes) Swap(i, j int) {
    56  	nodes.labels[i], nodes.labels[j] = nodes.labels[j], nodes.labels[i]
    57  	nodes.nodes[i], nodes.nodes[j] = nodes.nodes[j], nodes.nodes[i]
    58  }
    59  
    60  func (n *radixNode) getLevel() (Level, bool) {
    61  	if n.level == nil {
    62  		return 0, false
    63  	}
    64  	return *n.level, true
    65  }
    66  
    67  func (n *radixNode) insert(name string, level Level) {
    68  	if name == "" {
    69  		n.level = &level
    70  		return
    71  	}
    72  
    73  	firstChar := name[0]
    74  	for i, label := range n.childNodes.labels {
    75  		if firstChar == label {
    76  			// Split based on the common prefix of the existing node and the new one.
    77  			child, prefixSplit := n.splitCommonPrefix(i, name)
    78  			child.insert(name[prefixSplit:], level)
    79  			return
    80  		}
    81  	}
    82  
    83  	// No existing node starting with this letter, so create it.
    84  	child := &radixNode{prefix: name, level: &level}
    85  	n.childNodes.labels = append(n.childNodes.labels, firstChar)
    86  	n.childNodes.nodes = append(n.childNodes.nodes, child)
    87  	sort.Sort(&n.childNodes)
    88  	return
    89  }
    90  
    91  func (n *radixNode) splitCommonPrefix(existingChildIndex int, name string) (*radixNode, int) {
    92  	child := n.childNodes.nodes[existingChildIndex]
    93  
    94  	if strings.HasPrefix(name, child.prefix) {
    95  		// No split needs to be done. Rather, the new name shares the entire
    96  		// prefix with the existing node, so the new node is just a child of
    97  		// the existing one. Or the new name is the same as the existing name,
    98  		// which means that we just move on to the next token.
    99  		// Either way, this return accomplishes that.
   100  		return child, len(child.prefix)
   101  	}
   102  
   103  	i := longestPrefix(name, child.prefix)
   104  	commonPrefix := name[:i]
   105  	child.prefix = child.prefix[i:]
   106  
   107  	// Create a new intermediary node in the place of the existing node, with
   108  	// the existing node as a child.
   109  	newNode := &radixNode{
   110  		prefix: commonPrefix,
   111  		childNodes: childNodes{
   112  			labels: []byte{child.prefix[0]},
   113  			nodes:  []*radixNode{child},
   114  		},
   115  	}
   116  	n.childNodes.nodes[existingChildIndex] = newNode
   117  	return newNode, i
   118  }
   119  
   120  func (n *radixNode) search(name string) (level Level, found bool) {
   121  	node := n
   122  	for {
   123  		nameLen := len(name)
   124  		if nameLen == 0 {
   125  			break
   126  		}
   127  		firstChar := name[0]
   128  		if child := node.getChild(firstChar); child != nil {
   129  			childPrefixLen := len(child.prefix)
   130  			if nameLen >= childPrefixLen && child.prefix == name[:childPrefixLen] {
   131  				name = name[len(child.prefix):]
   132  				node = child
   133  				continue
   134  			}
   135  		}
   136  		break
   137  	}
   138  	return node.getLevel()
   139  }
   140  
   141  func (n *radixNode) getChild(label byte) *radixNode {
   142  	num := len(n.childNodes.labels)
   143  	i := sort.Search(num, func(i int) bool {
   144  		return n.childNodes.labels[i] >= label
   145  	})
   146  	if i < num && n.childNodes.labels[i] == label {
   147  		return n.childNodes.nodes[i]
   148  	}
   149  	return nil
   150  }
   151  
   152  func (n *radixNode) dumpTree(prefix string) string {
   153  	var out string
   154  	if n.level != nil {
   155  		out += fmt.Sprintf("%s=%s\n", prefix+n.prefix, n.level.String())
   156  	}
   157  	for _, child := range n.childNodes.nodes {
   158  		out += child.dumpTree(prefix + n.prefix)
   159  	}
   160  	return out
   161  }
   162  
   163  // longestPrefix finds the length of the shared prefix of two strings.
   164  func longestPrefix(k1, k2 string) int {
   165  	max := len(k1)
   166  	if l := len(k2); l < max {
   167  		max = l
   168  	}
   169  	var i int
   170  	for i = 0; i < max; i++ {
   171  		if k1[i] != k2[i] {
   172  			break
   173  		}
   174  	}
   175  	return i
   176  }