内置插桩模块编辑

对于每个服务器插桩模块,都会为每个已处理的请求报告一个事务。该事务将存储在请求上下文中,可以通过该框架的 API 获取。请求上下文可用于报告 自定义 Span

module/apmhttp编辑

软件包 apmhttp 提供了一个低级别的 net/http 中间件处理程序。其他 Web 中间件通常应基于此。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 http.Request.Context 获取该事务。

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

func main() {
	var myHandler http.Handler = ...
	tracedHandler := apmhttp.Wrap(myHandler)
}

apmhttp 处理程序将恢复紧急情况并将它们发送到 Elastic APM。

软件包 apmhttp 还提供了用于插桩 http.Clienthttp.RoundTripper 的函数,以便在请求上下文包含事务的情况下将传出请求作为 Span 进行跟踪。执行请求时,应使用 http.Request.WithContext 或辅助函数(例如 https://golang.ac.cn/x/net/context/ctxhttp 提供的辅助函数)传播封闭上下文。

客户端 Span 在响应正文被完全使用或关闭之前不会结束。如果您两者均未做到,则不会发送 Span。始终关闭响应正文以确保可以重用 HTTP 连接;请参阅 func (*Client) Do

import (
	"net/http"

	"golang.org/x/net/context/ctxhttp"

	"go.elastic.co/apm/v2"
	"go.elastic.co/apm/module/apmhttp/v2"
)

var tracingClient = apmhttp.WrapClient(http.DefaultClient)

func serverHandler(w http.ResponseWriter, req *http.Request) {
	// Propagate the transaction context contained in req.Context().
	resp, err := ctxhttp.Get(req.Context(), tracingClient, "http://backend.local/foo")
	if err != nil {
		apm.CaptureError(req.Context(), err).Send()
		http.Error(w, "failed to query backend", 500)
		return
	}
	body, err := ioutil.ReadAll(resp.Body)
	...
}

func main() {
	http.ListenAndServe(":8080", apmhttp.Wrap(http.HandlerFunc(serverHandler)))
}

module/apmfasthttp编辑

软件包 apmfasthttp 为 valyala/fasthttp 中间件请求处理程序提供了一个低级别。其他基于 fasthttp 的 Web 中间件通常应基于此。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 fasthttp.RequestCtx 使用 apm.TransactionFromContext 获取该事务。

import (
	"github.com/valyala/fasthttp"

	"go.elastic.co/apm/module/apmfasthttp/v2"
)

func main() {
	var myHandler fasthttp.RequestHandler = func(ctx *fasthttp.RequestCtx) {
		apmCtx := apm.TransactionFromContext(ctx)
		// ...
	}
	tracedHandler := apmfasthttp.Wrap(myHandler)
}

apmfasthttp 处理程序将恢复紧急情况并将它们发送到 Elastic APM。

module/apmecho编辑

软件包 apmecho 和 apmechov4 分别为 Echo Web 框架版本 3.x 和 4.x 提供了中间件。

如果您使用的是 Echo 4.x (github.com/labstack/echo/v4),请使用 module/apmechov4。对于较旧的 Echo 3.x 版本 (github.com/labstack/echo),请使用 module/apmecho

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 echo.Context.Request().Context() 获取该事务。

import (
	echo "github.com/labstack/echo/v4"

	"go.elastic.co/apm/module/apmechov4/v2"
)

func main() {
	e := echo.New()
	e.Use(apmechov4.Middleware())
	...
}

中间件将恢复紧急情况并将它们发送到 Elastic APM,因此您无需安装 echo/middleware.Recover 中间件。

module/apmgin编辑

软件包 apmgin 为 Gin Web 框架提供了中间件。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 gin.Context.Request.Context() 获取该事务。

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

func main() {
	engine := gin.New()
	engine.Use(apmgin.Middleware(engine))
	...
}

apmgin 中间件将恢复紧急情况并将它们发送到 Elastic APM,因此您无需安装 gin.Recovery 中间件。

module/apmfiber编辑

软件包 apmfiber 为 Fiber Web 框架版本 2.x(v2.18.0 及更高版本)提供了中间件。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 fiber.Ctx.Context() 获取该事务。

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

func main() {
	app := fiber.New()
	app.Use(apmfiber.Middleware())
	...
}

apmfiber 中间件将恢复紧急情况并将它们发送到 Elastic APM,因此您无需安装 fiber recover 中间件。您可以使用 WithPanicPropagation 选项禁用默认行为。

module/apmbeego编辑

软件包 apmbeego 为 Beego Web 框架提供了中间件。

对于每个请求,都会在请求上下文中存储一个事务,您可以在控制器中通过 beego/context.Context.Request.Context() 获取该事务。

import (
	"github.com/astaxie/beego"

	"go.elastic.co/apm/v2"
	"go.elastic.co/apm/module/apmbeego/v2"
)

type thingController struct{beego.Controller}

func (c *thingController) Get() {
	span, _ := apm.StartSpan(c.Ctx.Request.Context(), "thingController.Get", "controller")
	span.End()
	...
}

func main() {
	beego.Router("/", &thingController{})
	beego.Router("/thing/:id:int", &thingController{}, "get:Get")
	beego.RunWithMiddleWares("localhost:8080", apmbeego.Middleware())
}

module/apmgorilla编辑

软件包 apmgorilla 为 Gorilla Mux 路由器提供了中间件。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 http.Request.Context() 获取该事务。

import (
	"github.com/gorilla/mux"

	"go.elastic.co/apm/module/apmgorilla/v2"
)

func main() {
	router := mux.NewRouter()
	apmgorilla.Instrument(router)
	...
}

apmgorilla 中间件将恢复紧急情况并将它们发送到 Elastic APM,因此您无需安装任何其他恢复中间件。

module/apmgrpc编辑

软件包 apmgrpc 为 gRPC-Go 提供了服务器和客户端拦截器。服务器拦截器为每个传入请求报告事务,而客户端拦截器为每个传出请求报告 Span。对于每个已服务的 RPC,都会在传递给该方法的上下文中存储一个事务。

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

func main() {
	server := grpc.NewServer(
		grpc.UnaryInterceptor(apmgrpc.NewUnaryServerInterceptor()),
		grpc.StreamInterceptor(apmgrpc.NewStreamServerInterceptor()),
	)
	...
	conn, err := grpc.Dial(addr,
		grpc.WithUnaryInterceptor(apmgrpc.NewUnaryClientInterceptor()),
		grpc.WithStreamInterceptor(apmgrpc.NewStreamClientInterceptor()),
	)
	...
}

可以选择使服务器拦截器恢复紧急情况,方式与 grpc_recovery 相同。apmgrpc 服务器拦截器始终会将其观察到的紧急情况作为错误发送到 Elastic APM 服务器。如果您想恢复紧急情况,但还想继续使用 grpc_recovery,则应确保它在拦截器链中位于 apmgrpc 拦截器之前,否则 apmgrpc 将不会捕获紧急情况。

server := grpc.NewServer(grpc.UnaryInterceptor(
	apmgrpc.NewUnaryServerInterceptor(apmgrpc.WithRecovery()),
))
...

流拦截器会发出表示整个流的事务和 Span,而不是单个消息。对于客户端流,当请求失败时;当 grpc.ClientStream.RecvMsggrpc.ClientStream.SendMsggrpc.ClientStream.Header 中的任何一个返回错误时;或者当 grpc.ClientStream.RecvMsg 为非流服务器方法返回时,Span 将结束。

module/apmhttprouter编辑

软件包 apmhttprouter 为 httprouter 提供了一个低级别的中间件处理程序。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 http.Request.Context() 获取该事务。

import (
	"github.com/julienschmidt/httprouter"

	"go.elastic.co/apm/module/apmhttprouter/v2"
)

func main() {
	router := httprouter.New()

	const route = "/my/route"
	router.GET(route, apmhttprouter.Wrap(h, route))
	...
}

httprouter 不提供获取匹配路由的方法,因此必须将路由传递给包装器。

或者,使用 apmhttprouter.Router 类型,该类型包装了 httprouter.Router,提供了相同的 API 并插桩了添加的路由。要使用此包装器类型,请将您对 httprouter.New 的使用重写为 apmhttprouter.New;返回的类型是 *apmhttprouter.Router,而不是 *httprouter.Router

import "go.elastic.co/apm/module/apmhttprouter/v2"

func main() {
	router := apmhttprouter.New()

	router.GET(route, h)
	...
}

module/apmnegroni编辑

软件包 apmnegroni 为 negroni 库提供了中间件。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 http.Request.Context 获取该事务。

import (
	"net/http"

	"go.elastic.co/apm/module/apmnegroni/v2"
)

func serverHandler(w http.ResponseWriter, req *http.Request) {
	...
}

func main() {
	n := negroni.New()
	n.Use(apmnegroni.Middleware())
	n.UseHandler(serverHandler)
	http.ListenAndServe(":8080", n)
}

apmnegroni 处理程序将恢复紧急情况并将它们发送到 Elastic APM。

module/apmlambda编辑

软件包 apmlambda 拦截对您的 AWS Lambda 函数调用的请求。

此功能处于技术预览阶段,可能会在将来的版本中更改或删除。Elastic 将努力解决任何问题,但技术预览版中的功能不受官方 GA 功能的支持 SLA 的约束。

导入软件包就足以报告函数调用。

import (
	_ "go.elastic.co/apm/module/apmlambda/v2"
)

我们目前不通过上下文公开事务;当我们这样做时,您需要对代码进行少量更改,以调用 apmlambda.Start 而不是 lambda.Start。

module/apmsql编辑

软件包 apmsql 提供了一种包装 database/sql 驱动程序的方法,以便将查询和其他执行作为当前事务中的 Span 进行报告。

要跟踪 SQL 查询,请使用 apmsql.Register 注册驱动程序,并使用 apmsql.Open 获取连接。参数与您分别调用 sql.Register 和 sql.Open 时完全相同。

为方便起见,我们还提供了一些软件包,它们将使用 apmsql.Register 自动注册流行的驱动程序。

  • module/apmsql/pq (github.com/lib/pq)
  • module/apmsql/pgxv4 (github.com/jackc/pgx/v4/stdlib)
  • module/apmsql/mysql (github.com/go-sql-driver/mysql)
  • module/apmsql/sqlite3 (github.com/mattn/go-sqlite3)
import (
	"go.elastic.co/apm/module/apmsql/v2"
	_ "go.elastic.co/apm/module/apmsql/v2/pq"
	_ "go.elastic.co/apm/module/apmsql/v2/sqlite3"
)

func main() {
	db, err := apmsql.Open("postgres", "postgres://...")
	db, err := apmsql.Open("sqlite3", ":memory:")
}

如果使用了上下文方法,并且上下文包含事务,则将为查询和其他语句执行创建跨度。

module/apmgopg编辑

包 apmgopg 提供了一种检测 go-pg 数据库操作的方法。

要跟踪 go-pg 语句,请使用您计划使用的数据库实例调用 apmgopg.Instrument,并提供包含 apm 事务的上下文。

import (
	"github.com/go-pg/pg"

	"go.elastic.co/apm/module/apmgopg/v2"
)

func main() {
	db := pg.Connect(&pg.Options{})
	apmgopg.Instrument(db)

	db.WithContext(ctx).Model(...)
}

如果使用了上下文方法,并且上下文包含事务,则将为查询和其他语句执行创建跨度。

module/apmgopgv10编辑

包 apmgopgv10 提供了一种检测 go-pg 数据库操作 v10 的方法。

要跟踪 go-pg 语句,请使用您计划使用的数据库实例调用 apmgopgv10.Instrument,并提供包含 apm 事务的上下文。

import (
	"github.com/go-pg/pg/v10"

	"go.elastic.co/apm/module/apmgopgv10/v2"
)

func main() {
	db := pg.Connect(&pg.Options{})
	apmgopg.Instrument(db)

	db.WithContext(ctx).Model(...)
}

module/apmgorm编辑

包 apmgorm 提供了一种检测 GORM 数据库操作的方法。

要跟踪 GORM 操作,请导入适当的 apmgorm/dialects 包(而不是 gorm/dialects 包),并使用 apmgorm.Open(而不是 gorm.Open)。参数完全相同。

apmgorm.Open 获取 *gorm.DB 后,您可以调用 apmgorm.WithContext 将包含事务的上下文传播到操作。

import (
	"go.elastic.co/apm/module/apmgorm/v2"
	_ "go.elastic.co/apm/module/apmgorm/v2/dialects/postgres"
)

func main() {
	db, err := apmgorm.Open("postgres", "")
	...
	db = apmgorm.WithContext(ctx, db)
	db.Find(...) // creates a "SELECT FROM <foo>" span
}

module/apmgormv2编辑

包 apmgormv2 提供了一种检测 GORM 数据库操作的方法。

要跟踪 GORM 操作,请导入适当的 apmgormv2/driver 包(而不是 gorm.io/driver 包),并将这些方言用于 gorm.Open 而不是 gorm 驱动程序。

获得 *gorm.DB 后,您可以调用 db.WithContext 将包含事务的上下文传播到操作。

import (
	"gorm.io/gorm"
	postgres "go.elastic.co/apm/module/apmgormv2/v2/driver/postgres"
)

func main() {
	db, err := gorm.Open(postgres.Open("dsn"), &gorm.Config{})
	...
	db = db.WithContext(ctx)
	db.Find(...) // creates a "SELECT FROM <foo>" span
}

module/apmgocql编辑

包 apmgocql 提供了一种检测 gocql 的方法,以便将查询作为当前事务中的跨度报告。

要报告 gocql 查询,请构造一个 apmgocql.Observer 并将其分配给 gocql.ClusterConfigQueryObserverBatchObserver 字段,或者通过其 Observer 方法将其安装到特定的 gocql.Querygocql.Batch 中。

只要查询具有关联的上下文并且上下文包含事务,就会为查询创建跨度。

import (
	"github.com/gocql/gocql"

	"go.elastic.co/apm/module/apmgocql/v2"
)

func main() {
	observer := apmgocql.NewObserver()
	config := gocql.NewCluster("cassandra_host")
	config.QueryObserver = observer
	config.BatchObserver = observer

	session, err := config.CreateSession()
	...
	err = session.Query("SELECT * FROM foo").WithContext(ctx).Exec()
	...
}

module/apmredigo编辑

包 apmredigo 提供了一种检测 Redigo 的方法,以便将 Redis 命令作为当前事务中的跨度报告。

要报告 Redis 命令,请使用顶级 DoDoWithTimeout 函数。除了初始的 context.Context 参数外,这些函数的签名与 redis.Conn 等效函数相同。如果传入的上下文包含采样的交易,则将为 Redis 命令报告一个跨度。

提供了另一个顶级函数 Wrap 来包装 redis.Conn,以便其 DoDoWithTimeout 方法调用上述函数。最初,包装的连接将与后台上下文相关联;可以使用其 WithContext 方法获取具有另一个上下文的浅表副本。例如,在 HTTP 中间件中,您可以将连接绑定到请求上下文,这会将跨度与请求的 APM 事务相关联。

import (
	"net/http"

	"github.com/gomodule/redigo/redis"

	"go.elastic.co/apm/module/apmredigo/v2"
)

var redisPool *redis.Pool // initialized at program startup

func handleRequest(w http.ResponseWriter, req *http.Request) {
	// Wrap and bind redis.Conn to request context. If the HTTP
	// server is instrumented with Elastic APM (e.g. with apmhttp),
	// Redis commands will be reported as spans within the request's
	// transaction.
	conn := apmredigo.Wrap(redisPool.Get()).WithContext(req.Context())
	defer conn.Close()
	...
}

module/apmgoredis编辑

包 apmgoredis 提供了一种检测 go-redis/redis 的方法,以便将 Redis 命令作为当前事务中的跨度报告。

要报告 Redis 命令,请使用顶级 Wrap 函数包装 redis.Clientredis.ClusterClientredis.Ring。最初,包装的客户端将与后台上下文相关联;可以使用其 WithContext 方法获取具有另一个上下文的浅表副本。例如,在 HTTP 中间件中,您可以将客户端绑定到请求上下文,这会将跨度与请求的 APM 事务相关联。

import (
	"net/http"

	"github.com/go-redis/redis"

	"go.elastic.co/apm/module/apmgoredis/v2"
)

var redisClient *redis.Client // initialized at program startup

func handleRequest(w http.ResponseWriter, req *http.Request) {
	// Wrap and bind redisClient to the request context. If the HTTP
	// server is instrumented with Elastic APM (e.g. with apmhttp),
	// Redis commands will be reported as spans within the request's
	// transaction.
	client := apmgoredis.Wrap(redisClient).WithContext(req.Context())
	...
}

module/apmgoredisv8编辑

包 apmgoredisv8 提供了一种检测 go-redis/redis v8 的方法,以便将 Redis 命令作为当前事务中的跨度报告。

要报告 Redis 命令,您可以从 redis.Clientredis.ClusterClientredis.Ring 实例调用 AddHook(apmgoredis.NewHook())

import (
	"github.com/go-redis/redis/v8"

	apmgoredis "go.elastic.co/apm/module/apmgoredisv8/v2"
)

func main() {
	redisClient := redis.NewClient(&redis.Options{})
	// Add apm hook to redisClient.
	// Redis commands will be reported as spans within the current transaction.
	redisClient.AddHook(apmgoredis.NewHook())

	redisClient.Get(ctx, "key")
}

module/apmrestful编辑

包 apmrestful 提供了一个 go-restful 过滤器,用于跟踪请求和捕获紧急情况。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 http.Request.Context() 获取该事务。

import (
	"github.com/emicklei/go-restful"

	"go.elastic.co/apm/module/apmrestful/v2"
)

func init() {
	// Trace all requests to web services registered with the default container.
	restful.Filter(apmrestful.Filter())
}

func main() {
	var ws restful.WebService
	ws.Path("/things").Consumes(restful.MIME_JSON, restful.MIME_XML).Produces(restful.MIME_JSON, restful.MIME_XML)
	ws.Route(ws.GET("/{id:[0-1]+}").To(func(req *restful.Request, resp *restful.Response) {
		// req.Request.Context() should be propagated to downstream operations such as database queries.
	}))
	...
}

module/apmchi编辑

包 apmchi 为 chi 路由器提供了中间件,用于跟踪请求和捕获紧急情况。

对于每个请求,都会在请求上下文中存储一个事务,您可以在处理程序中通过 http.Request.Context() 获取该事务。

import (
	"github.com/go-chi/chi"

	"go.elastic.co/apm/module/apmchi/v2"
)

func main() {
	r := chi.NewRouter()
	r.Use(apmchi.Middleware())
	r.Get("/route/{pattern}", routeHandler)
	...
}

module/apmlogrus编辑

包 apmlogrus 提供了一个 logrus Hook 实现,用于将错误消息发送到 Elastic APM,以及一个用于将跟踪上下文字段添加到日志记录的函数。

import (
	"github.com/sirupsen/logrus"

	"go.elastic.co/apm/module/apmlogrus/v2"
)

func init() {
	// apmlogrus.Hook will send "error", "panic", and "fatal" level log messages to Elastic APM.
	logrus.AddHook(&apmlogrus.Hook{})
}

func handleRequest(w http.ResponseWriter, req *http.Request) {
	// apmlogrus.TraceContext extracts the transaction and span (if any) from the given context,
	// and returns logrus.Fields containing the trace, transaction, and span IDs.
	traceContextFields := apmlogrus.TraceContext(req.Context())
	logrus.WithFields(traceContextFields).Debug("handling request")

	// Output:
	// {"level":"debug","msg":"handling request","time":"1970-01-01T00:00:00Z","trace.id":"67829ae467e896fb2b87ec2de50f6c0e","transaction.id":"67829ae467e896fb"}
}

module/apmzap编辑

包 apmzap 提供了一个 go.uber.org/zap/zapcore.Core 实现,用于将错误消息发送到 Elastic APM,以及一个用于将跟踪上下文字段添加到日志记录的函数。

import (
	"go.uber.org/zap"

	"go.elastic.co/apm/module/apmzap/v2"
)

// apmzap.Core.WrapCore will wrap the core created by zap.NewExample
// such that logs are also sent to the apmzap.Core.
//
// apmzap.Core will send "error", "panic", and "fatal" level log
// messages to Elastic APM.
var logger = zap.NewExample(zap.WrapCore((&apmzap.Core{}).WrapCore))

func handleRequest(w http.ResponseWriter, req *http.Request) {
	// apmzap.TraceContext extracts the transaction and span (if any)
	// from the given context, and returns zap.Fields containing the
	// trace, transaction, and span IDs.
	traceContextFields := apmzap.TraceContext(req.Context())
	logger.With(traceContextFields...).Debug("handling request")

	// Output:
	// {"level":"debug","msg":"handling request","trace.id":"67829ae467e896fb2b87ec2de50f6c0e","transaction.id":"67829ae467e896fb"}
}

module/apmzerolog编辑

包 apmzerolog 提供了 ZerologLevelWriter 接口的实现,用于将错误记录发送到 Elastic APM,以及用于将跟踪上下文和详细的错误堆栈跟踪添加到日志记录的函数。

import (
	"net/http"

	"github.com/rs/zerolog"

	"go.elastic.co/apm/module/apmzerolog/v2"
)

// apmzerolog.Writer will send log records with the level error or greater to Elastic APM.
var logger = zerolog.New(zerolog.MultiLevelWriter(os.Stdout, &apmzerolog.Writer{}))

func init() {
	// apmzerolog.MarshalErrorStack will extract stack traces from
	// errors produced by github.com/pkg/errors. The main difference
	// with github.com/rs/zerolog/pkgerrors.MarshalStack is that
	// the apmzerolog implementation records fully-qualified function
	// names, enabling errors reported to Elastic APM to be attributed
	// to the correct package.
	zerolog.ErrorStackMarshaler = apmzerolog.MarshalErrorStack
}

func traceLoggingMiddleware(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		logger := zerolog.Ctx(ctx).Hook(apmzerolog.TraceContextHook(ctx))
		req = req.WithContext(logger.WithContext(ctx))
		h.ServeHTTP(w, req)
	})
}

