Passer au contenu principal
Gin-gonic est un framework web complet pour Go. Les données reportées depuis Gin-gonic sont prises en charge par AppSignal. Cette page vous aidera à configurer l’instrumentation des applications Gin-gonic et à reporter les paramètres et payloads de requête.

Configuration

Pour instrumenter votre application Go-gin, vous devrez importer le paquet d’instrumentation officiel OpenTelemetry :
import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
L’instrumentation Go-gin est packagée comme un middleware de routeur. Comme vous pouvez le voir dans l’exemple ci-dessous, l’initialisation du tracer est appelée avant tout autre chose, comme décrit plus en détail sur la page Installation Go. Ajouter otelgin.Middleware() au routeur de votre application est tout ce dont vous avez besoin pour instrumenter toutes vos requêtes.
func main() {
	cleanup := initOpenTelemetry()
	defer cleanup()

	router := gin.New()
	// This middleware must be added before any middlewares or routes
	router.Use(otelgin.Middleware("your-app-name"))
	// Your routes, app's logic, and server start up
	// ...
}

Reporter les paramètres de requête

Par défaut, l’instrumentation Gin ne reporte aucun paramètre de requête entrant, comme les chaînes de requête et le contenu du corps JSON. Pour reporter ces valeurs à AppSignal, ajoutez un middleware à votre stack Gin-gonic comme suit :
import (
	"bytes"
	"encoding/json"
	"context"
	"io/ioutil"
	"net/url"

	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/trace"
)

func recordParameters(c *gin.Context) {
	span := trace.SpanFromContext(c.Request.Context())

	// Query parameters
	requestQueryParameters := c.Request.URL.Query()
	attributeQueryParameters := make(map[string]any)
	for k, v := range requestQueryParameters {
		attributeQueryParameters[k] = v
	}

	if len(attributeQueryParameters) > 0 {
		serializedQueryParams, err := json.Marshal(attributeQueryParameters)
		if err == nil {
			span.SetAttributes(attribute.String("appsignal.request.query_parameters", string(serializedQueryParams)))
		}
	}

	// Request body payload
	var serializedBodyPayload string
	var payload map[string]interface{}
	requestBodyPayload, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		c.Next()
		return
	}
	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBodyPayload))
	contentType := c.GetHeader("Content-Type")
	if contentType == "application/json" {
		serializedBodyPayload = string(requestBodyPayload)
	} else if contentType == "application/x-www-form-urlencoded" {
		// Parse form-urlencoded body
		values, err := url.ParseQuery(string(requestBodyPayload))
		if err != nil {
			c.Next()
			return
		}

		// Convert form values to a JSON-compatible map
		payload = make(map[string]interface{})
		for key, val := range values {
			if len(val) == 1 {
				payload[key] = val[0]
			} else {
				payload[key] = val
			}
		}
		json, _ := json.Marshal(payload)
		serializedBodyPayload = string(json)
	} else {
		c.Next()
		return
	}
	if len(serializedBodyPayload) > 0 {
		span.SetAttributes(attribute.String("appsignal.request.payload", serializedBodyPayload))
	}
	c.Next()
}

func main() {
	// Init OpenTelemetry
	cleanup := initOpenTelemetry()
	defer cleanup()

	r := gin.New()
	r.Use(otelgin.Middleware("opentelemetry-go-gin"))
	// After the OpenTelemetry middleware, but before your other middlewares:
	r.Use(recordParameters)
	// Other middlewares and router handlers go here...
}