github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/log/doc.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  //</624342646269153280>
    11  
    12  /*
    13  包log15为最佳实践日志提供了一个独立、简单的工具包,即
    14  人和机器都可读。它是根据标准库的IO和NET/HTTP建模的
    15  包装。
    16  
    17  此包强制您只记录键/值对。键必须是字符串。值可能是
    18  任何你喜欢的类型。默认输出格式为logfmt,但也可以选择使用
    19  如果你觉得合适的话,就改为JSON。以下是您登录的方式:
    20  
    21      log.info(“访问页面”,“路径”,r.url.path,“用户ID”,user.id)
    22  
    23  这将输出如下行:
    24  
    25       lvl=info t=2014-05-02t16:07:23-0700 msg=“page accessed”path=/org/71/profile user_id=9
    26  
    27  入门
    28  
    29  要开始,您需要导入库:
    30  
    31      导入日志“github.com/inconschrevable/log15”
    32  
    33  
    34  现在您可以开始记录了:
    35  
    36      FUNC主体()
    37          log.info(“程序启动”,“args”,os.args())
    38      }
    39  
    40  
    41  公约
    42  
    43  因为记录人类有意义的信息是很常见的,也是很好的实践,所以每个人的第一个论点
    44  日志记录方法是*隐式*键'msg'的值。
    45  
    46  此外,为消息选择的级别将自动添加键“lvl”,因此
    47  将当前时间戳与键“t”一起使用。
    48  
    49  您可以将任何附加上下文作为一组键/值对提供给日志函数。允许登录15
    50  你喜欢简洁、有序和快速,而不是安全。这是一个合理的折衷
    51  日志功能。您不需要显式地声明键/值,log15理解它们是交替的
    52  在变量参数列表中:
    53  
    54      log warn(“大小越界”,“低”,“低”,“高”,“高”,“val”,val)
    55  
    56  如果您确实支持类型安全,则可以选择传递一个log.ctx:
    57  
    58      log.warn(“大小越界”,log.ctx“低”:下限,“高”:上限,“val”:val)
    59  
    60  
    61  上下文记录器
    62  
    63  通常,您希望将上下文添加到记录器中,以便跟踪与之关联的操作。一个HTTP协议
    64  请求就是一个很好的例子。您可以轻松地创建具有自动包含上下文的新记录器。
    65  每条记录线:
    66  
    67      请求记录器:=log.new(“path”,r.url.path)
    68  
    69      /以后
    70      requestlogger.debug(“db txn commit”,“duration”,txtimer.finish())
    71  
    72  这将输出一条日志行,其中包含连接到记录器的路径上下文:
    73  
    74      lvl=dbug t=2014-05-02t16:07:23-0700 path=/repo/12/add25oke msg=“db txn commit”持续时间=0.12
    75  
    76  
    77  处理程序
    78  
    79  处理程序接口定义日志行的打印位置和格式。汉德勒是
    80  受net/http处理程序接口启发的单个接口:
    81  
    82      类型处理程序接口
    83          日志(R*记录)错误
    84      }
    85  
    86  
    87  处理程序可以筛选记录、格式化它们,或者分派到多个其他处理程序。
    88  此包为常见的日志记录模式实现了许多处理程序
    89  易于组合以创建灵活的自定义日志结构。
    90  
    91  下面是一个将logfmt输出打印到stdout的示例处理程序:
    92  
    93      处理程序:=log.streamHandler(os.stdout,log.logfmtformat())
    94  
    95  下面是一个示例处理程序,它遵从其他两个处理程序。一个处理程序只打印记录
    96  从logfmt中的rpc包到标准输出。其他打印错误级别的记录
    97  json格式输出到文件/var/log/service.json中或更高版本
    98  
    99      处理程序:=log.multihandler(
   100          log.lvlfilterhandler(log.lvlerror,log.must.filehandler(“/var/log/service.json”,log.jsonformat()),
   101          log.matchfilterhandler(“pkg”,“app/rpc”log.stdouthandler())
   102      )
   103  
   104  记录文件名和行号
   105  
   106  此包实现了三个处理程序,将调试信息添加到
   107  Context、CallerFileHandler、CallerFundler和CallerStackHandler。这里是
   108  将每个日志记录调用的源文件和行号添加到
   109  语境。
   110  
   111      h:=log.CallerFileHandler(log.stdouthandler)
   112      log.root().sethandler(h)
   113      …
   114      log.error(“打开文件”,“err”,err)
   115  
   116  这将输出如下行:
   117  
   118      lvl=eror t=2014-05-02t16:07:23-0700 msg=“open file”err=“file not found”caller=data.go:42
   119  
   120  下面是一个记录调用堆栈而不仅仅是调用站点的示例。
   121  
   122      h:=log.callerstackhandler(“%+v”,log.stdouthandler)
   123      log.root().sethandler(h)
   124      …
   125      log.error(“打开文件”,“err”,err)
   126  
   127  这将输出如下行:
   128  
   129      lvl=eror t=2014-05-02t16:07:23-0700 msg=“open file”err=“找不到文件”stack=“[pkg/data.go:42 pkg/cmd/main.go]”
   130  
   131  “%+v”格式指示处理程序包含源文件的路径
   132  相对于编译时gopath。github.com/go-stack/stack包
   133  记录可用的格式化谓词和修饰符的完整列表。
   134  
   135  自定义处理程序
   136  
   137  处理程序接口非常简单,编写自己的接口也很简单。让我们创建一个
   138  尝试写入一个处理程序的示例处理程序,但如果失败,则返回到
   139  写入另一个处理程序,并包括尝试写入时遇到的错误
   140  去初选。当试图通过网络套接字登录时,这可能很有用,但如果是这样的话
   141  无法将这些记录记录记录到磁盘上的文件中。
   142  
   143      类型backuphandler结构
   144          主处理机
   145          辅助处理程序
   146      }
   147  
   148      func(h*backuphandler)日志(r*record)错误
   149          错误:=h.primary.log(r)
   150          如果犯错!= nIL{
   151              r.ctx=append(ctx,“主错误”,err)
   152              返回H.secondary.log(r)
   153          }
   154          返回零
   155      }
   156  
   157  此模式非常有用,以至于处理任意数量处理程序的通用版本
   158  包含在这个名为failhandler的库中。
   159  
   160  记录昂贵的操作
   161  
   162  有时,您希望记录计算非常昂贵的值,但不想支付
   163  如果您没有将日志记录级别提高到较高的详细级别,计算它们的价格。
   164  
   165  此包提供了一个简单的类型,用于注释要评估的日志记录操作。
   166  懒惰地,就在它即将被记录时,这样就不会在上游处理程序
   167  过滤掉它。只需将不带参数的任何函数与log.lazy类型一起包装。例如:
   168  
   169      func factorrsakey()(factors[]int)
   170          //返回一个非常大的数的因子
   171      }
   172  
   173      log.debug(“factors”,log.lazy factorsakey)
   174  
   175  如果由于任何原因(如错误级别的日志记录)未记录此消息,则
   176  从未对factorsakey进行过评估。
   177  
   178  动态上下文值
   179  
   180  可以使用相同的log.lazy机制将上下文附加到您希望成为的记录器上。
   181  在记录消息时计算,但在创建记录器时不计算。例如,让我们想象一下
   182  有玩家对象的游戏:
   183  
   184      类型播放器结构
   185          名称字符串
   186          活布尔
   187          日志记录器
   188      }
   189  
   190  你总是想记录一个玩家的名字,不管他们是活的还是死的,所以当你创建这个玩家时
   191  对象,可以执行以下操作:
   192  
   193      p:=&player name:name,alive:true
   194      p.logger=log.new(“名称”,p.name,“活动”,p.live)
   195  
   196  直到现在,即使玩家死了,日志记录程序仍会报告他们还活着,因为日志记录
   197  创建记录器时将计算上下文。通过使用惰性包装器,我们可以推迟评估
   198  玩家是否对每条日志消息都是活动的,这样日志记录将反映玩家的
   199  当前状态,无论何时写入日志消息:
   200  
   201      p:=&player name:name,alive:true
   202      isalive:=func()bool返回p.live
   203      player.logger=log.new(“名称”,p.name,“活动”,log.lazy isalive)
   204  
   205  终端格式
   206  
   207  如果log15检测到stdout是终端,它将配置默认值
   208  它的处理程序(即log.stdouthandler)使用TerminalFormat。这种格式
   209  为您的终端很好地记录,包括基于颜色编码的输出
   210  在日志级别上。
   211  
   212  错误处理
   213  
   214  因为log15允许您绕过类型系统,所以有几种方法可以指定
   215  日志函数的参数无效。例如,你可以包装一些不是
   216  带log.lazy的零参数函数,或传递不是字符串的上下文键。因为日志记录库
   217  通常是报告错误的机制,对于日志记录功能来说是很麻烦的
   218  返回错误。相反,log15通过向您提供以下保证来处理错误:
   219  
   220  -任何包含错误的日志记录仍将打印,并将错误解释为日志记录的一部分。
   221  
   222  -任何包含错误的日志记录都将包含上下文键log15_错误,使您能够轻松
   223  (如果您愿意,自动)检测您的任何日志记录调用是否传递了错误值。
   224  
   225  了解这一点,您可能会想知道为什么处理程序接口可以在其日志方法中返回错误值。处理程序
   226  只有当错误无法将其日志记录写入外部源时,才鼓励返回错误,例如
   227  Syslog守护程序没有响应。这允许构造有用的处理程序来处理这些失败。
   228  就像那个失败者。
   229  
   230  图书馆使用
   231  
   232  log15旨在对库作者有用,作为提供可配置的日志记录到
   233  他们图书馆的用户。在库中使用的最佳实践是始终禁用记录器的所有输出
   234  默认情况下,并提供库的使用者可以配置的公共记录器实例。像这样:
   235  
   236      包装你的衣服
   237  
   238      导入“github.com/inconschrevable/log15”
   239  
   240      var log=log.new()。
   241  
   242      函数()
   243          log.setHandler(log.discardHandler())
   244      }
   245  
   246  如果您的库用户愿意,可以启用它:
   247  
   248      导入“github.com/inconschrevable/log15”
   249      导入“example.com/yourlib”
   250  
   251      FUNC主体()
   252          处理程序:=//自定义处理程序设置
   253          yourlib.log.sethandler(处理程序)
   254      }
   255  
   256  附加记录器上下文的最佳实践
   257  
   258  将上下文附加到记录器的能力非常强大。你应该在哪里做,为什么?
   259  我喜欢将一个记录器直接嵌入到我的应用程序中的任何持久对象中,并添加
   260  唯一的跟踪上下文键。例如,假设我正在编写一个Web浏览器:
   261  
   262      类型选项卡结构
   263          URL字符串
   264          渲染*渲染上下文
   265          /…
   266  
   267          记录器
   268      }
   269  
   270      func newtab(url字符串)*tab_
   271          返回和标签{
   272              /…
   273              网址:
   274  
   275              记录器:log.new(“url”,url),
   276          }
   277      }
   278  
   279  当创建一个新的选项卡时,我会为它分配一个具有以下URL的记录器:
   280  该选项卡作为上下文,以便通过日志轻松跟踪。
   281  现在,每当我们对选项卡执行任何操作时,我们都将使用
   282  嵌入式记录器,它将自动包含选项卡标题:
   283  
   284      tab.debug(“移动位置”,“idx”,tab.idx)
   285  
   286  只有一个问题。如果标签URL改变了怎么办?我们可以
   287  使用log.lazy确保始终写入当前的URL,但是
   288  这意味着我们无法追踪标签的整个生命周期
   289  用户导航到新的URL后登录。
   290  
   291  相反,考虑一下要附加到记录器上的值
   292  与您考虑在SQL数据库模式中作为键使用的方法相同。
   293  如果可以使用在
   294  对象,这样做。但除此之外,log15的ext包有一个方便的randid
   295  函数来生成可能称为“代理键”的内容
   296  它们只是用于跟踪的随机十六进制标识符。回到我们的身边
   297  例如,我们希望像这样设置记录器:
   298  
   299          导入logext“github.com/inconschrevable/log15/ext”
   300  
   301          T:=和Tab {
   302              /…
   303              网址:
   304          }
   305  
   306          t.logger=log.new(“id”,logext.randid(8),“url”,log.lazy_t.geturl)
   307          返回T
   308  
   309  现在,即使在加载新的URL时,我们也会有一个唯一的可跟踪标识符,但是
   310  我们仍然可以在日志消息中看到选项卡的当前URL。
   311  
   312  必须
   313  
   314  对于所有可以返回错误的处理程序函数,都有一个版本
   315  函数,它不会返回错误,但会在失败时出现恐慌。它们都有
   316  在“必须”对象上。例如:
   317  
   318      log.must.filehandler(“/path”,log.jsonformat)
   319      log must.nethandler(“tcp”,“:1234”,log.jsonformat)
   320  
   321  灵感与信用
   322  
   323  以下所有优秀的项目都激发了这个图书馆的设计灵感:
   324  
   325  code.google.com/p/log4go
   326  
   327  github.com/op/go-logging
   328  
   329  github.com/technoweenie/grohl公司
   330  
   331  github.com/sirusen/logrus公司
   332  
   333  github.com/kr/logfmt
   334  
   335  github.com/spacemonkeygo/spacelog/空间日志
   336  
   337  Golang的stdlib,特别是IO和net/http
   338  
   339  名字
   340  
   341  https://xkcd.com/927/
   342  
   343  **/
   344  
   345  package log
   346