module/apmelasticsearch编辑

包 apmelasticsearch 提供了一种检测 Elasticsearch 客户端(例如 go-elasticsearcholivere/elastic)的 HTTP 传输的方法,以便将 Elasticsearch 请求作为当前事务中的跨度报告。

要为 Elasticsearch 请求创建跨度,请使用 WrapRoundTripper 函数包装客户端的 HTTP 传输,然后将请求与包含事务的上下文相关联。

import (
	"net/http"

	"github.com/olivere/elastic"

	"go.elastic.co/apm/module/apmelasticsearch/v2"
)

var client, _ = elastic.NewClient(elastic.SetHttpClient(&http.Client{
	Transport: apmelasticsearch.WrapRoundTripper(http.DefaultTransport),
}))

func handleRequest(w http.ResponseWriter, req *http.Request) {
	result, err := client.Search("index").Query(elastic.NewMatchAllQuery()).Do(req.Context())
	...
}

module/apmmongo编辑

包 apmmongo 提供了一种检测 MongoDB Go 驱动程序 的方法,以便将 MongoDB 命令作为当前事务中的跨度报告。

要为 MongoDB 命令创建跨度,请在构造客户端时传入使用 apmmongo.CommandMonitor 创建的 CommandMonitor,然后在执行命令时,传入包含事务的上下文。

