APItoolkit full color logo
Sign Up

Go Gin OpenTelemetry Integration

Installation

Install the APIToolkit gin SDK using the following command go get command:

go get github.com/apitoolkit/apitoolkit-go/gin

Configuration

Before configuration open telemetery and setting up the APItoolkit middleware, you need to configure a few environment variables. These variables provide essential information for setting up openTelemetry and APItoolkit.

OTEL_RESOURCE_ATTRIBUTES="at-project-key=YOUR_API_KEY" # Your apitoolkit API key
OTEL_SERVICE_NAME="apitoolkit-otel-go-demo" # Service name for your the service you're integrating in
OTEL_SERVICE_VERSION="0.0.1" # Your application's service version

Usage

After setting up the environment variables, you can configure the OpenTelemetry SDK and APItoolkit middleware like so:

package main

import (
	"log"
	"net/http"

	apitoolkit "github.com/apitoolkit/apitoolkit-go/gin"
	"github.com/gin-gonic/gin"
	_ "github.com/joho/godotenv/autoload" // autoload .env file for otel configuration
)

func main() {
	// Configure openTelemetry
	shutdown, err := apitoolkit.ConfigureOpenTelemetry()
	if err != nil {
		log.Printf("error configuring openTelemetry: %v", err)
	}
	defer shutdown()

	router := gin.Default()
	// Add the apitoolkit gin middleware to monitor http requests
	// And report errors to apitoolkit
	router.Use(apitoolkit.Middleware(apitoolkit.Config{
		RedactHeaders:      []string{"Authorization", "X-Api-Key"},
		RedactRequestBody:  []string{"password", "credit_card"},
		RedactResponseBody: []string{"password", "credit_card"},
	}))

	router.GET("/greet/:name", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "Hello " + c.Param("name")})
	})

	router.Run(":8000")
}

Error Reporting

APItoolkit automatically detects different unhandled errors, API issues, and anomalies but you can report and track specific errors at different parts of your application. This will help you associate more detail and context from your backend with any failing customer request.

To manually report specific errors at different parts of your application, use the ReportError() method, passing in the context and error arguments, like so:

package main

import (
	"log"
	"net/http"
	"os"

	apitoolkit "github.com/apitoolkit/apitoolkit-go/gin"
	"github.com/gin-gonic/gin"
	_ "github.com/joho/godotenv/autoload" // autoload .env file for otel configuration
)

