github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/log/handler_glog.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:41</date> 10 //</624342646499840000> 11 12 13 package log 14 15 import ( 16 "errors" 17 "fmt" 18 "regexp" 19 "runtime" 20 "strconv" 21 "strings" 22 "sync" 23 "sync/atomic" 24 ) 25 26 //当用户vmodule模式无效时返回errvmodulesyntax。 27 var errVmoduleSyntax = errors.New("expect comma-separated list of filename=N") 28 29 //当用户回溯模式无效时,返回errTraceSyntax。 30 var errTraceSyntax = errors.New("expect file.go:234") 31 32 //Gloghandler是一个日志处理程序,模拟谷歌的过滤功能。 33 //glog logger:设置全局日志级别;用callsite模式覆盖 34 //匹配;并在特定位置请求回溯。 35 type GlogHandler struct { 36 origin Handler //此包装的原始处理程序 37 38 level uint32 //当前日志级别,可原子访问 39 override uint32 //标记是否使用原子可访问的重写 40 backtrace uint32 //标记是否设置回溯位置 41 42 patterns []pattern //要重写的模式的当前列表 43 siteCache map[uintptr]Lvl //调用站点模式计算的缓存 44 location string //文件:进行堆栈转储的行位置 45 lock sync.RWMutex //锁定保护覆盖模式列表 46 } 47 48 //newgloghandler创建了一个新的日志处理程序,其过滤功能与 49 //谷歌的Glog日志。返回的处理程序实现处理程序。 50 func NewGlogHandler(h Handler) *GlogHandler { 51 return &GlogHandler{ 52 origin: h, 53 } 54 } 55 56 //sethandler更新处理程序以将记录写入指定的子处理程序。 57 func (h *GlogHandler) SetHandler(nh Handler) { 58 h.origin = nh 59 } 60 61 //模式包含vmodule选项的筛选器,保持详细级别 62 //和要匹配的文件模式。 63 type pattern struct { 64 pattern *regexp.Regexp 65 level Lvl 66 } 67 68 //冗长设置了发光的冗长天花板。单个包装的冗长程度 69 //源文件可以使用vmodule来提升。 70 func (h *GlogHandler) Verbosity(level Lvl) { 71 atomic.StoreUint32(&h.level, uint32(level)) 72 } 73 74 //vmodule设置glog冗长模式。 75 // 76 //参数的语法是以逗号分隔的pattern=n列表,其中 77 //模式是文本文件名或“glob”模式匹配,n是v级别。 78 // 79 //例如: 80 // 81 //pattern=“gopher.go=3” 82 //在所有名为“gopher.go”的go文件中将v级别设置为3 83 // 84 //模式=“FoO=3” 85 //将导入路径以“foo”结尾的任何包的所有文件中的v设置为3 86 // 87 /*pattern=“foo/*=3” 88 //在导入路径包含“foo”的任何包的所有文件中,将v设置为3 89 func(h*gloghandler)vmodule(ruleset string)错误 90 var过滤器[]模式 91 对于u,规则:=range strings.split(ruleset,“,”) 92 //可以忽略尾随逗号等空字符串 93 如果len(rule)==0 94 持续 95 } 96 //确保我们有模式=级别筛选规则 97 部分:=strings.split(rule,“=”) 98 如果莱恩(零件)!= 2 { 99 返回errvmodulesyntax 100 } 101 零件[0]=字符串.trimspace(零件[0]) 102 部件[1]=字符串。Trimspace(部件[1]) 103 如果len(零件[0])=0 len(零件[1])=0 104 返回errvmodulesyntax 105 } 106 //分析级别,如果正确,则组装筛选规则 107 级别,错误:=strconv.atoi(部件[1]) 108 如果犯错!= nIL{ 109 返回errvmodulesyntax 110 } 111 如果水平<=0 112 继续//忽略。这是无害的,但没有必要支付管理费用。 113 } 114 //将规则模式编译为正则表达式 115 匹配器=:“*” 116 对于u,comp:=range strings.split(parts[0],“/”) 117 如果comp=“*” 118 匹配器+=“(/.*)?” 119 其他,如果有!=“{” 120 matcher+=“/”+regexp.quoteteta(comp) 121 } 122 } 123 如果!字符串.hassuffix(部件[0],“.go”); 124 Matcher+=“/[^/]+\\.go” 125 } 126 matcher=matcher+“$” 127 128 re,:=regexp.compile(matcher) 129 filter=append(filter,pattern re,lvl(level)) 130 } 131 //换掉新过滤系统的vmodule模式 132 H.Lo.C.() 133 延迟h.lock.unlock() 134 135 h.patterns=过滤器 136 h.sitecache=make(映射[uintptr]lvl) 137 atomic.storeuint32(&h.override,uint32(len(filter))) 138 139 返回零 140 } 141 142 //backtraceat设置glog backtrace位置。当设置为文件和行时 143 //保存日志语句的数字,堆栈跟踪将写入信息 144 //每当执行命中该语句时记录。 145 / / 146 //与vmodule不同,“.go”必须存在。 147 func(h*gloghandler)backtraceat(location string)错误 148 //确保回溯位置包含两个非空元素 149 部件:=strings.split(位置,“:”) 150 如果莱恩(零件)!= 2 { 151 返回errtraceSyntax 152 } 153 零件[0]=字符串.trimspace(零件[0]) 154 部件[1]=字符串。Trimspace(部件[1]) 155 如果len(零件[0])=0 len(零件[1])=0 156 返回errtraceSyntax 157 } 158 //确保.go前缀存在且该行有效 159 如果!字符串.hassuffix(部件[0],“.go”); 160 返回errtraceSyntax 161 } 162 如果uuErr:=strconv.atoi(第[1]部分);Err!= nIL{ 163 返回errtraceSyntax 164 } 165 //一切似乎都有效 166 H.Lo.C.() 167 延迟h.lock.unlock() 168 169 H.位置=位置 170 atomic.storeuint32(&h.backtrace,uint32(len(location))) 171 172 返回零 173 } 174 175 //日志实现handler.log,通过全局、本地筛选日志记录 176 //和回溯过滤器,如果允许它通过,最后发出它。 177 func(h*gloghandler)日志(r*record)错误 178 //如果请求回溯,请检查这是否是调用站点 179 如果atomic.loaduint32(&h.backtrace)>0 180 //这里的一切都很慢。尽管我们可以缓存呼叫站点 181 //和vmodule一样,回溯非常罕见,不值得额外增加 182 / /复杂性。 183 H.锁定() 184 匹配:=h.location==r.call.string() 185 h.lock.runlock()。 186 187 如果匹配{ 188 //调用站点匹配,将日志级别提升为INFO并收集堆栈 189 吕林佛 190 191 buf:=make([]字节,1024*1024) 192 buf=buf[:runtime.stack(buf,true)] 193 r.msg+=“\n\n”+字符串(buf) 194 } 195 } 196 //如果全局日志级别允许,则快速跟踪日志记录 197 如果atomic.loadunt32(&h.level)>=uint32(r.lvl) 198 返回h.origin.log(r) 199 } 200 //如果不存在本地重写,则快速跟踪跳过 201 如果atomic.loaduint32(&h.override)==0 202 返回零 203 } 204 //检查调用站点缓存中以前计算的日志级别 205 H.锁定() 206 lvl,确定:=h.sitecache[r.call.pc()] 207 h.lock.runlock()。 208 209 //如果我们还没有缓存调用站点,请计算它 210 如果!好吧{ 211 H.Lo.C.() 212 对于u,规则:=范围h.模式 213 if rule.pattern.matchString(fmt.sprintf(“%+s”,r.call)) 214 h.sitecache[r.call.pc()],lvl,ok=rule.level,rule.level,真 215 打破 216 } 217 } 218 //如果没有匹配的规则,记得下次删除日志 219 如果!好吧{ 220 h.sitecache[r.call.pc()]=0 221 } 222 锁定() 223 } 224 如果lvl>=r.lvl 225 返回h.origin.log(r) 226 } 227 返回零 228 } 229