教你用Golang写一个 color 日志库

BelleAlmeid 7年前
   <h2>前言</h2>    <p>在计算机里面,ansi转义码是使用带内信号去控制格式化,颜色,或者其他的输出选项在视频流或者文本终端中的一种办法。编码这些格式化信息,就是在确定的字节序列中,把上述所说的ansi码嵌入到这个文本中。终端会去寻找命令去解释这些字符,而不是把它看作简单的字符码(ascii)。</p>    <p>1970年提出的ansi码,但是直到1980年的早期才普及在了迷你主机和大型机房中。它被使用在早期的电子公告板上,对比之前缺乏光标移动的系统,它改善了显示的效果,这导致了它被广泛的使用。</p>    <p>尽管硬件文本终端,在21世纪已经日益稀少。但是不动摇ansi标准的影响。因为大部分的文本模拟器的解释工作,至少还有相当一部分的文本存在ansi转义序列。唯一的例外就是微软的win32 console。不过这些在微软升级到window10之后已经被解决了。</p>    <p>所以这个古老的协议对我们现在的文本输出依然是有很重要的影响。</p>    <h3>一条小命令</h3>    <pre>  <code class="language-go">echo-e"\033[1;31mI ♡ You \e[0m"  </code></pre>    <p>output:</p>    <p><img src="https://simg.open-open.com/show/dbc7fb3d616e3e5b5f76e21c2ef06c4e.jpg"></p>    <p>不上图我写什么文档,对吧。这条命令可以用来简单的告白用。送给大家了。从这里我们引出了ansi对文本颜色的输出影响,看,就是图中字符的颜色发生了变化。利用这样的性质我们今天就要分享一下如何写一个彩色的日子库(color log)</p>    <h3>CSI</h3>    <p>转义序列使用ESC控制字符开始,对于2个字符序列,第二个字符是ASCII的64到95。(@到_,还有所有大写英文字母和[]\^),然而,序列中大多数是超过2个字符的,并以ESC控制字符和左中括号开始。序列被称作CSI,即控制序列引导器或者控制序列启动器的简称。这个序列的最后一个字符是在ASCII范围64到126。也还有一个单字符的CSI (155/0x9B/0233)ESC[,这两个字符序列比单个字符形式用的更多,细节参看C0和C1控制编码。(下文会添加文档的链接),使用UTF-8编码的终端上,两种形式都使用2字节(CSI in UTF-8 is 0xC2, 0x9B),但ESC[序列更加明了。</p>    <h3>文本颜色</h3>    <p>文本颜色(和SGR (Select Graphic Rendition)参数)使用CSI n1 [;n2 [; ...]] m 序列来处理,如上所示,序列中每一个n1, n2, ...就是一个SGR参数。因此,例如,你使用30~37表示前景色,40~47表示背景色。下图是一张颜色过渡图。</p>    <p><img src="https://simg.open-open.com/show/7bbd6126825cbd68f9587924810b33c9.jpg"></p>    <h3>开始编码</h3>    <pre>  <code class="language-go">packageutil    import (   "fmt"   "time"  )    const (  color_red=uint8(iota+ 91)  color_green  color_yellow  color_blue  color_magenta//洋红    info= "[INFO]"  trac= "[TRAC]"  erro= "[ERRO]"  warn= "[WARN]"  succ= "[SUCC]"  )    // see complete color rules in document in https://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-ecma48-13  funcTrace(formatstring,a...interface{}) {  prefix:=yellow(trac)  fmt.Println(formatLog(prefix),fmt.Sprintf(format,a...))  }    funcInfo(formatstring,a...interface{}) {  prefix:=blue(info)  fmt.Println(formatLog(prefix),fmt.Sprintf(format,a...))  }    funcSuccess(formatstring,a...interface{}) {  prefix:=green(succ)  fmt.Println(formatLog(prefix),fmt.Sprintf(format,a...))  }    funcWarning(formatstring,a...interface{}) {  prefix:=magenta(warn)  fmt.Println(formatLog(prefix),fmt.Sprintf(format,a...))  }    funcError(formatstring,a...interface{}) {  prefix:=red(erro)  fmt.Println(formatLog(prefix),fmt.Sprintf(format,a...))  }    func red(sstring) string {   returnfmt.Sprintf("\x1b[%dm%s\x1b[0m",color_red,s)  }    func green(sstring) string {   returnfmt.Sprintf("\x1b[%dm%s\x1b[0m",color_green,s)  }    func yellow(sstring) string {   returnfmt.Sprintf("\x1b[%dm%s\x1b[0m",color_yellow,s)  }    func blue(sstring) string {   returnfmt.Sprintf("\x1b[%dm%s\x1b[0m",color_blue,s)  }    func magenta(sstring) string {   returnfmt.Sprintf("\x1b[%dm%s\x1b[0m",color_magenta,s)  }    func formatLog(prefixstring) string {   returntime.Now().Format("2006/01/02 15:04:05") + " " +prefix+ " "  }  </code></pre>    <p>上面就是一个完整的彩色log的代码</p>    <p>输出的效果:</p>    <p><img src="https://simg.open-open.com/show/072b40353f5ad6c3a5abd683152f0187.jpg"></p>    <h2>完整代码</h2>    <p><a href="/misc/goto?guid=4959731388931328548" rel="nofollow,noindex">完整的colorlog代码</a> <a href="/misc/goto?guid=4959731389028416000" rel="nofollow,noindex">测试代码</a> 如果你需要在本地测试,请确保你搭建了正确的go开发环境,并且down下 <a href="/misc/goto?guid=4959731389120041273" rel="nofollow,noindex">https://github.com/liyu4/chill</a> 这个项目。找到util单元</p>    <pre>  <code class="language-go">yourpath指的是你的项目路径。  cd yourpath/chill/util  go test-v  </code></pre>    <h2>后记</h2>    <p>在其中 \x1b[ 实现CSI:</p>    <p>转换前景色为黑色,使用\x1b[30m</p>    <p>转换为红色,使用\x1b[31m</p>    <p>如果使用加粗参数,灰色写作\x1b[30;1m</p>    <p>获取红色加粗,使用\x1b[31;1m</p>    <p>重置颜色为缺省值,使用\x1b[39;49m (或者使用 \x1b[0m 重置所有属性)</p>    <p>\033[0m 重置为正常</p>    <p>\033[1m 设置高亮度或加粗</p>    <p>\033[4m 下划线</p>    <p>\033[5m 闪烁</p>    <p>\033[7m 反显</p>    <p>\033[8m 消隐</p>    <p>\033[30m -- /33[37m 设置前景色</p>    <p>\033[40m -- /33[47m 设置背景色</p>    <p>控制符ESC的常用表示方法\e、\x1b(\x1B)、\033都可以</p>    <p>\e 指代Escape,对应八进制\033,对应十六进制\x1b</p>    <h3>参考文档</h3>    <p><a href="/misc/goto?guid=4959731389204243504" rel="nofollow,noindex">ansi转义序列</a> <a href="/misc/goto?guid=4959731389288591611" rel="nofollow,noindex">中文文档</a></p>    <p> </p>    <p>来自:https://www.zybuluo.com/aliasliyu4/note/612147</p>    <p> </p>