func main() {
	// Configure openTelemetry
	shutdown, err := apitoolkit.ConfigureOpenTelemetry()
	if err != nil {
		log.Printf("error configuring openTelemetry: %v", err)
	}
	defer shutdown()

	router := gin.New()
	router.Use(apitoolkit.Middleware(apitoolkit.Config{}))

	router.GET("/", func(c *gin.Context) {
		file, err := os.Open("non-existing-file.txt")
		if err != nil {
			// Report the error to APItoolkit
			apitoolkit.ReportError(c.Request.Context(), err)
			c.JSON(http.StatusInternalServerError, gin.H{"message": "Something went wrong"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": file.Name()})
	})
	router.Run(":8000")
}

Monitoring Outgoing Requests

Outgoing requests are external API calls you make from your API. By default, APItoolkit monitors all requests users make from your application and they will all appear in the page.

<section class="tab-group" data-tab-group="group1"> <button class="tab-button" data-tab="tab1">Using APItoolkit</button> <button class="tab-button" data-tab="tab2">Using Otel instrumentation</button> <div id="tab1" class="tab-content"> To monitor outgoing HTTP requests from your application, replace the default HTTP client transport with a custom RoundTripper. This allows you to capture and send copies of all incoming and outgoing requests to APItoolkit.

Here's an example of the configuration with a custom RoundTripper:

package main

import (
	"log"
	"net/http"

	apitoolkit "github.com/apitoolkit/apitoolkit-go/gin"
	"github.com/gin-gonic/gin"
	_ "github.com/joho/godotenv/autoload" // autoload .env file for otel configuration
)

func main() {
	// Configure openTelemetry
	shutdown, err := apitoolkit.ConfigureOpenTelemetry()
	if err != nil {
		log.Printf("error configuring openTelemetry: %v", err)
	}
	defer shutdown()

	router := gin.New()
	router.Use(apitoolkit.Middleware(apitoolkit.Config{}))

	router.GET("/", func(c *gin.Context) {
		// Create a new HTTP client
		HTTPClient := apitoolkit.HTTPClient(
			c.Request.Context(),
			apitoolkit.WithRedactHeaders("content-type", "Authorization", "HOST"),
			apitoolkit.WithRedactRequestBody("$.user.email", "$.user.addresses"),
			apitoolkit.WithRedactResponseBody("$.users[*].email", "$.users[*].credit_card"),
		)

		// Make an outgoing HTTP request using the modified HTTPClient
		_, _ = HTTPClient.Get("https://jsonplaceholder.typicode.com/posts/1")
		c.String(http.StatusOK, "Ok, success!")
	})
	router.Run(":8000")
}

<div class="callout"> <p><i class="fa-regular fa-lightbulb"></i> <b>Tip</b></p> <p class="mt-6">You can also redact data with the custom RoundTripper for outgoing requests.</p> </div>

</div>

<div id="tab2" class="tab-content"> You can also use an otel instrumentation library to monitor outgoing requests from your server, but using this instead of the APItoolkit HTTP client will not log request and response bodies. To use otel outgoing request monitoring, you must first install it using the command below:

go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp

Here's an example of the configuration with otel instrumentation:

package main

import (
	"io"
	"log"
	"net/http"

	apitoolkit "github.com/apitoolkit/apitoolkit-go/gin"
	"github.com/gin-gonic/gin"
	_ "github.com/joho/godotenv/autoload" // autoload .env file for otel configuration
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

var clientWithOtel = http.Client{
	Transport: otelhttp.NewTransport(http.DefaultTransport),
}

func main() {
	// Configure openTelemetry
	shutdown, err := apitoolkit.ConfigureOpenTelemetry()
	if err != nil {
		log.Printf("error configuring openTelemetry: %v", err)
	}
	defer shutdown()

	router := gin.New()
	router.Use(apitoolkit.Middleware(apitoolkit.Config{}))

	router.GET("/", func(c *gin.Context) {
		// Create a new request
		ctx := c.Request.Context()
		req, err := http.NewRequestWithContext(ctx, "GET", "https://jsonplaceholder.typicode.com/users", nil)
		if err != nil {
			log.Fatalf("failed to create request: %v", err)
		}

		// Perform the request, this requests will be monitored by
		resp, err := clientWithOtel.Do(req)
		if err != nil {
			log.Fatalf("failed to make request: %v", err)
		}
		defer resp.Body.Close()

		// Read response body
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("failed to read response: %v", err)
		}

		c.String(http.StatusOK, string(body))

	})
	router.Run(":8000")
}

</div> </section>

---

OpenTelemetry Redis Instrumentation

APItoolkit provides an OpenTelemetry Redis instrumentation library that you can use to monitor Redis requests. To use the Redis instrumentation, you must first install it using the command below:

go get github.com/go-redis/redis/extra/redisotel/v8

Here's an example of the configuration with Redis instrumentation:

package main

import (
	"log"
	"net/http"

	apitoolkit "github.com/apitoolkit/apitoolkit-go/gin"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/extra/redisotel/v8"
	"github.com/go-redis/redis/v8"
	_ "github.com/joho/godotenv/autoload"
)

func main() {
	// Configure openTelemetry
	shutdown, err := apitoolkit.ConfigureOpenTelemetry()
	if err != nil {
		log.Printf("error configuring openTelemetry: %v", err)
	}
	defer shutdown()

	// Create Redis client
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})

	// Add Redis instrumentation
	rdb.AddHook(redisotel.NewTracingHook())

	router := gin.Default()
	router.Use(apitoolkit.Middleware(apitoolkit.Config{}))

	router.GET("/greet/:name", func(c *gin.Context) {
		// Get the current context from Gin
		ctx := c.Request.Context()
		// Perform Redis operations
		// IMPORTANT: You must use the context from Gin to perform Redis operations
		err := rdb.Set(ctx, "example_key", "example_value", 0).Err()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Redis set failed: " + err.Error()})
			return
		}
		val, err := rdb.Get(ctx, "example_key").Result()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Redis get failed: " + err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Hello, " + val + "!"})
	})
	router.Run(":8000")

}

All redis operations will be monitored by the OpenTelemetry SDK and can be viewed in you APIToolkit log explorer.

All Environment Variables

Set the following environment variables in your application to enable the SDK:

Variable NameDescriptionRequiredExample
OTEL_RESOURCE_ATTRIBUTESAPItoolkit project key (at-project-key=<YOUR_API_KEY>)Yesat-project-key=my-api-key
OTEL_SERVICE_NAMEThe name of the service being monitoredNoexample-chi-server
OTEL_SERVICE_VERSIONThe version of your application or serviceNo0.0.1
OTEL_EXPORTER_OTLP_ENDPOINTThe grpc endpoint for the OpenTelemetry collector.Nootelcol.apitoolkit.io:4317
OTEL_TRACES_ENABLEDEnable or disable tracingNotrue
OTEL_METRICS_ENABLEDEnable or disable metricsNotrue
OTEL_LOG_LEVELThe log level for the SDK (Set to debug to enable debug logs)Noinfo
OTEL_EXPORTER_OTLP_METRICS_PERIODThe period at which metrics are exported.No30s
OTEL_PROPAGATORSThe propagators to use for tracing.Notracecontext,baggage

All Middleware Configuration Fields

The middleware configuration specifies how the APItoolkit SDK should handle requests and responses. Below are the available fields:

Field NameTypeDescriptionDefault ValueExample
DebugboolEnable detailed logs during developmentfalsetrue
ServiceNamestringName of the service being monitored-"example-chi-server"
ServiceVersionstringVersion of the service-"0.0.1"
Tags[]stringAdditional tags for contextual information[][]string{"env:dev", "team:backend"}
CaptureRequestBodyboolEnable capturing of request bodyfalsetrue
CaptureResponseBodyboolEnable capturing of response bodyfalsetrue
RedactHeaders[]stringList of headers to redact[][]string{"Authorization", "X-Api-Key"}
RedactRequestBody[]stringJSONPath list of request body fields to redact[][]string{"$.password", "$.credit_card"}
RedactResponseBody[]stringJSONPath list of response body fields to redact[][]string{"$.password", "$.credit_card"}

<div class="callout"> <p><i class="fa-regular fa-lightbulb"></i> <b>Tips</b></p> <ol> <li> Remember to keep your APIToolkit project key (at-project-key) secure and not expose it in public repositories or logs. </li> </ul>

</div>