import (
	"context"
	"net/http"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"

	"go.elastic.co/apm/module/apmmongo/v2"
)

var client, _ = mongo.Connect(
	context.Background(),
	options.Client().SetMonitor(apmmongo.CommandMonitor()),
)

func handleRequest(w http.ResponseWriter, req *http.Request) {
	collection := client.Database("db").Collection("coll")
	cur, err := collection.Find(req.Context(), bson.D{})
	...
}

module/apmawssdkgo编辑

包 apmawssdkgo 提供了一种检测 AWS SDK Go 会话对象的方法,以便将 AWS 请求作为当前事务中的跨度报告。

要为 AWS 请求创建跨度,您应该在构造客户端时包装使用 session.NewSession 创建的 session.Session。执行命令时,传入包含事务的上下文。

支持以下服务

  • S3
  • DynamoDB
  • SQS
  • SNS

将使用 apmawssdkgo.WrapSession 包装的 session.Session 传递给 AWS SDK 中的这些服务将在当前事务中报告跨度。

import (
	"context"
	"net/http"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"

	"go.elastic.co/apm/module/apmawssdkgo/v2"
)

func main() {
  session := session.Must(session.NewSession())
  session = apmawssdkgo.WrapSession(session)

  uploader := s3manager.NewUploader(session)
  s := &server{uploader}
  ...
}

