[[builtin-modules]]
=== Built-in instrumentation modules

For each server instrumentation module, a transaction is reported for each handled
request. The transaction will be stored in the request context, which can be obtained through
that framework's API. The request context can be used for reporting <<custom-instrumentation-spans, custom spans>>.

* <<builtin-modules-apmecho>>
* <<builtin-modules-apmgin>>
* <<builtin-modules-apmbeego>>
* <<builtin-modules-apmgorilla>>
* <<builtin-modules-apmgrpc>>
* <<builtin-modules-apmhttp>>
* <<builtin-modules-apmhttprouter>>
* <<builtin-modules-apmnegroni>>
* <<builtin-modules-apmlambda>>
* <<builtin-modules-apmsql>>
* <<builtin-modules-apmgopg>>
* <<builtin-modules-apmgorm>>
* <<builtin-modules-apmgocql>>
* <<builtin-modules-apmredigo>>
* <<builtin-modules-apmgoredis>>
* <<builtin-modules-apmgoredisv8>>
* <<builtin-modules-apmrestful>>
* <<builtin-modules-apmchi>>
* <<builtin-modules-apmlogrus>>
* <<builtin-modules-apmzap>>
* <<builtin-modules-apmzerolog>>
* <<builtin-modules-apmelasticsearch>>
* <<builtin-modules-apmmongo>>

[[builtin-modules-apmecho]]
==== module/apmecho
Packages apmecho and apmechov4 provide middleware for the https://github.com/labstack/echo[Echo]
web framework, versions 3.x and 4.x respectively.

If you are using Echo 4.x (`github.com/labstack/echo/v4`), then you should use `module/apmechov4`.
For the older Echo 3.x versions (`github.com/labstack/echo`), you should use `module/apmecho`.

For each request, a transaction is stored in the request context, which can be obtained via
https://godoc.org/github.com/labstack/echo#Context[echo.Context]`.Request().Context()` in your handler.

[source,go]
----
import (
	echo "github.com/labstack/echo/v4"

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

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

The middleware will recover panics and send them to Elastic APM, so you do not need to install
the echo/middleware.Recover middleware.

[[builtin-modules-apmgin]]
==== module/apmgin
Package apmgin provides middleware for the https://gin-gonic.com/[Gin] web framework.

For each request, a transaction is stored in the request context, which can be obtained via
https://godoc.org/github.com/gin-gonic/gin#Context[gin.Context]`.Request.Context()` in your handler.

[source,go]
----
import (
	"go.elastic.co/apm/module/apmgin"
)

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

The apmgin middleware will recover panics and send them to Elastic APM, so you do not need to install the gin.Recovery middleware.

[[builtin-modules-apmbeego]]
==== module/apmbeego
Package apmbeego provides middleware for the https://beego.me/[Beego] web framework.

For each request, a transaction is stored in the request context, which can be obtained via
https://godoc.org/github.com/astaxie/beego/context#Context[beego/context.Context]`.Request.Context()`
in your controller.

[source,go]
----
import (
	"github.com/astaxie/beego"

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

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())
}
----

[[builtin-modules-apmgorilla]]
==== module/apmgorilla
Package apmgorilla provides middleware for the http://www.gorillatoolkit.org/pkg/mux[Gorilla Mux] router.

For each request, a transaction is stored in the request context, which can be obtained via
https://golang.org/pkg/net/http/#Request[http.Request]`.Context()` in your handler.

