API 文档编辑

本节介绍 API 中最常用的部分。

Go Agent 使用标准 godoc 进行文档化。有关完整文档,请参阅 pkg.go.dev/go.elastic.co/apm/v2 上的文档,或使用“godoc”工具。

Tracer API编辑

您的应用程序与 Go Agent 的第一个接触点是 apm.Tracer 类型,它提供用于报告事务和错误的方法。

为了简化检测,Go Agent 提供了一个初始化函数 apm.DefaultTracer()。此 Tracer 在第一次调用 apm.DefaultTracer() 时初始化,并在后续调用中返回。此函数返回的 Tracer 可以使用 apm.SetDefaultTracer(tracer) 进行修改。调用此函数将关闭之前的默认 Tracer(如果存在)。此 Tracer 使用环境变量进行配置;有关详细信息,请参阅 配置

import (
	"go.elastic.co/apm/v2"
)

func main() {
	tracer := apm.DefaultTracer()
	...
}

事务编辑

func (*Tracer) StartTransaction(name, type string) *Transaction编辑

StartTransaction 返回一个新的 Transaction,它具有指定的名称和类型,并且开始时间设置为当前时间。如果您需要设置时间戳或父 跟踪上下文,请使用 Tracer.StartTransactionOptions

此方法应在事务开始时调用,例如 Web 或 RPC 请求。例如:

transaction := apm.DefaultTracer().StartTransaction("GET /", "request")

事务将在 Elastic APM 应用程序中按类型和名称分组。

启动事务后,您可以记录结果并添加上下文以进一步描述事务。

transaction.Result = "Success"
transaction.Context.SetLabel("region", "us-east-1")

有关设置事务上下文的更多详细信息,请参阅 上下文

func (*Tracer) StartTransactionOptions(name, type string, opts TransactionOptions) *Transaction编辑

StartTransactionOptions 本质上与 StartTransaction 相同,但它还接受一个选项结构体。此结构体允许您指定父 跟踪上下文 和/或事务的开始时间。

opts := apm.TransactionOptions{
	Start: time.Now(),
	TraceContext: parentTraceContext,
}
transaction := apm.DefaultTracer().StartTransactionOptions("GET /", "request", opts)

func (*Transaction) End()编辑

End 将事务排队以发送到 Elastic APM 服务器。事务在调用此方法后不得修改,但仍可用于启动跨度。

事务的持续时间计算为事务开始到调用此方法之间经过的时间。要覆盖此行为,可以在调用 End 之前设置事务的 Duration 字段。

transaction.End()

func (*Transaction) TraceContext() TraceContext编辑

TraceContext 返回事务的 跟踪上下文

func (*Transaction) EnsureParent() SpanID编辑

EnsureParent 返回事务的父跨度 ID,如果事务之前没有父跨度,则生成并记录一个父跨度 ID。

EnsureParent 使得与 JavaScript 真实用户监控 (RUM) 代理为初始页面加载创建的跨度相关联。如果您的后端服务动态生成 HTML 页面,则可以将跟踪和父跨度 ID 注入页面以初始化 JavaScript RUM 代理,以便 Web 浏览器的页面加载显示为跟踪的根。

var initialPageTemplate = template.Must(template.New("").Parse(`
<html>
<head>
<script src="elastic-apm-js-base/dist/bundles/elastic-apm-js-base.umd.min.js"></script>
<script>
  elasticApm.init({
    serviceName: '',
    serverUrl: 'https://127.0.0.1:8200',
    pageLoadTraceId: {{.TraceContext.Trace}},
    pageLoadSpanId: {{.EnsureParent}},
    pageLoadSampled: {{.Sampled}},
  })
</script>
</head>
<body>...</body>
</html>
`))

func initialPageHandler(w http.ResponseWriter, req *http.Request) {
	err := initialPageTemplate.Execute(w, apm.TransactionFromContext(req.Context()))
	if err != nil {
		...
	}
}

有关更多信息,请参阅 JavaScript RUM 代理文档

func (*Transaction) ParentID() SpanID编辑

