Sentry-Go SDK 中文实践指南(一)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Sentry-Go SDK 中文实践指南(一)

介绍



Sentry-Go SDK 中文实践指南(http://sentry-go.hacker-linner.com/)


安装


Sentry 通过在应用程序的运行时中使用 SDK 捕获数据。

使用 Go Modules 时,无需安装任何软件即可开始将 Sentry 与 Go 程序一起使用。导入 SDK,然后当您下次构建程序时,go tool 会自动下载最新版本的 SDK。


import (
  "github.com/getsentry/sentry-go"
)


不使用或没有 Go Modules 时,要使用最新版本的SDK,请运行:


go get github.com/getsentry/sentry-go


有关如何管理依赖项的更多信息,请参阅有关 Modules 的 Go 文档。


配置


配置应在应用程序的生命周期中尽早进行。


package main
import (
  "log"
  "time"
  "github.com/getsentry/sentry-go"
)
func main() {
  err := sentry.Init(sentry.ClientOptions{
    // 在此处设置您的 DSN 或设置 SENTRY_DSN 环境变量。
    Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
    // 可以在这里设置 environment 和 release,
    // 也可以设置 SENTRY_ENVIRONMENT 和 SENTRY_RELEASE 环境变量。
    Environment: "",
    Release:     "",
    // 允许打印 SDK 调试消息。
    // 入门或尝试解决某事时很有用。
    Debug: true,
  })
  if err != nil {
    log.Fatalf("sentry.Init: %s", err)
  }
    // 在程序终止之前刷新缓冲事件。
    // 将超时设置为程序能够等待的最大持续时间。
  defer sentry.Flush(2 * time.Second)
}


验证


此代码段包含一个故意的错误,因此您可以在设置后立即测试一切是否正常:


package main
import (
  "log"
  "time"
  "github.com/getsentry/sentry-go"
)
func main() {
  err := sentry.Init(sentry.ClientOptions{
    Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  })
  if err != nil {
    log.Fatalf("sentry.Init: %s", err)
  }
  defer sentry.Flush(2 * time.Second)
  sentry.CaptureMessage("It works!")
}


要查看和解决记录的错误,请登录 sentry.io(或者你私有部署的 sentry) 并打开您的项目。单击错误标题将打开一个页面,您可以在其中查看详细信息并将其标记为已解决。


处理 Panics



在 Go SDK 中捕获未处理的紧急情况(panics)的方法是通过 Recover 方法。它可以直接通过 defer 关键字使用,也可以作为实现的一部分使用。


用法


如下所示,直接使用 Sentry 时,它将从紧急状态中恢复,并根据收到的输入类型在内部决定是使用 CaptureException 还是 CaptureMessage 方法。由于出现字符串 panic 并不常见,建议在 SDK 初始化期间使用 AttachStacktrace 选项,该选项还将尝试为消息提供有用的堆栈跟踪。


func() {
  defer sentry.Recover()
  // do all of the scary things here(在这里做所有可怕的事情)^_^
}()


默认情况下,Sentry Go SDK 使用异步传输,在下面的代码示例中,需要使用 sentry.Flush 方法显式等待事件传递完成。这是必要的,因为否则程序将不会等待异步 HTTP 调用返回响应,并在到达 main 函数末尾时立即退出进程。在正在运行的 goroutine 中或使用 HTTPSyncTransport(在 Transports 部分中可以了解到)时,不需要它。


如果要控制单个 defer 调用的传递,或在捕获之前执行其他操作,则必须直接在 Hub 实例上使用 Recovery 方法,因为它可以接受 err 本身。


func() {
  defer func() {
    err := recover()
    if err != nil {
      sentry.CurrentHub().Recover(err)
      sentry.Flush(time.Second * 5)
    }
  }()
  // do all of the scary things here
}()


使用 Context


除了常规的 Recover 方法外,还有一种可用于紧急情况的方法,即 RecoverWithContext。它允许传递 context.Context 的实例作为第一个参数。这为我们提供了两个附加功能。


第一个是从上下文(context)提取 Hub 实例并使用它而不是全局实例 —— 这用于每个 http/server 包集成,因为它允许执行上下文分离。您可以在我们的 http 集成源代码中看到它的作用。


第二个功能是对 beforeSend 方法内部的 context.Context 本身的访问,可用于提取有关在 panic 下发生的情况的任何其他信息:


type contextKey int
const SomeContextKey = contextKey(1)
func main() {
  sentrySyncTransport := sentry.NewHTTPSyncTransport()
  sentrySyncTransport.Timeout = time.Second * 3
  sentry.Init(sentry.ClientOptions{
    Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
    Transport: sentrySyncTransport,
    BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
      if hint.Context != nil {
        // hint.Context.Value(SomeContextKey) 会给您存储的字符串,现在可以将其附加到事件中
      }
      return event
    },
  })
  ctx := context.WithValue(context.Background(), SomeContextKey, "some details about your panic")
  func() {
    defer sentry.RecoverWithContext(ctx)
    // do all of the scary things here
  }()
}


