cherrypy.lib.cpstats模块

cpstats,用于收集和报告程序统计数据的包。

概述

程序运行的统计数据是非常宝贵的监视和调试工具。不幸的是,收集和报告这些关键值通常是临时的。该包旨在增加一个收集统计性能数据的集中场所,一个记录数据的结构,该结构提供将数据外推到更有用的信息中,以及一种向人类调查人员和监测软件提供该数据的方法。让我们更详细地分析每一个问题。

数据收集

就像 Python 一样 logging 模块为收集和发送消息提供了一个通用的可导入的工具,性能统计数据将从类似的通用机制中获益,并且可以 not 要求希望收集统计信息的每个包导入第三方模块。因此,我们选择重新使用 logging 通过添加 statistics 反对它。

logging.statistics 对象是嵌套的dict。它不是自定义类,因为这样会:

  1. 需要库和应用程序导入第三方模块才能参与

  2. 抑制外推方法和报告工具的创新,以及

  3. 慢一点。

但是,关于dict.的结构有一些规范:

{
  +----"SQLAlchemy": {
  |        "Inserts": 4389745,
  |        "Inserts per Second":
  |            lambda s: s["Inserts"] / (time() - s["Start"]),
  |  C +---"Table Statistics": {
  |  o |        "widgets": {-----------+
N |  l |            "Rows": 1.3M,      | Record
a |  l |            "Inserts": 400,    |
m |  e |        },---------------------+
e |  c |        "froobles": {
s |  t |            "Rows": 7845,
p |  i |            "Inserts": 0,
a |  o |        },
c |  n +---},
e |        "Slow Queries":
  |            [{"Query": "SELECT * FROM widgets;",
  |              "Processing Time": 47.840923343,
  |              },
  |             ],
  +----},
}

这个 logging.statistics 口述有四个级别。最顶层只不过是一组用于引入模块化的名称,通常是沿着包名称的行。例如,如果sqlAlchemy项目想要参与,它可能会填充该项。 logging.statistics['SQLAlchemy'] ,其值将是第二层dict,我们称之为“命名空间”。名称空间有助于多个包避免键名冲突,并使报表更易于读取和引导。如果需要,sqlAlchemy的维护人员应该可以自由地使用多个命名空间(例如“sqlAlchemy orm”)。请注意,命名空间名称上没有大小写或其他语法约束;它们应该被人类选择为可读性最高(既不太短也不太长)。

然后,每个名称空间都是命名统计值的dict,例如“requests/sec”或“uptime”。您应该选择在报表上看起来不错的名称:空格和大写字母都可以。

除了scalars之外,名称空间中的值可以是(第三层)dict,也可以是名为“collection”的列表。例如,樱桃 StatsTool 跟踪“请求”集合中每个请求正在执行(或最近完成)的操作,其中每个键都是线程ID;子集合中的每个值都必须是第四个dict(whew!)每个线程的统计数据。我们将集合中的每个子集合称为“记录”。同样地, StatsTool 还保留一个慢速查询列表,其中每个记录依次包含有关每个慢速查询的数据。

名称空间或记录中的值也可以是函数,这使我们能够:

外推

统计数据的收集需要很快,尽可能接近于宿主程序无法察觉的数据。例如,这要求我们最小化I/O,但在Python中,这也意味着我们需要最小化函数调用。因此,在设计名称空间和记录值时,请尝试插入现有的最基本的标量值。

然而,到了报告收集到的数据的时候,我们通常可以更自由地进行计算。因此,每当报告工具(如提供的 StatsPage cherrypy类)获取 logging.statistics 为了报告,他们首先打电话 extrapolate_statistics (通过整个 statistics 听写是唯一的论点)。这会对统计数据dict进行深度复制,以便报告工具可以对其进行迭代,甚至可以在不损害原始数据的情况下对其进行更改。但它也通过调用dict中的任何函数来扩展它们。例如,您可能在命名空间中有一个值为“lambda scope:time.time()”的“当前时间”条目。“scope”参数是当前的名称空间dict(或者record,如果我们现在扩展其中一个名称空间dict),允许您访问现有的静态条目。如果你真的很邪恶,你甚至可以一次修改多个条目。

但是,不要试图计算一个条目,然后在进一步的外推中使用它的值;不能保证函数调用的顺序。这可能导致一定数量的重复工作(或者重新设计模式),但这比使规范复杂化要好。

在整个事情被推断出来之后,是时候:

报告

这个 StatsPage 班级抓住 logging.statistics 听写,全部外推,然后将其转换为HTML以便于查看。每个名称空间都有自己的头和属性表,并为每个集合添加一个额外的表。这不是统计规范的一部分;其他工具可以根据自己的喜好进行格式化。