func (s *server) handleRequest(w http.ResponseWriter, req *http.Request) {
  ctx := req.Context()
  out, err := s.uploader.UploadWithContext(ctx, &s3manager.UploadInput{
    Bucket: aws.String("your-bucket"),
    Key:    aws.String("your-key"),
    Body:   bytes.NewBuffer([]byte("your-body")),
  })
  ...
}

module/apmazure编辑

包 apmazure 提供了一种检测 Azure Pipeline Go 管道对象的方法,以便将 Azure 请求作为当前事务中的跨度报告。

要为 Azure 请求创建跨度,您应该使用相关服务的 NewPipeline 函数(例如 azblob.NewPipeline)创建一个新的管道,然后使用 apmazure.WrapPipeline 包装 pipeline.Pipeline。返回的 Pipeline 可以照常使用。

支持以下服务

  • Blob 存储
  • 队列存储
  • 文件存储
import (
  "github.com/Azure/azure-storage-blob-go/azblob"

  "go.elastic.co/apm/module/apmazure/v2"
)

func main() {
  p := azblob.NewPipeline(azblob.NewAnonymousCredential(), po)
  p = apmazure.WrapPipeline(p)
  u, err := url.Parse("https://my-account.blob.core.windows.net")
  serviceURL := azblob.NewServiceURL(*u, p)
  containerURL := serviceURL.NewContainerURL("mycontainer")
  blobURL := containerURL.NewBlobURL("readme.txt")
  // Use the blobURL to interact with Blob Storage
  ...
}