并发


并发的 Go 程序使用 goroutines(一种由 Go 运行时管理的轻量级线程形式)。由于 goroutine 同时运行,因此每个 goroutine 必须在本地跟踪其与 Sentry 相关的数据。否则,数据争用(data races)会在您的程序中引入细微的错误,其后果从明显的变化到意外的崩溃,甚至更糟的是,意外地将 Scope 中存储的数据混合在一起。在 Scopes and Hubs 部分中对此有更多的了解。


处理这个问题最简单的方法是为您启动的每个 goroutine 创建一个新的 Hub,但是这需要您重新绑定当前 Client 并自己处理 Scope。这就是为什么我们提供了一个名为 Clone 的辅助方法。它负责创建集线器、克隆现有 Scope 并将其与 Client 一起重新分配给新创建的实例。


克隆后,Hub 将完全隔离,可以在并发调用中安全使用。但是,不应使用在全局上公开的方法,而应在 Hub 上直接调用它们。

这是两个示例:


  • 建议对 Hub 进行安全的确定性调用


// Example of __CORRECT__ use of scopes inside a Goroutine
// 正确使用
go func(localHub *sentry.Hub) {
  // as goroutine argument
  localHub.ConfigureScope(func(scope *sentry.Scope) {
    scope.SetTag("secretTag", "go#1")
  })
  localHub.CaptureMessage("Hello from Goroutine! #1")
}(sentry.CurrentHub().Clone())
go func() {
  // or created locally
  localHub := sentry.CurrentHub().Clone()
  localHub.ConfigureScope(func(scope *sentry.Scope) {
    scope.SetTag("secretTag", "go#2")
  })
  localHub.CaptureMessage("Hello from Goroutine! #2")
}()


  • 阻止在 Hub 上进行的不确定性调用,该调用会泄漏线程之间的信息


// Example of __INCORRECT__ use of scopes inside a Goroutine - DON'T USE IT!
// 不正确使用
go func() {
  sentry.ConfigureScope(func(scope *sentry.Scope) {
    scope.SetTag("secretTag", "go#1")
  })
  sentry.CaptureMessage("Hello from Goroutine! #1")
}()
go func() {
  sentry.ConfigureScope(func(scope *sentry.Scope) {
    scope.SetTag("secretTag", "go#2")
  })
  sentry.CaptureMessage("Hello from Goroutine! #2")
}()
// 此时,两个事件都可以具有 `go#1` 标签或 `go#2` 标签。我们永远不会知道。


配置项



  • 基本选项

详细了解如何配置 SDK。这些选项是在首次初始化 SDK 时设置的,并作为对象传递给 init()

  • Releases & Health

了解如何配置您的 SDK 以告知 Sentry 您的版本。

  • Transports

通过 Transports,您可以更改将事件传递到 Sentry 的方式。

  • Environments

了解如何配置您的 SDK,以告知 Sentry 您的环境。

  • 过滤和采样事件

详细了解如何配置您的 SDK 以过滤和采样报告给 Sentry 的事件。

  • Shutdown and Draining

如果应用程序意外关闭,请详细了解我们的 SDK 的默认行为。


基本选项


可以使用多种选项对 SDK 进行配置。这些选项在很大程度上在 SDK 中进行了标准化,但是为了更好地适应平台特性,还存在一些差异。选项在 SDK 首次初始化时设置。

选项作为一个 sentry.ClientOptions 的实例传递给 Init() 方法:


sentry.Init(sentry.ClientOptions{
  Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  Debug: true,
})