ParentID 返回事务父级的 ID,如果事务没有父级,则返回零(无效)SpanID。

func ContextWithTransaction(context.Context, *Transaction) context.Context编辑

ContextWithTransaction 将事务添加到上下文中,并返回结果上下文。

可以使用 apm.TransactionFromContext 检索事务。上下文也可以传递到 apm.StartSpan 中,该方法在内部使用 TransactionFromContext 来创建作为事务子级的跨度。

func TransactionFromContext(context.Context) *Transaction编辑

TransactionFromContext 返回先前使用 apm.ContextWithTransaction 存储在上下文中的事务,如果上下文不包含事务,则返回 nil。

func DetachedContext(context.Context) context.Context编辑

DetachedContext 返回一个新的上下文,该上下文与输入的生存期分离,但仍返回与输入相同的 value。

DetachedContext 可用于维护关联事件所需的跟踪上下文,但操作是“即发即弃”的,不应受周围上下文的截止时间或取消的影响。

func TraceFormatter(context.Context) fmt.Formatter编辑

TraceFormatter 返回 fmt.Formatter 的实现,可用于格式化提供上下文中存储的事务和跨度的 ID。

格式化程序理解以下格式

  • %v: 跟踪 ID、事务 ID 和(如果在跨度上下文中)跨度 ID,以空格分隔
  • %t: 仅跟踪 ID
  • %x: 仅事务 ID
  • %s: 仅跨度 ID

“+”选项可用于以“key=value”样式格式化 value,字段名称为 trace.idtransaction.idspan.id。例如,使用 "%+v" 作为格式将产生 "trace.id=…​ transaction.id=…​ span.id=…​"。

有关更深入的示例,请参阅 手动日志关联(非结构化)

跨度编辑

为了描述事务中的活动,我们创建跨度。Go Agent 内置支持为某些活动生成跨度,例如数据库查询。您可以使用 API 报告特定于应用程序的跨度。

func (*Transaction) StartSpan(name, spanType string, parent *Span) *Span编辑

StartSpan 在事务中启动并返回一个新的跨度,它具有指定的名称、类型和可选的父跨度,并且开始时间设置为当前时间。如果您需要设置时间戳或父 跟踪上下文,请使用 Transaction.StartSpanOptions

如果跨度类型包含两个点,则假定它们用于分隔跨度类型、子类型和操作;一个点用于分隔跨度类型和子类型,并且不会设置操作。

如果事务被采样,则跨度的 ID 将被设置,并且如果 Tracer 进行了相应的配置,则其堆栈跟踪将被设置。如果事务未被采样,则返回的跨度将在调用其 End 方法时被静默丢弃。为了避免对这些被丢弃的跨度进行任何不必要的计算,请调用 Dropped 方法。

为了方便起见,在 nil Transaction 上创建跨度是有效的;生成的跨度将是非空的,可以安全使用,但不会报告给 APM 服务器。

span := tx.StartSpan("SELECT FROM foo", "db.mysql.query", nil)

func (*Transaction) StartSpanOptions(name, spanType string, opts SpanOptions) *Span编辑

StartSpanOptions 本质上与 StartSpan 相同,但它还接受一个选项结构体。此结构体允许您指定父 跟踪上下文 和/或跨度的开始时间。如果选项中未指定父跟踪上下文,则跨度将是事务的直接子级。否则,父跟踪上下文应属于从事务派生的某个跨度。

opts := apm.SpanOptions{
	Start: time.Now(),
	Parent: parentSpan.TraceContext(),
}
span := tx.StartSpanOptions("SELECT FROM foo", "db.mysql.query", opts)

func StartSpan(ctx context.Context, name, spanType string) (*Span, context.Context)edit

StartSpan 在上下文中启动并返回一个新的跨度,该跨度位于采样事务和父跨度内(如果有)。如果跨度未被丢弃,它将包含在生成的上下文中。

span, ctx := apm.StartSpan(ctx, "SELECT FROM foo", "db.mysql.query")

func (*Span) End()edit

