【问题标题】:How does Sentry aggregate errors?Sentry 如何汇总错误?
【发布时间】:2012-10-31 04:24:30
【问题描述】:

我正在使用 Sentry(在 django 项目中),我想知道如何正确聚合错误。我将某些用户操作记录为错误,因此没有底层系统异常,并且正在使用culprit 属性设置友好的错误名称。该消息是模板化的,并且包含一条通用消息(“用户 'x' 无法执行操作,因为 'y'”),但绝不完全相同(不同的用户,不同的条件)。

Sentry 显然在后台使用了一组属性来确定是否将错误聚合为相同的异常,但尽管查看了代码,但我无法弄清楚如何。

任何人都可以缩短我深入研究代码并告诉我需要设置哪些属性才能按我的意愿管理聚合的捷径吗?

[更新 1:事件分组]

这一行出现在 sentry.models.Group:

class Group(MessageBase):
    """
    Aggregated message which summarizes a set of Events.
    """
    ...

    class Meta:
        unique_together = (('project', 'logger', 'culprit', 'checksum'),)
    ...

这是有道理的——我现在设置的项目、记录器和罪魁祸首——问题是checksum。我将进一步调查,但是“校验和”表明二进制等价永远不会起作用 - 必须可以对具有不同属性的相同异常的实例进行分组?

[更新 2:事件校验和]

事件校验和来自sentry.manager.get_checksum_from_event方法:

def get_checksum_from_event(event):
    for interface in event.interfaces.itervalues():
        result = interface.get_hash()
        if result:
            hash = hashlib.md5()
            for r in result:
                hash.update(to_string(r))
            return hash.hexdigest()
    return hashlib.md5(to_string(event.message)).hexdigest()

下一站——interfaces 事件从何而来?

[更新 3:事件接口]

我发现interfaces 指的是描述传递给哨兵事件的数据的标准机制,并且我正在使用标准的sentry.interfaces.Messagesentry.interfaces.User 接口。

根据异常实例,这两者都将包含不同的数据 - 因此校验和永远不会匹配。有什么方法可以将这些从校验和计算中排除? (或者至少是 User 接口值,因为它必须不同 - 我可以标准化的 Message 接口值。)

[更新 4:解决方案]

以下是MessageUser 接口的两个get_hash 函数:

# sentry.interfaces.Message
def get_hash(self):
    return [self.message]

# sentry.interfaces.User
def get_hash(self):
    return []

看看这两个,只有Message.get_hash 接口会返回一个由get_checksum_for_event 方法获取的值,因此这是将返回的值(散列等)。最终效果是校验和仅根据消息进行评估 - 这在理论上意味着我可以标准化消息并保持用户定义的唯一性。

我已经在这里回答了我自己的问题,但希望我的调查对遇到同样问题的其他人有用。 (顺便说一句,作为其中的一部分,我还针对 Sentry 文档提交了拉取请求;-))

(任何使用/扩展 Sentry 和自定义接口的人请注意 - 如果您想避免您的接口被用于对异常进行分组,请返回一个空列表。)

【问题讨论】:

标签: django sentry


【解决方案1】:

我遇到了一个关于异常的常见问题。目前我们的系统只捕获异常,我很困惑为什么其中一些合并到一个错误中,而另一些则没有。 根据您上面的信息,我提取了“get_hash”方法并试图找到“引发”我的错误的差异。我发现分组错误都来自一个自写的异常类型,它有一个空的 Exception.message 值。

get_hash 输出:

[<class 'StorageException'>, StorageException()]

多个错误来自具有填充消息值的异常类(jinja 模板引擎)

[<class 'jinja2.exceptions.UndefinedError'>, UndefinedError('dict object has no attribute LISTza_*XYZ*',)]

不同的异常消息触发不同的报告,在我的例子中,合并是由于缺少 Exception.message 值引起的。

实施:

class StorageException(Exception):

def __init__(self, value):
    Exception.__init__(self)
    self.value = value

【讨论】:

    【解决方案2】:

    在问题本身中查看我的最终更新。事件聚合在“项目”、“记录器”、“罪魁祸首”和“校验和”属性的组合上。其中前三个相对容易控制 - 第四个,“校验和”是作为事件一部分发送的数据类型的函数。

    Sentry 使用“接口”的概念来控制传入数据的结构,每个接口都带有get_hash 的实现,用于为传入的数据返回一个哈希值。Sentry 带有一个标准接口的数量('Message'、'User'、'HTTP'、'Stacktrace'、'Query'、'Exception'),每个都有自己的get_hash 实现。默认值(继承自 Interface 基类)是一个空列表,不会影响校验和。

    在没有任何有效接口的情况下,事件消息本身会经过哈希处理并作为校验和返回,这意味着消息需要唯一才能对事件进行分组。

    【讨论】:

    • raven.readthedocs.org/en/latest/config/logging.html#usage 上显示“如果您使用正确的字符串格式,Sentry 将智能地对消息进行分组。”以日志消息字符串格式保持不变且参数不同的示例为例。这与校验和机制有什么关系?
    • @akaihola - 我不知道。查看代码本身,Message.get_hash() 方法返回消息本身 - 这是后格式化。
    • @HugoRodger-Brown @akaihola 我相信接口sentry.interfaces.Message 具有messageparams 属性,并且消息是预先格式化的。详情见here
    • 好地方 - 我实际上不再使用 Sentry,但很高兴知道它是如何工作的。
    猜你喜欢
    • 2019-12-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-04-12
    • 2016-07-31
    • 1970-01-01
    相关资源
    最近更新 更多