// ClientOptions 用来配置 SDK 客户端
type ClientOptions struct {
  // 要使用的 DSN。如果未设置 DSN,则实际上将禁用客户端。
  Dsn string
  // 在调试模式下,调试信息会打印到 stdout,以帮助您了解 sentry 在做什么。
  Debug bool
  // 配置 SDK 是否应生成堆栈跟踪并将其附加到纯捕获消息调用。
  AttachStacktrace bool
  // 事件提交的采样率(0.0-1.0,默认为 1.0)
  SampleRate float64
  // 用于与事件消息进行匹配的正则表达式字符串列表,如果适用,
  // 则捕获错误类型和值。如果找到匹配项,则将删除整个事件。
  IgnoreErrors []string
  // 发送回调之前。
  BeforeSend func(event *Event, hint *EventHint) *Event
  // 在面包屑之前添加回调。
  BeforeBreadcrumb func(breadcrumb *Breadcrumb, hint *BreadcrumbHint) *Breadcrumb
  // 要在当前客户端上安装的集成,接收默认集成
  Integrations func([]Integration) []Integration
  // io.Writer 实现应与 `Debug` 模式一起使用
  DebugWriter io.Writer
  // transport 使用
  // 这是实现 `Transport` 接口的结构的一个实例。
  // 默认来自 `transport.go` 的 `httpTransport`
  Transport Transport
  // The server name to be reported.
  // 要报告的服务器名称。
  ServerName string
  // 与事件一起发送的版本。
  Release string
  // 与事件一起发送的 dist。
  Dist string
  // 与事件一起发送的环境。
  Environment string
  // 面包屑的最大数量。
  MaxBreadcrumbs int
  // 指向 `http.Client` 的可选指针,它将与默认的 HTTPTransport 一起使用。
  // 使用您自己的客户端将忽略 HTTPTransport,HTTPProxy,HTTPSProxy 和 CaCerts 选项。
  HTTPClient *http.Client
  // 指向 `http.Transport` 的可选指针,它将与默认的 HTTPTransport 一起使用。
  // 使用您自己的 transport 将使 HTTPProxy,HTTPSProxy 和 CaCerts 选项被忽略。
  HTTPTransport *http.Transport
  // 要使用的可选 HTTP 代理。
  // 这将默认为 `http_proxy` 环境变量。
  // 或 `https_proxy`(如果存在的话)。
  HTTPProxy string
  // 要使用的可选 HTTPS 代理。
  // 这将默认为 `HTTPS_PROXY` 环境变量
  // 或 `http_proxy`(如果存在的话)。
  HTTPSProxy string
  // 要使用的可选 CaCert。
  // 默认为 `gocertifi.CACerts()`。
  CaCerts *x509.CertPool
}


提供 SSL 证书


默认情况下,TLS 使用主机的根 CA 设置。如果您没有 ca-certificates(这应该是解决丢失证书问题的首选方法), 而要使用 gocertifi,则可以提供预加载的证书文件作为 sentry.Init 调用的选项之一:


package main
import (
  "log"
  "github.com/certifi/gocertifi"
  "github.com/getsentry/sentry-go"
)
sentryClientOptions := sentry.ClientOptions{
  Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
}
rootCAs, err := gocertifi.CACerts()
if err != nil {
  log.Println("Could not load CA Certificates: %v\n", err)
} else {
  sentryClientOptions.CaCerts = rootCAs
}
sentry.Init(sentryClientOptions)


删除默认集成


sentry-go SDK 几乎没有内置的集成,这些集成可以使用其他信息增强事件或以一种或另一种方式管理事件。


如果您想了解更多有关它们的信息,请直接查看源代码。


但是,在某些情况下,您可能需要禁用其中一些功能。为此,您可以使用 Integrations 配置选项并过滤不需要的集成。例如:


sentry.Init(sentry.ClientOptions{
  Integrations: func(integrations []sentry.Integration) []sentry.Integration {
    var filteredIntegrations []sentry.Integration
    for _, integration := range integrations {
      if integration.Name() == "ContextifyFrames" {
        continue
      }
      filteredIntegrations = append(filteredIntegrations, integration)
    }
    return filteredIntegrations
  },
})


Releases & Health


发行版是部署到环境中的代码版本。当您向 Sentry 提供有关发行版的信息时,您可以:


  • 确定新版本中引入的问题和回归
  • 预测哪个提交引起了问题,谁可能负责
  • 通过在提交消息中包含问题编号来解决问题
  • 部署代码后接收电子邮件通知


绑定版本


配置客户端 SDK 时,请包含发行 ID(通常称为“版本”)。该 ID 通常是 git SHA 或自定义版本号。


发行版名称不能:

  • 包含换行符或空格
  • 使用正斜杠(“/”),反斜杠(“\”),句点(“.”)或双句号(“..”)
  • 超过200个字符

每个组织的版本都是全球性的;在它们前面加上特定项目的前缀,以便于区分。