您可以通过更新statspage.formatting来控制输出哪些列以及如何对它们进行格式化,这是一个反映键和嵌套的dict。 logging.statistics .区别在于,它没有数据值,而是有格式化值。对给定的键使用none向statspage指示不应输出给定的列。使用带格式的字符串(如“%.3f”)插入值,或使用可调用字符串(如lambda v:v.isoformat())进行更高级的格式设置。格式化dict中未提到的任何条目的输出都保持不变。

监测

虽然HTML输出很难用统计数据为每个<td>分配唯一的ID,但最好是提取/cpstats/data,它输出整个(外推的)。 logging.statistics json格式的dict。这可能更容易解析,并且没有任何格式控件,因此您可以以一致的序列化格式获得“原始”数据。注意:目前还没有针对日期时间对象的处理方法。如果可以,现在就尝试time.time()。Nagios可能会感谢你。

关闭收藏

建议每个命名空间都有一个“已启用”项,如果为false,则停止收集(但不报告)统计数据。应用程序应通过将这些条目设置为false或true(如果存在)来提供暂停和恢复收集的控件。

使用

要收集Cherrypy应用程序的统计信息,请执行以下操作:

from cherrypy.lib import cpstats
appconfig['/']['tools.cpstats.on'] = True

要根据您自己的代码收集统计信息,请执行以下操作:

import logging
# Initialize the repository
if not hasattr(logging, 'statistics'): logging.statistics = {}
# Initialize my namespace
mystats = logging.statistics.setdefault('My Stuff', {})
# Initialize my namespace's scalars and collections
mystats.update({
    'Enabled': True,
    'Start Time': time.time(),
    'Important Events': 0,
    'Events/Second': lambda s: (
        (s['Important Events'] / (time.time() - s['Start Time']))),
    })
...
for event in events:
    ...
    # Collect stats
    if mystats.get('Enabled', False):
        mystats['Important Events'] += 1

要报告统计信息:

root.cpstats = cpstats.StatsPage()

设置统计报告格式:

See 'Reporting', above.
class cherrypy.lib.cpstats.ByteCountWrapper(rfile)[源代码]

基类:object

像对象一样包装文件,计算读取的字节数。

close()[源代码]
next()[源代码]
read(size=- 1)[源代码]
readline(size=- 1)[源代码]
readlines(sizehint=0)[源代码]
class cherrypy.lib.cpstats.StatsPage[源代码]

基类:object

data()[源代码]
formatting = {'CherryPy Applications': {'Bytes Read/Request': '%.3f', 'Bytes Read/Second': '%.3f', 'Bytes Written/Request': '%.3f', 'Bytes Written/Second': '%.3f', 'Current Time': <function iso_format>, 'Enabled': <function pause_resume.<locals>._pause_resume>, 'Requests': {'Bytes Read': '%s', 'Bytes Written': '%s', 'End Time': None, 'Processing Time': '%.3f', 'Start Time': None}, 'Requests/Second': '%.3f', 'Slow Queries': {'End Time': None, 'Processing Time': '%.3f', 'Start Time': <function iso_format>}, 'Start Time': <function iso_format>, 'Total Time': '%.3f', 'URI Set Tracking': {'Avg': '%.3f', 'Max': '%.3f', 'Min': '%.3f', 'Sum': '%.3f'}, 'Uptime': '%.3f'}, 'CherryPy WSGIServer': {'Connections/second': '%.3f', 'Enabled': <function pause_resume.<locals>._pause_resume>, 'Start time': <function iso_format>}}
get_dict_collection(v, formatting)[源代码]

返回( [报头] , [rows] )对于给定的集合。

get_list_collection(v, formatting)[源代码]

返回( [报头] , [子程序] )对于给定的集合。

get_namespaces()[源代码]

为每个命名空间生成(标题、标量、集合)。

index()[源代码]
pause(namespace)[源代码]
resume(namespace)[源代码]
class cherrypy.lib.cpstats.StatsTool[源代码]

基类:cherrypy._cptools.Tool

记录有关当前请求的各种信息。

_setup()[源代码]

将此工具挂接到cherrypy.request中。

当工具在config中“打开”时,标准CherryPy请求对象将自动调用此方法。

record_start()[源代码]

记录请求的开始。

record_stop(uriset=None, slow_queries=1.0, slow_queries_count=100, debug=False, **kwargs)[源代码]

记录请求的结束。

cherrypy.lib.cpstats._get_threading_ident()[源代码]
cherrypy.lib.cpstats.average_uriset_time(s)[源代码]
cherrypy.lib.cpstats.extrapolate_statistics(scope)[源代码]

返回给定范围的外推副本。

cherrypy.lib.cpstats.iso_format(v)[源代码]
cherrypy.lib.cpstats.locale_date(v)[源代码]
cherrypy.lib.cpstats.pause_resume(ns)[源代码]
cherrypy.lib.cpstats.proc_time(s)[源代码]