Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Data Management(问题分组篇)

简介: Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Data Management(问题分组篇)

SDK Fingerprinting



在受支持的 SDK 中,可以覆盖 Sentry 的默认分组,该分组将 fingerprint 属性作为字符串数组传递。fingerprint 数组的长度不受限制。这类似于 fingerprint rules functionality,它总是可用的,并可以实现类似的结果。


Basic Example


在最基本的情况下,值直接传递:


function makeRequest(method, path, options) {
  return fetch(method, path, options).catch(function(err) {
    Sentry.withScope(function(scope) {
      // group errors together based on their request and response
      scope.setFingerprint([method, path, String(err.statusCode)]);
      Sentry.captureException(err);
    });
  });
}


您可以使用变量替换将动态值填充到通常在服务器上计算出的指纹中。例如,可以添加值 {{default}},以将整个正常生成的分组哈希添加到指纹中。这些值与服务器端指纹识别相同。有关更多信息,请参见 Variables。


Group Errors With Greater Granularity


您的应用程序查询远程过程调用模型(Remote Procedure Call Model, RPC)接口或外部应用程序编程接口(external application Programming interface, API)服务,因此堆栈跟踪通常是相同的(即使传出请求非常不同)。


以下示例将进一步分解 Sentry 将创建的默认组(用 {{default}} 表示),并考虑错误对象的一些属性:


class MyRPCError extends Error {
  constructor(message, functionName, errorCode) {
    super(message);
    // The name of the RPC function that was called (e.g. "getAllBlogArticles")
    this.functionName = functionName;
    // For example a HTTP status code returned by the server.
    this.errorCode = errorCode;
  }
}
Sentry.init({
  ...,
  beforeSend: function(event, hint) {
    const exception = hint.originalException;
    if (exception instanceof MyRPCError) {
      event.fingerprint = [
        '{{ default }}',
        String(exception.functionName),
        String(exception.errorCode)
      ];
    }
    return event;
  }
});


Group Errors More Aggressively


通用错误(例如数据库连接错误)具有许多不同的堆栈跟踪,并且从不在一起。

以下示例将通过从数组中省略 {{ default }} 来完全覆盖 Sentry 的分组:


class DatabaseConnectionError extends Error {}
Sentry.init({
  ...,
  beforeSend: function(event, hint) {
    const exception = hint.originalException;
    if (exception instanceof DatabaseConnectionError) {
      event.fingerprint = ['database-connection-error'];
    }
    return event;
  }
});


Fingerprint Rules



Fingerprint 规则(以前称为服务器端指纹)也配置了类似于 stack trace rules 的配置,但语法略有不同。匹配器(matchers)是相同的,但不是翻转标志(flipping flags),而是分配一个指纹,它完全覆盖默认分组。


这些规则可以在 Settings > Projects > [project] > Issue Grouping > Fingerprint Rules 中按项目设置。Group Settings 有输入字段,您可以在其中写入自定义指纹规则。该语法遵循 Discover queries 中的语法。如果要否定匹配,可以在表达式前面加上感叹号(!)。


所有值都匹配,并且在堆栈跟踪的情况下,将考虑所有帧。如果所有匹配项都匹配,则应用指纹。

Fingerprinting Config


# You can use comments to explain the rules.  Rules themselves follow the
# following syntax:
matcher:expression -> list of values
# The list of values can be hardcoded or substituted values.


下面是一个实际的示例,它将特定类型的异常组合在一起:


error.type:DatabaseUnavailable -> system-down
error.type:ConnectionError -> system-down
error.value:"connection error: *" -> connection-error, {{ transaction }}


Matchers


匹配器通常使用通配符语法。可以使用以下匹配器:

error.type

  • alias: type
  • 与异常类型(异常名称)匹配。匹配以区分大小写的形式进行。


error.type:ZeroDivisionError -> zero-division
error.type:ConnectionError -> connection-error


error.value

  • alias: value
  • 与异常值匹配。错误或异常通常具有易于理解的描述(值)。该匹配器允许不区分大小写的匹配。


error.value:"connection error (code: *)" -> connection-error
error.value:"could not connect (*)" -> connection-error


message

  • 匹配日志消息。它还会自动检查其他异常值,因为它们很难分开。匹配不区分大小写。


message:"system encountered a fatal problem: *" -> fatal-log


logger

  • 匹配 logger 的名称,这对于将 logger 的所有消息组合在一起非常有用。此匹配区分大小写。


logger:"com.myapp.mypackage.*" -> mypackage-logger


level

  • 在日志级别匹配。匹配不区分大小写。


logger:"com.myapp.FooLogger" level:"error" -> mylogger-error


tags.tag_name

  • 与标签 tag_name 的值匹配。这对于过滤某些类型的事件很有用。例如,您可以分离由特定服务器引起的事件:


tags.server_name:"canary-*.mycompany.internal" -> canary-events


stack.abs_path

  • alias: path
  • 在事件的路径上匹配,并且不区分大小写。它使用路径遍历语义,这意味着 * 不匹配斜杠,而 ** 匹配。请注意,此匹配器在 abs_pathfilename 上都匹配,因为 SDK 关于如何支持这些值可能会非常不一致。如果 glob 匹配这些值中的任何一个,则视为匹配。


stack.abs_path:"**/my-utils/*.js" -> my-utils, {{ error.type }}


stack.module

  • alias: module
  • stack.abs_path 类似,但是匹配模块名称。匹配区分大小写,并且会应用常规的规则(* 也匹配斜杠)。


stack.module:"*/my-utils/*" -> my-utils, {{ error.type }}


stack.function

  • alias: function
  • 检查堆栈跟踪中的任何函数是否与全局匹配。匹配区分大小写:


stack.function:"my_assertion_failed" -> my-assertion-failed


stack.package

  • alias: package
  • 与 frame 的 "package" 匹配。这通常是包含 frame 的 debug symbol/object file 的名称。如果有任何 frame 与该目标文件匹配,那么它将匹配。


stack.package:"**/libcurl.dylib" -> libcurl
stack.package:"**/libcurl.so" -> libcurl


family

  • 用于 "scope" 匹配器。存在以下族:用于任何类型的 JavaScript 事件的 javascript,用于任何类型的 Native 事件的 native。任何其他平台称为 other


family:native !stack.module:"myproject::*" -> not-from-my-project


app

  • 检查 frame 是否在应用程序内。与其他匹配器结合使用时特别有用。可能的值为 yesno


app:yes stack.function:"assert" -> assert


Combining Matchers


当多个匹配器组合在一起时,它们都需要匹配。在 frame 上运行的匹配器必须全部应用于同一 frame;否则,它们不被视为匹配项。


例如,如果在函数名称和模块名称上都匹配,则仅当 frame 同时在函数名称和模块名称上匹配时,才存在匹配项。一个frame 仅与函数名称匹配是不够的,即使另一个 frame 本身会与模块名称匹配也是如此。


# this matches if a frame exists with a specific function and module name
# and also a specific error type is thrown
error.type:ConnectionError stack.function:"connect" stack.module:"bot" -> bot-error


Variables


在 fingerprint 的右边,你可以使用常数值和变量。变量会被自动替换,并具有与匹配器相同的名称,但它们的填充方式可能不同。


变量用双花括号括起来({{variable_name}})。

{{ default }}

  • 这将填充正常分组操作将产生的默认 fingerprint。如果您想用其他方法细分一个已经存在的组,这将非常有用:


stack.function:"query_database" -> {{ default }}, {{ transaction }}


{{ transaction }}

  • 这会将 transaction 名称填写到 transaction 中。它将强制为每个 transaction 创建一个组:


error.type:"ApiError" -> api-error, {{ transaction }}


{{ error.type }}

  • alias: {{ type }}
  • 这将填写发生的错误的名称。使用 ·chained exceptions· 时,它将是最近抛出的错误。这将强制每个 ·transaction· 创建一个组:


stack.function:"evaluate_script" -> script-evaluation, {{ error.type }}


{{ stack.function }}

  • alias: {{ function }}
  • 这将填充 "crashing frame," 的功能名称,也称为应用程序代码的最上层 frame。


error.type:"ScriptError" -> script-evaluation, {{ stack.function }}


{{ stack.module }}

  • alias: {{ module }}
  • 这将填写"crashing frame,"的模块名称,也称为应用程序代码的最上层 frame。


error.type:"ScriptError" -> script-evaluation, {{ stack.module }}


{{ stack.package }}

  • alias: {{ package }}
  • 这将填写 "crashing frame," 的 package 名称(object file),也称为应用程序代码的最上层 frame。


stack.function:"assert" -> assertion, {{ stack.package }}


{{ logger }}

  • 这将填写引起事件的 logger 的名称。


message:"critical connection error*" -> connection-error, {{ logger }}


{{ level }}

  • 这将填充用于创建事件的日志级别的名称。


message:"connection error*" -> connection-error, {{ logger }}, {{ level }}


{{ tags.tag_name }}

  • 这会将 tag 的值填充到 fingerprint 中,例如,可以使用 fingerprint 按 server name 或类似名称拆分事件。


message:"connection error*" -> connection-error, {{ tags.server_name }}


Stack Trace Rules



如果使用堆栈跟踪进行分组,则堆栈跟踪规则(以前称为分组增强)会影响输入该算法的数据。可以在 Settings > Projects > [project] > Issue Grouping > Stack Trace Rules 下,针对每个项目配置这些规则。