sentry.Init(sentry.ClientOptions{
    Release: "my-project-name@2.3.12",
})


如何使版本对代码可用由您决定。例如,您可以使用在构建过程中设置的环境变量。

这将用发布值标记每个事件。我们建议您在部署 Sentry 之前告诉它一个新版本,因为这将解锁更多的特性,如我们的文档中所讨论的。但如果不这样做,Sentry 将在第一次看到带有该 release ID 的事件时自动在系统中创建一个 release 实体。


配置了 SDK 之后,您可以安装存储库集成,或者手动为 Sentry 提供您自己的提交元数据。请阅读我们关于版本的文档, 以获得关于集成、关联提交以及在部署版本时告知 Sentry 的更多信息。


Transports


通过 Transports,您可以更改将事件传递到 Sentry 的方式。

Sentry Go SDK 本身提供了两个内置传输。HTTPTransport,它是非阻塞的,默认情况下使用。和 HTTPSyncTransport 处于阻塞状态。每种传输方式都提供略有不同的配置选项。


用法


要配置传输,请提供一个 sentry.Transport 实例到 ClientOptions


package main
import (
  "time"
  "github.com/getsentry/sentry-go"
)
func main() {
  sentrySyncTransport := sentry.NewHTTPSyncTransport()
  sentrySyncTransport.Timeout = time.Second * 3
  sentry.Init(sentry.ClientOptions{
    Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
    Transport: sentrySyncTransport,
  })
}


每种运输方式都提供自己的工厂函数。NewHTTPTransportNewHTTPSyncTransport


选项


HTTPTransport


// HTTPTransport 是由 `Client` 使用的 `Transport` 接口的默认实现。
type HTTPTransport struct {
  // 传输缓冲区的大小。默认为30。
  BufferSize int
  // HTTP 客户端请求超时。默认为30秒。
  Timeout time.Duration
}


HTTPSyncTransport


// HTTPSyncTransport 是 `Transport` 接口的实现,它在每个捕获的事件之后都会阻塞。
type HTTPSyncTransport struct {
  // HTTP 客户端请求超时。默认为30秒。
  Timeout time.Duration
}


Environments


Sentry 在收到带有环境标签的事件时自动创建环境。环境是区分大小写的。环境名称不能包含换行、空格或斜杠,不能是字符串“None”,或超过64个字符。您不能删除环境,但可以隐藏它们。


sentry.Init(sentry.ClientOptions{
  Environment: "production",
})


在 sentry.io 的问题详细信息页面中,环境帮助您更好地过滤问题、版本和用户反馈。您可以在我们的文档中了解更多关于使用环境的信息。


过滤和采样事件


将 Sentry 添加到您的应用程序将为您提供有关错误和性能的大量非常有价值的信息,而这些信息是您以前无法获得的。而且很多信息都是好的-只要是正确的信息,而且数量合理。


Sentry SDK 有几个配置选项来帮助您控制这一点,允许您过滤掉您不想要的事件,并从您想要的事件中选取一个代表性的示例。


注意:Sentry UI 还提供了使用入站筛选器筛选事件的方法。不过,我们建议您在客户端级别进行过滤,因为它可以消除发送您实际上不需要的事件的开销。


过滤错误事件


配置您的 SDK,通过使用 beforeSend 回调方法并配置、启用或禁用集成来过滤错误事件。


UsingbeforeSend

所有的 Sentry SDK 都支持 beforeSend 回调方法。 beforeSend 在事件被发送到服务器之前被立即调用,因此它是您可以编辑其数据的最终位置。它将事件对象作为参数接收,因此您可以使用该参数根据定制逻辑和事件上可用的数据修改事件数据或完全删除它(通过返回 null)。


在 Go 中,函数可以用来修改事件或返回一个全新的事件。如果返回 nil, SDK 将丢弃该事件。


sentry.Init(sentry.ClientOptions{
  BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
    // Modify the event here
    event.User.Email = "" // Don't send user's email address
    return event
  },
})


还要注意,可以过滤面包屑,这在面包屑文档中已经讨论过了。


Event Hints

before-send 回调同时传递 event 和第二个参数 hint,它包含一个或多个 hint。

通常,一个 hint 保存原始异常,以便可以提取其他数据或影响分组。在本例中,如果捕获到某种类型的异常,则指纹被强制设置为公共值:


sentry.Init(sentry.ClientOptions{
  BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
    if ex, ok := hint.OriginalException.(DatabaseConnectionError); ok {
      event.Fingerprint = []string{"database-connection-error"}
    }
    return event
  },
})


