Scrittura di un plug-in di telemetria Genkit

Le librerie Firebase Genkit sono strumentate con OpenTelemetry per supportare la raccolta di tracce, metriche e log. Gli utenti Genkit possono esportare questo di dati di telemetria agli strumenti di monitoraggio e visualizzazione mediante l'installazione di un plug-in configura l'SDK OpenTelemetry Go da esportare in un particolare sistema compatibile con OpenTelemetry.

Genkit include un plug-in che configura OpenTelemetry per esportare i dati in Google Cloud Monitoring e Cloud Logging. Per supportare altri sistemi di monitoraggio, puoi estendere Genkit scrivendo un plug-in di telemetria, come descritto in questa pagina.

Prima di iniziare

Per informazioni sulla scrittura di plug-in Genkit, consulta Scrittura di plug-in Genkit qualsiasi tipo di plug-in Genkit, compresi quelli di telemetria. In particolare, tieni presente che ogni plug-in deve esportare una funzione Init che gli utenti devono chiamare prima di utilizzare il plug-in.

Esportatori e logger

Come già detto in precedenza, il compito principale di un plug-in di telemetria è configurare OpenTelemetry (per il quale Genkit è già stato utilizzato) per esportare i dati a un particolare servizio. A questo scopo, ti serve quanto segue:

  • Un'implementazione di SpanExporter di OpenTelemetry che esporta i dati nel servizio che preferisci.
  • Un'implementazione di metric.Exporter di OpenTelemetry che esporta i dati nel servizio che preferisci.
  • Un slog.Logger o un'implementazione dell'interfaccia slog.Handler che esporta i log nel servizio che preferisci.

A seconda del servizio in cui vuoi eseguire l'esportazione, potrebbe essere una un impegno relativamente piccolo o grande.

Poiché OpenTelemetry è uno standard di settore, molti servizi di monitoraggio dispongono di librerie che implementano queste interfacce. Ad esempio, il plug-in googlecloud per Genkit utilizza la libreria opentelemetry-operations-go gestita dal team di Google Cloud. Analogamente, molti servizi di monitoraggio forniscono librerie che implementano standard slog.

D'altra parte, se non sono disponibili librerie di questo tipo per il tuo servizio, l'implementazione delle interfacce necessarie può essere un progetto importante.

Controlla il registro OpenTelemetry o la documentazione del servizio di monitoraggio per verificare se le integrazioni sono già disponibili.

Se devi creare personalmente queste integrazioni, dai un'occhiata alla fonte Gli esportatori ufficiali di OpenTelemetry e la pagina A Guide to Write slog Gestori.

Creazione del plug-in

Dipendenze

Ogni plug-in di telemetria deve importare la libreria di base di Genkit e diverse librerie OpenTelemetry:

import {
	// Import the Genkit core library.

	"github.com/firebase/genkit/go/genkit"

	// Import the OpenTelemetry libraries.
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/sdk/metric"
	"go.opentelemetry.io/otel/sdk/trace"
}

Se stai creando un plug-in per un'integrazione OpenTelemetry o slog esistente, dovrai anche importarli.

Config

Un plug-in di telemetria deve supportare, come minimo, le seguenti opzioni di configurazione:

type Config struct {
	// Export even in the dev environment.
	ForceExport bool

	// The interval for exporting metric data.
	// The default is 60 seconds.
	MetricInterval time.Duration

	// The minimum level at which logs will be written.
	// Defaults to [slog.LevelInfo].
	LogLevel slog.Leveler
}

Gli esempi riportati di seguito presuppongono che tu renda disponibili queste opzioni e forniranno alcune indicazioni su come gestirle.

La maggior parte dei plug-in include anche le impostazioni di configurazione per il servizio l'esportazione in (chiave API, nome progetto e così via).

Init()

La funzione Init() di un plug-in di telemetria deve eseguire tutte le seguenti operazioni:

  • Torna in anticipo se Genkit è in esecuzione in un ambiente di sviluppo (ad esempio quando viene eseguito con genkit start) e l'opzione Config.ForceExport non è impostata:

    shouldExport := cfg.ForceExport || os.Getenv("GENKIT_ENV") != "dev"
    if !shouldExport {
    	return nil
    }
    
  • Inizializza l'esportatore di intervalli di traccia e registralo con Genkit:

    spanProcessor := trace.NewBatchSpanProcessor(YourCustomSpanExporter{})
    genkit.RegisterSpanProcessor(g, spanProcessor)
    
  • Inizializza l'esportatore di metriche e registralo con la biblioteca OpenTelemetry:

    r := metric.NewPeriodicReader(
    	YourCustomMetricExporter{},
    	metric.WithInterval(cfg.MetricInterval),
    )
    mp := metric.NewMeterProvider(metric.WithReader(r))
    otel.SetMeterProvider(mp)
    

    Utilizza l'intervallo di raccolta configurato dall'utente (Config.MetricInterval) quando inizializzazione il PeriodicReader.

  • Registra il gestore slog come logger predefinito:

    logger := slog.New(YourCustomHandler{
    	Options: &slog.HandlerOptions{Level: cfg.LogLevel},
    })
    slog.SetDefault(logger)
    

    Devi configurare il gestore in modo da rispettare il log minimo specificato dall'utente livello (Config.LogLevel).

Oscuramento delle PII

Poiché la maggior parte dei flussi di IA generativa inizia con qualche tipo di input dell'utente, probabile che alcune tracce di flusso contengano l'identificazione personale di informazioni (PII). Per proteggere i tuoi utenti di informazioni, dovresti oscurare le informazioni che consentono l'identificazione personale (PII). dalle tracce prima di esportarle.

Se stai creando il tuo esportatore di span, puoi incorporare questa funzionalità.

Se stai creando il tuo plug-in sulla base di un'integrazione OpenTelemetry esistente, può aggregare l'esportatore di intervalli fornito con un esportatore personalizzato che esegue dell'attività. Ad esempio, il plug-in googlecloud rimuove genkit:input e genkit:output attributi da ogni intervallo prima di esportarli utilizzando un wrapper simile al seguente:

type redactingSpanExporter struct {
	trace.SpanExporter
}

func (e *redactingSpanExporter) ExportSpans(ctx context.Context, spanData []trace.ReadOnlySpan) error {
	var redacted []trace.ReadOnlySpan
	for _, s := range spanData {
		redacted = append(redacted, redactedSpan{s})
	}
	return e.SpanExporter.ExportSpans(ctx, redacted)
}

func (e *redactingSpanExporter) Shutdown(ctx context.Context) error {
	return e.SpanExporter.Shutdown(ctx)
}

type redactedSpan struct {
	trace.ReadOnlySpan
}

func (s redactedSpan) Attributes() []attribute.KeyValue {
	// Omit input and output, which may contain PII.
	var ts []attribute.KeyValue
	for _, a := range s.ReadOnlySpan.Attributes() {
		if a.Key == "genkit:input" || a.Key == "genkit:output" {
			continue
		}
		ts = append(ts, a)
	}
	return ts
}

Risoluzione dei problemi

Se hai difficoltà a visualizzare i dati dove previsto, OpenTelemetry offre un utile strumento di diagnostica che aiuta a individuare l'origine del problema.