每行都是一条规则;当所有表达式匹配时,一个或多个匹配表达式后跟一个或多个要执行的动作。所有规则在堆栈跟踪中的所有帧上从上到下执行。

堆栈跟踪规则的语法类似于:


matcher-name:expression other-matcher:expression ... action1 action2 ...


该语法遵循 Discover queries 中的语法。如果要否定匹配,可以在表达式前面加上感叹号(!)。

下面是一个实际的例子:


# mark all code in node modules not to be in app
stack.abs_path:**/node_modules/**         -app
# remove all generated javascript code from all grouping
stack.abs_path:**/generated/**.js         -group


Matchers


可以在一行中定义多个匹配器。下面的匹配器是可用的:

family

  • 匹配通用 platform family,目前包括 javascript, native 和 other。逗号分隔规则将它们应用于多个平台。


family:javascript stack.abs_path:**/generated/**  -group


stack.abs_path

  • alias: path
  • 该匹配器对堆栈跟踪中路径上的 Unix glob 行为不区分大小写。路径分隔符被标准化为 /。作为特殊规则,如果文件名是相对的,则它仍在 **/ 上匹配。


# match on all files under `project` with a `.c` extension
stack.abs_path:**/project/**.c` +app
# matches on vendor/foo without sub folders
stack.abs_path:**/vendor/foo/*.c` -app
# matches on `foo.c` as well as `foo/bar.c`.
stack.abs_path:**/*.gen.c` -group


stack.module

  • alias: module
  • Module 与 path 类似,但与 module 匹配。它不用于 Native,但用于 JavaScript、Python 和类似平台。匹配是区分大小写的,常规通配符是可用的。请注意,modules 不是 packages,这可能会让 Native 环境感到困惑。

stack.function

  • alias: function
  • 匹配堆栈跟踪中的函数,并且使用常规通配符区分大小写。


stack.function:myproject_* +app
stack.function:malloc      -group


stack.package

  • alias: package
  • 在堆栈跟踪中匹配 package。package 是包含 functionmodule 的容器。这是一个 .jar ,一个 .dylib 或类似的。匹配规则与 path 相同。例如,这通常是一个绝对路径。


stack.package:**/libcurl.dylib -group


app

  • stack trace frame 的应用内标记的当前状态匹配。yes 表示该 frame 是应用程序内 frame,no 表示不是。


Actions


有两种类型的 actions:标记(flag)和变量(variables)设置。

flag 标识在所有匹配器都匹配并使用以下前缀时采取的动作:


  • + 设置 flag
  • - 取消设置 flag
  • ^ 适用于匹配帧之上的帧(走向崩溃)。
  • v 适用于匹配帧下面的帧(远离崩溃)。

例如,-group ^-group 从组中移除匹配帧和它上面的所有帧。

  • app:在应用程序内标记或取消标记 frame
  • group:从分组中添加或删除 frame

variables:可以设置变量(variable=value)。当前只有一种:

  • max-frames:设置要分组的总帧数。默认值为 0,表示“所有帧”。如果设置为 3,则仅考虑前三个帧。

如果一行以 hash(#) 作为前缀,则它是一个注释并被忽略。


stack.abs_path:**/node_modules/** -group
stack.abs_path:**/app/utils/requestError.jsx -group
stack.abs_path:**src/getsentry/src/getsentry/** +app
family:native max-frames=3
stack.function:fetchSavedSearches v-group
stack.abs_path:**/app/views/**.jsx stack.function:fetchData ^-group
family:native stack.function:SpawnThread v-app -app
family:native stack.function:_NSRaiseError ^-group -app
family:native stack.function:std::* -app
family:native stack.function:core::* -app


Recommendations


这些建议将大大改善您的即用型分组体验。

Mark in-app Frames

为了主动改善您的体验,请帮助 Sentry 确定堆栈跟踪中的哪些帧是“应用程序内”(属于您自己的应用程序),哪些不是。SDK 定义了默认规则,但是在许多情况下,也可以在服务器上进行改进。特别是对于需要服务器端处理的语言(例如,Native C,C++ 或 JavaScript),最好在服务器上覆盖它。


stack.function:myapplication::* +app


你也可以通过标记其他帧 “not in-app” 来达到同样的效果。然而,如果是这种情况,你应该确保首先将所有帧设置为 “in-app”,以覆盖默认值:


app:no                   +app
stack.function:std::*    -app
stack.function:boost::*  -app


你需要强制所有帧首先在应用程序内,因为客户端 SDK 或早期处理可能已经设置了一些默认值。


Cut Stack Traces


在许多情况下,您要删除堆栈跟踪的顶部或底部。例如,许多代码库使用通用函数来生成错误。在这种情况下,错误机制将显示为堆栈跟踪的一部分。

例如,如果你使用 Rust,你可能想要删除一些与 panic 处理相关的 frames:


stack.function:std::panicking::begin_panic       ^-app -app ^-group
stack.function:core::panicking::begin_panic      ^-app -app ^-group


在这里,我们告诉系统从 begin-panic 到崩溃位置的所有 frame 都不是应用程序的一部分(包括 panic frame 本身)。在所有情况下,以上所有 frame 均与分组无关。

同样,您也可以删除堆栈跟踪的 base。如果您有不同的主循环来驱动应用程序,则此功能特别有用:


例如,如果你使用 Rust,你可能想要删除一些与 panic 处理相关的 frames:


stack.function:std::panicking::begin_panic       ^-app -app ^-group
stack.function:core::panicking::begin_panic      ^-app -app ^-group


这并不适用于所有的项目,但它可以很好地工作于许多崩溃的大型应用程序。默认的策略是考虑与分组相关的大多数堆栈跟踪。这意味着导致崩溃的每个不同的堆栈跟踪都将导致创建不同的组。如果你不想这样,你可以通过限制应该考虑的帧数来强制设置更大的组。


例如,如果堆栈跟踪中的任何帧都指向一个公共的外部库,你可以告诉系统只考虑 top N 帧:


# always only consider the top 1 frame for all native events
family:native max-frames=1
# if the bug is in proprietarymodule.so, only consider top 2 frames
family:native stack.package:**/proprietarymodule.so  max-frames=2
# these are functions we want to consider much more of the stack trace for
family:native stack.function:KnownBadFunction1  max-frames=5
family:native stack.function:KnownBadFunction2  max-frames=5


相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
存储 Cloud Native 数据处理
从嵌入式状态管理到云原生架构:Apache Flink 的演进与下一代增量计算范式
本文整理自阿里云资深技术专家、Apache Flink PMC 成员梅源在 Flink Forward Asia 新加坡 2025上的分享,深入解析 Flink 状态管理系统的发展历程,从核心设计到 Flink 2.0 存算分离架构,并展望未来基于流批一体的通用增量计算方向。
390 0
从嵌入式状态管理到云原生架构:Apache Flink 的演进与下一代增量计算范式
|
7月前
|
运维 Kubernetes Cloud Native
智联招聘 × 阿里云 ACK One:云端弹性算力颠覆传统 IDC 架构,打造春招技术新范式
在 2025 年春季招聘季的激战中,智联招聘凭借阿里云 ACK One 注册集群与弹性 ACS 算力的深度融合,成功突破传统 IDC 机房的算力瓶颈,以云上弹性架构支撑千万级用户的高并发访问,实现招聘服务效率与稳定性的双重跃升。
|
5月前
|
运维 监控 Cloud Native
从本土到全球,云原生架构护航灵犀互娱游戏出海
本文内容整理自「 2025 中企出海大会·游戏与互娱出海分论坛」,灵犀互娱基础架构负责人朱晓靖的演讲内容,从技术层面分享云原生架构护航灵犀互娱游戏出海经验。
531 16
|
5月前
|
运维 监控 Cloud Native
从本土到全球,云原生架构护航灵犀互娱游戏出海
内容整理自「 2025 中企出海大会·游戏与互娱出海分论坛」,灵犀互娱基础架构负责人朱晓靖的演讲内容,从技术层面分享云原生架构护航灵犀互娱游戏出海经验。
|
3月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
3月前
|
Java Linux 虚拟化
【Docker】(1)Docker的概述与架构,手把手带你安装Docker,云原生路上不可缺少的一门技术!
1. Docker简介 1.1 Docker是什么 为什么docker会出现? 假定您在开发一款平台项目,您的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。 您正在开发的应用依赖于您当前的配置且还要依赖于某些配置文件。 您的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。 **要求:**希望尽可能多在本地模拟这些环境而不产生重新创建服务器环境的开销 问题: 要如何确保应用能够在这些环境中运行和通过质量检测? 在部署过程中不出现令人头疼的版本、配置问题 无需重新编写代码和进行故障修复
403 2
|
9月前
|
运维 Cloud Native 测试技术
极氪汽车云原生架构落地实践
随着极氪数字业务的飞速发展,背后的 IT 技术也在不断更新迭代。极氪极为重视客户对服务的体验,并将系统稳定性、业务功能的迭代效率、问题的快速定位和解决视为构建核心竞争力的基石。
|
3月前
|
人工智能 Kubernetes Cloud Native
Higress(云原生AI网关) 架构学习指南
Higress 架构学习指南 🚀写在前面: 嘿,欢迎你来到 Higress 的学习之旅!
869 0
|
6月前
|
运维 监控 Cloud Native
从“守机器”到“写策略”——云原生架构把运维逼成了架构师
从“守机器”到“写策略”——云原生架构把运维逼成了架构师
146 1