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 }