End 将跨度标记为已完成。在此之后,不得修改跨度,但仍可将其用作跨度的父级。

跨度的持续时间将计算为从跨度启动到调用此方法所经过的时间。要覆盖此行为,可以在调用 End 之前设置跨度的 Duration 字段。

func (*Span) Dropped() booledit

Dropped 指示跨度是否被丢弃,这意味着它不会被报告给 APM 服务器。当使用 nil 或未采样事务创建跨度时,或者当已达到其最大跨度限制时,跨度会被丢弃。

func (*Span) TraceContext() TraceContextedit

TraceContext 返回跨度的 跟踪上下文

func ContextWithSpan(context.Context, *Span) context.Contextedit

ContextWithSpan 将跨度添加到上下文中并返回生成的上下文。

可以使用 apm.SpanFromContext 检索跨度。上下文也可以传递给 apm.StartSpan,它在内部使用 SpanFromContext 来创建另一个跨度作为该跨度的子级。

func SpanFromContext(context.Context) *Spanedit

SpanFromContext 返回之前使用 apm.ContextWithSpan 存储在上下文中的跨度,如果上下文不包含跨度,则返回 nil。

func (*Span) ParentID() SpanIDedit

ParentID 返回跨度父级的 ID。

上下文edit

在报告事务和错误时,您可以提供上下文来描述这些事件。内置的检测通常会提供一些上下文,例如 HTTP 请求的 URL 和远程地址。您也可以提供自定义上下文和标签。

func (*Context) SetLabel(key string, value interface{})edit