有关可用提示的信息,请参见EventHint实现。

当 SDK 为传输创建一个事件或breadcrumb时,该传输通常是从某种源对象创建的。例如,错误事件通常是由日志记录或异常实例创建的。为了更好地定制,SDK 将这些对象发送到特定的回调(beforeSendbeforeBreadcrumb 或 SDK 中的事件处理器系统)。


使用 Hints


有两个地方提供 Hints:

  1. beforeSend / beforeBreadcrumb
  2. eventProcessors


事件和 breadcrumb hints 是包含各种用于组合事件或 breadcrumb 的信息的对象。通常, hints 保存原始异常,以便可以提取其他数据或影响分组。


用于事件,如 event_idoriginalExceptionsyntheticException(内部用于生成更干净的堆栈跟踪),以及附加的任何其他任意 data


对于面包屑,hints 的使用依赖于实现。对于 XHR 请求,hint 包含 XHR 对象本身;对于用户交互,hint 包含 DOM 元素和事件名等等。


在本例中,如果捕获到某种类型的异常,则指纹被强制设置为公共值:


Hints for Events

originalException

引起 Sentry SDK 创建事件的原始异常。这对于更改 Sentry SDK 分组事件的方式或提取其他信息很有用。


syntheticException

当引发字符串或非错误对象时,Sentry 会创建一个合成异常,这样您就可以获得一个基本的堆栈跟踪。这个异常被存储在这里以供进一步的数据提取。


Hints for Breadcrumbs


event

对于从浏览器事件创建的 breadcrumb, Sentry SDK 通常将事件作为 hint 提供给 breadcrumb。例如,这可以用于从目标 DOM 元素提取数据到 breadcrumb。

level / input

对于从控制台日志截取创建的面包屑。这将保留原始控制台日志级别和日志功能的原始输入数据。

response / input

用于从 HTTP 请求创建的面包屑。它保存响应对象(来自 fetch API )和 fetch 函数的输入参数。

request / response / event

用于从 HTTP 请求创建的面包屑。它包含请求和响应对象(来自节点 HTTP API )以及节点事件( responseerror )。

xhr

对于通过旧版 XMLHttpRequest API 通过 HTTP 请求创建的面包屑。这将保留原始的 xhr 对象。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
安全 Go 调度
探索Go语言的并发之美:goroutine与channel的实践指南
在本文中,我们将深入探讨Go语言的并发机制,特别是goroutine和channel的使用。通过实际的代码示例,我们将展示如何利用这些工具来构建高效、可扩展的并发程序。我们将讨论goroutine的轻量级特性,channel的同步通信能力,以及它们如何共同简化并发编程的复杂性。
|
4月前
|
Shell Go 开发工具
【Azure Developer】Go语言调用Azure SDK如何登录到中国区Azure环境
【Azure Developer】Go语言调用Azure SDK如何登录到中国区Azure环境
|
5月前
|
JSON Java Serverless
函数计算产品使用问题之如何使用Go SDK从HTTP上下文中提取JSON数据
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
5月前
|
分布式计算 大数据 Go
MaxCompute操作报错合集之使用go sdk调用GetTunnelEndpoint出现报错:InvalidAction.NotFoundSpecified api is not found,该如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
7月前
|
安全 Go 开发工具
对象存储OSS产品常见问题之go语言SDK client 和 bucket 并发安全如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
158 9
|
资源调度 Kubernetes Go
SchedulerX支持Go版本SDK
Go语言越来越流行,SchedulerX是阿里云的分布式任务调度服务,新增支持Go版本SDK
124 0
|
Kubernetes Go 开发工具
开发 k8s 管理平台 - k8sailor 03. 使用 client-go sdk 链接集群
开发 k8s 管理平台 - k8sailor 03. 使用 client-go sdk 链接集群
265 0
开发 k8s 管理平台 - k8sailor 03. 使用 client-go sdk 链接集群
|
Go 开发工具
【Go】The selected directory is not a valid home for Go SDK
【Go】The selected directory is not a valid home for Go SDK
416 0
【Go】The selected directory is not a valid home for Go SDK
|
4月前
|
JavaScript 前端开发 Java
[Android][Framework]系统jar包,sdk的制作及引用
[Android][Framework]系统jar包,sdk的制作及引用
109 0
|
1月前
|
Java Linux API
Android SDK
【10月更文挑战第21天】
76 1