为什么要进行日志测试和如何进行日志测试

  13 expected_postquery_event = (postquery["hits"]["total"] == 1)

  14 unexpected_connectionfailed_event = (connectionfailed["hits"]["total"] == 0)

  15

  16 expected_prequery_event && expected_postquery_event && unexpected_connectionfailed_event

  我们使用'json' Ruby gem包去解析查询前后的curl搜索结果,这些结果是我们先前保存在重命名后的文件中的(前10行)。第12行到第14行说明了我们对测试结果的预期(即日志流中应该包含一个单一的DatabasePreQuery事件,一个单一的DatabasePostQuery事件,并且没有DatabaseConnectionFailed或其他事件)。最后一行是实际的测试(如果我们的期望都是正确的Ruby将返回“ture”,否则就会返回false)。

  更复杂的测试(或对事件的分析)可能,比如说,需要在给定时间内搜索所有数据库事件、计算查询次数、故障等。然而,使用的方法和上面描述的是一样的,只是在一个较大的JSON响应包中要执行稍微复杂的迭代代码。

  这是一个对这类测试进行curl查询的例子(你也可以在 GitHub 找到它):

  $ curl -XGET 'http://localhost:9200/_search?q=message:Database*&pretty' -d '

  {

  "query" : {

  "range" : {

  "@timestamp" : {

  "gte" : "now-10m/m"

  }

  }

  }

  }'

  我们也可以在系统中跟踪一条单一的执行路径,使用当活动最初被启动时我们注入系统的相关的ID:比如,用户点击一个按钮或一个批量作业开始。只要关联ID对于我们在日志聚合工具中的搜索是能够保证唯一的,我们将看到只与该查询有关的结果。

  通过搜索关联ID,我们就可以精确地确定到底是哪些服务器或容器参与了请求的处理和重建请求的过程。有一些商业工具能提供这样的功能,但通过我们自己建立这些功能中的一部分功能,我们也可以获得对系统运行情况的有益见解。

  测试日志的用户故事

  比如说,我们有一个关于法律市场的基于浏览器的系统,这个系统允许专业的法律从业者来编辑和保存文档。将文档数据保存到文档存储数据库,并将消息放在消息队列上。然而,作为一个国家的监管制度的一部分,我们需要确保该文件符合一定的要求,所以需要提供“审计”服务监听消息队列上的消息,然后检查最近更新过的文档:

  在这里,我们已经有了一个异步的、分布式的系统。当在浏览器中应用程序明确地显示了成功——该文档已经成功更新时,可能实际上还需要启动进一步的工作流程(例如,如果文档审计发现了文件的问题)。

  通过使用事件ID和事务跟踪的日志聚合功能,我们就有能力断言,基于在主要事务系统中的某些操作,某些特定的日志消息应该出现在日志聚合系统之中:

  具体来说,如果我们知道,审计服务应以事件ID“AuditRecordCreated”写一条日志信息,我们在Web应用程序的用户搜索完成后,就可以运行一个测试来寻找那个ID:

  有了这个能力去断言我们对系统的行为的期望之后,我们可以写出类似这样的行为水平测试:

  Given I run a scenario as a Lawyer

  And I create a document

  [And I wait 5 seconds]

  When I search the logs API

  Then I should find a recent entry for “AuditRecordCreated”

  这意味着,日志记录已经成为了一种可以扩展我们对分布式系统的测试的方式,只要能够明确在某些具体时刻我们期望哪些行为或事件会被记录下来,然后再去搜索就好了。

  结论

  对分布式的、可扩展的系统(通常包含不稳定的基础设施)进行故障排除,取决于是否有足够的日志记录和搜索设备。我们需要记录发生在我们的系统中的重要的事件,并通过一个唯一的关联ID将它们关联到一个特定的业务交易(如包裹快递)上。日志聚合和搜索工具使我们能够用一个简单的ID查询来跟踪终端到终端的业务交易。我们也可以查询一个类别的事件以调查组件或系统故障(例如,为了找到导致某次故障的所有的数据库事件)。最后,我们看到,我们可以而且我们也应该以与功能需求类似的方式来测试这些操作需求,即通过用户故事和BDD的场景。