[source,go]
----
import (
	"github.com/gorilla/mux"

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

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

The apmgorilla middleware will recover panics and send them to Elastic APM, so you do not need to install any other recovery middleware.

[[builtin-modules-apmgrpc]]
==== module/apmgrpc
Package apmgrpc provides server and client interceptors for https://github.com/grpc/grpc-go[gRPC-Go].
Server interceptors report transactions for each incoming request, while client interceptors
report spans for each outgoing request. For each RPC served, a transaction is stored in the
context passed into the method.

[source,go]
----
import (
	"go.elastic.co/apm/module/apmgrpc"
)

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

The server interceptor can optionally be made to recover panics, in the same way as
https://github.com/grpc-ecosystem/go-grpc-middleware/tree/master/recovery[grpc_recovery].
The apmgrpc server interceptor will always send panics it observes as errors to the Elastic APM server.
If you want to recover panics but also want to continue using grpc_recovery, then you should ensure
that it comes before the apmgrpc interceptor in the interceptor chain, or panics will not be captured
by apmgrpc.

[source,go]
----
server := grpc.NewServer(grpc.UnaryInterceptor(
	apmgrpc.NewUnaryServerInterceptor(apmgrpc.WithRecovery()),
))
...
----

There is currently no support for intercepting at the stream level. Please file an issue and/or
send a pull request if this is something you need.

[[builtin-modules-apmhttp]]
==== module/apmhttp
Package apmhttp provides a low-level `net/http` middleware handler. Other web middleware should
typically be based off this.

For each request, a transaction is stored in the request context, which can be obtained via
https://golang.org/pkg/net/http/#Request.Context[http.Request.Context] in your handler.

[source,go]
----
import (
	"go.elastic.co/apm/module/apmhttp"
)

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

The apmhttp handler will recover panics and send them to Elastic APM.

Package apmhttp also provides functions for instrumenting an `http.Client` or `http.RoundTripper`
such that outgoing requests are traced as spans, if the request context includes a transaction.
When performing the request, the enclosing context should be propagated by using
https://golang.org/pkg/net/http/#Request.WithContext[http.Request.WithContext], or a helper
such as those provided by https://golang.org/x/net/context/ctxhttp.

Client spans are not ended until the response body is fully consumed or closed. If you fail to
do either of these, then the span will not be sent. You should always close the response body
anyway, to ensure HTTP connections can be reused; see https://golang.org/pkg/net/http/#Client.Do.

[source,go]
----
import (
	"net/http"

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

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

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)))
}
----

[[builtin-modules-apmhttprouter]]
==== module/apmhttprouter
Package apmhttprouter provides a low-level middleware handler for https://github.com/julienschmidt/httprouter[httprouter].

For each request, a transaction is stored in the request context, which can be obtained via
https://golang.org/pkg/net/http/#Request[http.Request]`.Context()` in your handler.