module/apmpgx编辑

包 apmpgx 提供了一种检测 v4.17+ 的 Pgx 的方法,以便将 SQL 查询作为当前事务中的跨度报告。此外,该库还扩展了对 pgx 的支持,例如 COPY FROM 查询和 BATCH,它们具有自己的跨度类型:db.postgresql.copydb.postgresql.batch

要报告 pgx 查询,请创建 pgx 连接,然后将配置提供给 apmpgx.Instrument()。如果配置中存在记录器,则跟踪将写入日志。(没有记录器也可以安全使用)

只要查询具有关联的上下文并且上下文包含事务,就会为查询创建跨度。

使用池的示例

import (
    "github.com/jackc/pgx/v4/pgxpool"

    "go.elastic.com/apm/module/apmpgx/v2"
)

func main() {
    c, err := pgxpool.ParseConfig("dsn_string")
    ...
    pool, err := pgxpool.ParseConfig("dsn")
    ...
    // set custom logger before instrumenting
    apmpgx.Instrument(pool.ConnConfig)
    ...
}

不使用池的示例

import (
    "github.com/jackc/pgx/v4"

    "go.elastic.com/apm/module/apmpgx/v2"
)

func main() {
    c, err := pgx.Connect(context.Background, "dsn_string")
    ...
    // set custom logger before instrumenting
    apmpgx.Instrument(c.Config())
    ...
}