SetLabel 使用给定的键和值标记事务或错误。如果键包含任何特殊字符(.*"),它们将被替换为下划线。

如果值是数字或布尔值,则它将作为 JSON 数字或布尔值发送到服务器;否则,它将被转换为字符串,如果需要,将使用 fmt.Sprint。从版本 6.7 开始,服务器支持数字和布尔值。

超过 1024 个字符的字符串值将被截断。标签在 Elasticsearch 中被索引为关键字字段。

在使用标签之前,请确保您了解可用的不同类型的 元数据

避免定义太多用户指定的标签。在索引中定义太多唯一字段会导致 映射爆炸

func (*Context) SetCustom(key string, value interface{})edit

SetCustom 用于向事务或错误添加自定义的、非索引的上下文信息。如果键包含任何特殊字符(.*"),它们将被替换为下划线。

非索引意味着数据在 Elasticsearch 中不可搜索或聚合,您无法在数据之上构建仪表板。但是,非索引信息对于其他原因很有用,例如提供上下文信息以帮助您快速调试性能问题或错误。

该值可以是任何可以使用 encoding/json 编码的类型。

在使用自定义上下文之前,请确保您了解可用的不同类型的 元数据

func (*Context) SetUsername(username string)edit

SetUsername 记录与事务关联的用户的用户名。

func (*Context) SetUserID(id string)edit

SetUserID 记录与事务关联的用户的 ID。

func (*Context) SetUserEmail(email string)edit

SetUserEmail 记录与事务关联的用户的电子邮件地址。

错误edit

Elastic APM 提供两种捕获错误事件的方法:报告错误日志记录和报告“异常”(在 Go 中,无论是 panic 还是错误)。

func (*Tracer) NewError(error) *Erroredit

NewError 返回一个新的 Error,其中包含从 err 中获取的详细信息。

异常消息将设置为 err.Error()。异常模块和类型将分别设置为错误原因的包和类型名称,其中原因与 github.com/pkg/errors 中给出的定义相同。

e := apm.DefaultTracer().NewError(err)
...
e.Send()

提供的错误可以实现多个接口中的任何一个以提供其他信息

// Errors implementing ErrorsStacktracer will have their stacktrace
// set based on the result of the StackTrace method.
type ErrorsStacktracer interface {
    StackTrace() github.com/pkg/errors.StackTrace
}

// Errors implementing Stacktracer will have their stacktrace
// set based on the result of the StackTrace method.
type Stacktracer interface {
    StackTrace() []go.elastic.co/apm/v2/stacktrace.Frame
}

// Errors implementing Typer will have a "type" field set to the
// result of the Type method.
type Typer interface {
	Type() string
}

// Errors implementing StringCoder will have a "code" field set to the
// result of the Code method.
type StringCoder interface {
	Code() string
}

// Errors implementing NumberCoder will have a "code" field set to the
// result of the Code method.
type NumberCoder interface {
	Code() float64
}

使用 NewError 创建的错误将使用唯一 ID 填充其 ID 字段。这可以在您的应用程序中用于关联。

func (*Tracer) NewErrorLog(ErrorLogRecord) *Erroredit

NewErrorLog 为给定的 ErrorLogRecord 返回一个新的 Error

type ErrorLogRecord struct {
	// Message holds the message for the log record,
	// e.g. "failed to connect to %s".
	//
	// If this is empty, "[EMPTY]" will be used.
	Message string

	// MessageFormat holds the non-interpolated format
	// of the log record, e.g. "failed to connect to %s".
	//
	// This is optional.
	MessageFormat string

	// Level holds the severity level of the log record.
	//
	// This is optional.
	Level string

	// LoggerName holds the name of the logger used.
	//
	// This is optional.
	LoggerName string

	// Error is an error associated with the log record.
	//
	// This is optional.
	Error error
}

生成的 Error 的日志堆栈跟踪将不会被设置。调用 SetStacktrace 方法来设置它。

e := apm.DefaultTracer().NewErrorLog(apm.ErrorLogRecord{
	Message: "Somebody set up us the bomb.",
})
...
e.Send()

func (*Error) SetTransaction(*Transaction)edit

SetTransaction 将错误与给定的事务关联起来。

func (*Error) SetSpan(*Span)edit

SetSpan 将错误与给定的跨度及其跨度的交易关联起来。调用 SetSpan 时,无需再调用 SetTransaction。

func (*Error) Send()edit

Send 将错误排队以发送到 Elastic APM 服务器。

func (*Tracer) Recovered(interface{}) *Erroredit

Recovered 从恢复的值返回一个 Error,可以选择将其与事务关联起来。错误不会被发送;调用者有责任设置错误的上下文,然后调用其 Send 方法。

tx := apm.DefaultTracer().StartTransaction(...)
defer tx.End()
defer func() {
	if v := recover(); v != nil {
		e := apm.DefaultTracer().Recovered(v)
		e.SetTransaction(tx)
		e.Send()
	}
}()

func CaptureError(context.Context, error) *Erroredit

CaptureError 返回一个与上下文中存在的采样事务和跨度相关的错误(如果有),并使用给定的错误设置其异常详细信息。Error.Handled 字段将设置为 true,并将设置堆栈跟踪。

如果上下文中没有事务,或者它没有被采样,CaptureError 将返回 nil。为了方便起见,如果提供的错误为 nil,则 CaptureError 也将返回 nil。

if err != nil {
        e := apm.CaptureError(ctx, err)
        e.Send()
}

跟踪上下文edit

跟踪上下文包含事务或跨度的 ID、事务或跨度所属的端到端跟踪的 ID,以及跟踪选项,例如与采样相关的标志。跟踪上下文在进程之间传播,例如在 HTTP 标头中,以便关联来自相关服务的事件。

Elastic APM 的跟踪上下文基于 W3C 跟踪上下文 草案。

错误上下文edit

错误可以像事务一样与上下文关联。有关详细信息,请参阅 上下文。此外,错误可以使用 SetTransactionSetSpan 分别与活动事务或跨度关联。

tx := apm.DefaultTracer().StartTransaction("GET /foo", "request")
defer tx.End()
e := apm.DefaultTracer().NewError(err)
e.SetTransaction(tx)
e.Send()

跟踪器配置edit

许多配置属性可以通过 apm.Tracer 方法调用动态更新。有关详细信息,请参阅 pkg.go.dev/go.elastic.co/apm/v2#Tracer 中的文档。配置方法主要以 Set 为前缀,例如 apm#Tracer.SetLogger