[source,go]
----
import (
	"github.com/julienschmidt/httprouter"

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

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

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

https://github.com/julienschmidt/httprouter/pull/139[httprouter does not provide a means of obtaining the matched route], hence the route must be passed into the wrapper.

Alternatively you can use the apmhttprouter.Router type, which wraps httprouter.Router,
providing the same API and instrumenting added routes. To use this wrapper type, you
should rewrite your use of `httprouter.New` to `apmhttprouter.New`; the returned type
is `*apmhttprouter.Router`, and not `*httprouter.Router`.

[source,go]
----
import "go.elastic.co/apm/module/apmhttprouter"

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

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

[[builtin-modules-apmnegroni]]
==== module/apmnegroni

Package apmnegroni provides middleware for the https://github.com/urfave/negroni/[negroni] library.

For each request, a transaction is stored in the request context, which can be obtained via
https://golang.org/pkg/net/http/#Request.Context[http.Request.Context] in your handler.

[source,go]
----
import (
	"net/http"

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

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

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

The apmnegroni handler will recover panics and send them to Elastic APM.

[[builtin-modules-apmlambda]]
==== module/apmlambda
Package apmlambda intercepts requests to your AWS Lambda function invocations.

experimental[]

Importing the package is enough to report the function invocations.

[source,go]
----
import (
	_ "go.elastic.co/apm/module/apmlambda"
)
----

We currently do not expose the transactions via context; when we do, it will be
necessary to make a small change to your code to call apmlambda.Start instead of
lambda.Start.

[[builtin-modules-apmsql]]
==== module/apmsql
Package apmsql provides a means of wrapping `database/sql` drivers so that queries and other
executions are reported as spans within the current transaction.

To trace SQL queries, you should register drivers using apmsql.Register and obtain connections
with apmsql.Open. The parameters are exactly the same as if you were to call sql.Register
and sql.Open respectively.

As a convenience, we also provide packages which will automatically register popular drivers
with 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)

[source,go]
----
import (
	"go.elastic.co/apm/module/apmsql"
	_ "go.elastic.co/apm/module/apmsql/pq"
	_ "go.elastic.co/apm/module/apmsql/sqlite3"
)

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

Spans will be created for queries and other statement executions if the context methods are
used, and the context includes a transaction.

[[builtin-modules-apmgopg]]
==== module/apmgopg
Package apmgopg provides a means of instrumenting http://github.com/go-pg/pg[go-pg] database operations.

To trace `go-pg` statements, call `apmgopg.Instrument` with the database instance you plan on using and provide
a context that contains an apm transaction.

[source,go]
----
import (
	"github.com/go-pg/pg"

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

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

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

[[builtin-modules-apmgorm]]
==== module/apmgorm
Package apmgorm provides a means of instrumenting http://gorm.io[GORM] database operations.

To trace `GORM` operations, import the appropriate `apmgorm/dialects` package (instead of the
`gorm/dialects` package), and use `apmgorm.Open` (instead of `gorm.Open`). The parameters are
exactly the same.

Once you have a `*gorm.DB` from `apmgorm.Open`, you can call `apmgorm.WithContext` to
propagate a context containing a transaction to the operations:

[source,go]
----
import (
	"go.elastic.co/apm/module/apmgorm"
	_ "go.elastic.co/apm/module/apmgorm/dialects/postgres"
)

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

==== module/apmgormv2
Package apmgormv2 provides a means of instrumenting http://gorm.io[GORM] database operations.

To trace `GORM` operations, import the appropriate `apmgormv2/driver` package (instead of the
`gorm.io/driver` package), use these dialects to `gorm.Open` instead of gorm drivers.

Once you have a `*gorm.DB`, you can call `db.WithContext` to
propagate a context containing a transaction to the operations:

[source,go]
----
import (
	"gorm.io/gorm"
	postgres "go.elastic.co/apm/module/apmgormv2/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
}
----

[[builtin-modules-apmgocql]]
==== module/apmgocql
Package apmgocql provides a means of instrumenting https://github.com/gocql/gocql[gocql] so
that queries are reported as spans within the current transaction.

To report `gocql` queries, you can construct an `apmgocql.Observer` and assign it to
the `QueryObserver` and `BatchObserver` fields of `gocql.ClusterConfig`, or install it
into a specific `gocql.Query` or `gocql.Batch` via their `Observer` methods.

Spans will be created for queries as long as they have context associated, and the
context includes a transaction.

[source,go]
----
import (
	"github.com/gocql/gocql"

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

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()
	...
}
----

[[builtin-modules-apmredigo]]
==== module/apmredigo
Package apmredigo provides a means of instrumenting https://github.com/gomodule/redigo[Redigo]
so that Redis commands are reported as spans within the current transaction.

To report Redis commands, you can use the top-level `Do` or `DoWithTimeout` functions.
These functions have the same signature as the `redis.Conn` equivalents apart from an
initial `context.Context` parameter. If the context passed in contains a sampled
transaction, a span will be reported for the Redis command.

Another top-level function, `Wrap`, is provided to wrap a `redis.Conn` such that its
`Do` and `DoWithTimeout` methods call the above mentioned functions. Initially, the
wrapped connection will be associated with the background context; its `WithContext`
method may be used to obtain a shallow copy with another context. For example, in an
HTTP middleware you might bind a connection to the request context, which would
associate spans with the request's APM transaction.

[source,go]
----
import (
	"net/http"

	"github.com/gomodule/redigo/redis"

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

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()
	...
}
----

[[builtin-modules-apmgoredis]]
==== module/apmgoredis
Package apmgoredis provides a means of instrumenting https://github.com/go-redis/redis[go-redis/redis]
so that Redis commands are reported as spans within the current transaction.

To report Redis commands, you can use the top-level `Wrap` function to wrap a
`redis.Client`, `redis.ClusterClient`, or `redis.Ring`. Initially, the wrapped
client will be associated with the background context; its `WithContext` method
may be used to obtain a shallow copy with another context. For example, in an
HTTP middleware you might bind a client to the request context, which would
associate spans with the request's APM transaction.

[source,go]
----
import (
	"net/http"

	"github.com/go-redis/redis"

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

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())
	...
}
----

[[builtin-modules-apmgoredisv8]]
==== module/apmgoredisv8
Package apmgoredisv8 provides a means of instrumenting https://github.com/go-redis/redis[go-redis/redis] for v8
so that Redis commands are reported as spans within the current transaction.

To report Redis commands, you can call `AddHook(apmgoredis.NewHook())`
from instance of `redis.Client`, `redis.ClusterClient`, or `redis.Ring`.

[source,go]
----
import (
	"github.com/go-redis/redis/v8"

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

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")
}
----

[[builtin-modules-apmrestful]]
==== module/apmrestful
Package apmrestful provides a https://github.com/emicklei/go-restful[go-restful] filter
for tracing requests, and capturing panics.

For each request, a transaction is stored in the request context, which can be obtained via
https://golang.org/pkg/net/http/#Request[http.Request]`.Context()` in your handler.

[source,go]
----
import (
	"github.com/emicklei/go-restful"

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

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.
	}))
	...
}
----

