# Golang apmchi library question

**URL:** <https://discuss.elastic.co/t/golang-apmchi-library-question/211738>\
**Category:** APM\
**Tags:** go\
**Created:** [December 13, 2019, 2:44am UTC](https://discuss.elastic.co/t/golang-apmchi-library-question/211738 "2019-12-13T02:44:26Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Evan\_Something](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/evan_something/32/52579_2.png) [@Evan\_Something](https://discuss.elastic.co/u/Evan_Something)\
**Post date:** [December 13, 2019, 2:44am UTC](https://discuss.elastic.co/t/golang-apmchi-library-question/211738/1 "2019-12-13T02:44:26Z")

</div>

**Kibana version** : 7.4.2

**Elasticsearch version** : 7.4.2

**APM Server version** : 7.4.2

**APM Agent language and version** : unsure

**Original install method (e.g. download page, yum, deb, from source, etc.) and version**: docker

**Fresh install or upgraded from other version?** fresh install

**Is there anything special in your setup?** For example, are you using the Logstash or Kafka outputs? Are you using a load balancer in front of the APM Servers? Have you changed index pattern, generated custom templates, changed agent configuration etc.

attempting a barebones setup...

**Description of the problem including expected versus actual behavior. Please include screenshots (if relevant)**:

So I am trying to setup my first proof of concepts with APM. I have an API called Gateway that receives a request, and calls another Go service called Template Service.

I imported in my routes.go the "[go.elastic.co/apm/module/apmchi](http://go.elastic.co/apm/module/apmchi)" package, and I added the following line for instance in declaring routes for the template service:

```auto
func NewRoutes() *router.Mux {
	r := router.NewRouter()
	r.Use(middleware.Logger)
	r.Use(apmchi.Middleware())

	r.Route("/v1", func(r router.Router) {
		r.Get("/product-templates", getProductTemplates)
	})
	return r
}

```

I have similar in the Gateway project.

When I run both of them, they both appear in the APM console as services, and when I send a request that gets routed through the gateway to the template service, they appear as two separate and complete transactions.

Am I supposed to do additional setup? I wasn't sure if apmchi managed incoming requests, and there was [brief instructions](https://www.elastic.co/guide/en/apm/agent/go/current/instrumenting-source.html#builtin-modules-apmchi) for setting it up.

To confirm, when i open APM, I see both services listed, and if I click Gateway, I see under Transactions a line item for:

`GET /v1/product-templates`

And if I go back and select Template service, i see an identical:

`GET /v1/product-templates`

Finally, to add a little more context, in the gateway service, I declare routes like such:

```auto
// NewRoutes returns the applications routes
func NewRoutes() *router.Mux {
	r := router.NewRouter()

	r.Use(middleware.Logger)
	r.Use(newCors().Handler)
	r.Use(apmchi.Middleware())

	r.Route("/v1", func(r router.Router) {
		r.Group(func(r router.Router) {
			user.Routes(r)
		})
		r.Group(func(r router.Router) {
			salestax.Routes(r)
		})
		r.Group(func(r router.Router) {
			template.Routes(r)

```

And i have a templates.go file to handle this route, with a setup like such:

```auto
func Routes(r router.Router) {
	r.Use(middleware.Authenticator)

	r.Get("/product-templates", getProductTemplates)
	r.Get("/themes", getThemes)
}

```

Which does a call to the Template service like such:

```auto
func getProductTemplates(w http.ResponseWriter, r *http.Request) {
	fmt.Println("gateway")
	resp, err := request.Get(url(fmt.Sprintf("/product-templates")))
	if err != nil {
		errors.NewHTTP(http.StatusInternalServerError, err.Error()).Response(w)
		return
	}

	w.WriteHeader(resp.Response().StatusCode)
	w.Write(resp.Bytes())
}

```

Any assistance in understanding is appreciated 😄

---

<div class="post-metadata">

**Author:** ![axw](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/axw/32/28197_2.png) [@axw](https://discuss.elastic.co/u/axw)\
**Post date:** [December 13, 2019, 3:19am UTC](https://discuss.elastic.co/t/golang-apmchi-library-question/211738/2 "2019-12-13T03:19:45Z")

</div>

Hi @Evan_Something, thanks for checking out APM!

You've already gotten most of the way, the final missing piece is to propagate the trace context. There's a couple of things you'll need to do to achieve this:

1. instrument the HTTP _client_ in the gateway service
2. pass the incoming request context to the outgoing request

The first part can be done using [apmhttp.WrapClient](https://www.elastic.co/guide/en/apm/agent/go/master/builtin-modules.html#builtin-modules-apmhttp), e.g.:

```auto
var httpClient = apmhttp.WrapClient(http.DefaultClient)

```

You should then use this instrumented `httpClient` to perform the outgoing requests. It'll only create spans if the outgoing request context contains a transaction. You can achieve that like this:

```auto
func getProductTemplates(w http.ResponseWriter, r *http.Request) {
    fmt.Println("gateway")
    req, _ := http.NewRequestWithContext(r.Context(), "GET", url("/product-templates"), nil)
    resp, err := httpClient.Do(req)
    if err != nil {
        errors.NewHTTP(http.StatusInternalServerError, err.Error()).Response(w)
        return
    }
    w.WriteHeader(resp.Response().StatusCode)
    w.Write(resp.Bytes())
}

```

You might also like to use [https://golang.org/x/net/context/ctxhttp](https://golang.org/x/net/context/ctxhttp) to cut down on boilerplate a little bit. See the [module/apmhttp docs](https://www.elastic.co/guide/en/apm/agent/go/master/builtin-modules.html#builtin-modules-apmhttp) for an example.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [January 2, 2020, 11:19pm UTC](https://discuss.elastic.co/t/golang-apmchi-library-question/211738/3 "2020-01-02T23:19:46Z")

</div>

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.
