Zum Hauptinhalt springen
Gin-gonic ist ein vollwertiges Web-Framework für Go. Daten, die von Gin-gonic gemeldet werden, werden von AppSignal unterstützt. Diese Seite hilft Ihnen bei der Einrichtung, um Gin-gonic-Anwendungen zu instrumentieren und Request-Parameter und Payloads zu melden.

Einrichtung

Um Ihre Go-Gin-Anwendung zu instrumentieren, müssen Sie das offizielle OpenTelemetry-Instrumentierungspaket importieren:
import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
Die Go-Gin-Instrumentierung ist als Router-Middleware verpackt. Wie Sie im folgenden Beispiel sehen, wird die Tracer-Initialisierung vor allem anderen aufgerufen, wie auf der Seite Go-Installation ausführlicher beschrieben. otelgin.Middleware() zu Ihrem App-Router hinzuzufügen, ist alles, was Sie benötigen, um alle Ihre Requests instrumentiert zu bekommen.
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
	// ...
}

Request-Parameter melden

Standardmäßig meldet die Gin-Instrumentierung keine eingehenden Request-Parameter, wie Query-Strings und JSON-Body-Inhalte. Um diese Werte an AppSignal zu melden, fügen Sie Ihrem Gin-gonic-Stack eine Middleware wie folgt hinzu:
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...
}