[[builtin-modules-apmchi]]
==== module/apmchi
Package apmchi provides middleware for https://github.com/go-chi/chi[chi] routers,
for tracing requests and capturing panics.

For each request, a transaction is stored in the request context, which can be obtained via
https://golang.org/pkg/net/http/#Request[http.Request]`.Context()` in your handler.

[source,go]
----
import (
	"github.com/go-chi/chi"

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

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

[[builtin-modules-apmlogrus]]
==== module/apmlogrus
Package apmlogrus provides a https://github.com/sirupsen/logrus[logrus] Hook
implementation for sending error messages to Elastic APM, as well as a function
for adding trace context fields to log records.

[source,go]
----
import (
	"github.com/sirupsen/logrus"

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

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"}
}
----

[[builtin-modules-apmzap]]
==== module/apmzap
Package apmzap provides a https://godoc.org/go.uber.org/zap/zapcore#Core[go.uber.org/zap/zapcore.Core]
implementation for sending error messages to Elastic APM, as well as a function
for adding trace context fields to log records.

[source,go]
----
import (
	"go.uber.org/zap"

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

// 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"}
}
----

[[builtin-modules-apmzerolog]]
==== module/apmzerolog
Package apmzerolog provides an implementation of https://github.com/rs/zerolog[Zerolog]'s
`LevelWriter` interface for sending error records to Elastic APM, as well as functions
for adding trace context and detailed error stack traces to log records.

[source,go]
----
import (
	"net/http"

	"github.com/rs/zerolog"

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

// 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)
	})
}
----

[[builtin-modules-apmelasticsearch]]
==== module/apmelasticsearch
Package apmelasticsearch provides a means of instrumenting the HTTP transport
of Elasticsearch clients, such as https://github.com/elastic/go-elasticsearch[go-elasticsearch]
and https://github.com/olivere/elastic[olivere/elastic], so that Elasticsearch
requests are reported as spans within the current transaction.

To create spans for an Elasticsearch request, you should wrap the client's HTTP
transport using the `WrapRoundTripper` function, and then associate the request
with a context containing a transaction.

[source,go]
----
import (
	"net/http"

	"github.com/olivere/elastic"

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

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())
	...
}
----

[[builtin-modules-apmmongo]]
==== module/apmmongo
Package apmmongo provides a means of instrumenting the
https://github.com/mongodb/mongo-go-driver[MongoDB Go Driver], so that MongoDB
commands are reported as spans within the current transaction.

To create spans for MongoDB commands, you should pass in a `CommandMonitor` created
with `apmmongo.CommandMonitor` as an option when constructing a client, and then when
executing commands, pass in a context containing a transaction.

[source,go]
----
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"
)

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{})
	...
}
----
