Zapisywanie wtyczki telemetrycznej Genkit

Biblioteki Firebase Genkit są wyposażone w mechanizm OpenTelemetry z myślą o zbieraniu logów czasu, wskaźników i logów. Użytkownicy Genkit mogą to wyeksportować danych telemetrycznych do narzędzi do monitorowania i wizualizacji, instalując wtyczkę, która konfiguruje pakiet SDK OpenTelemetry Go, aby wyeksportować dane do konkretnego systemu obsługującego OpenTelemetry.

Genkit zawiera wtyczkę, która konfiguruje OpenTelemetry, aby eksportować dane do Google Cloud Monitoring i Cloud Logging. Dla zespołu pomocy z innych systemów monitorowania, możesz rozszerzyć Genkit, pisząc wtyczkę telemetryczną, jak opisano na tej stronie.

Zanim zaczniesz

Więcej informacji o pisaniu znajdziesz w artykule Pisanie wtyczek Genkit. wszelkiego rodzaju wtyczki Genkit, łącznie z wtyczkami do telemetrii. Zwróć szczególną uwagę na to, każda wtyczka musi eksportować funkcję Init, którą użytkownicy powinni wywoływać przed użyciem wtyczki.

Eksporterzy i rejestratorzy

Jak już wspomnieliśmy, głównym zadaniem wtyczki telemetrycznej jest skonfigurowanie OpenTelemetry (który jest już używany Genkit) do eksportowania danych. do konkretnej usługi. Aby to zrobić, potrzebne są:

  • Implementacja interfejsu SpanExporter OpenTelemetry który eksportuje dane do wybranej usługi.
  • Implementacja interfejsu metric.Exporter OpenTelemetry który eksportuje dane do wybranej usługi.
  • slog.Logger lub implementacja interfejsu slog.Handler który eksportuje dzienniki do wybranej usługi.

W zależności od usługi, do której chcesz eksportować dane, może to być lub stosunkowo niewielkiego wysiłku.

OpenTelemetry to standard branżowy, dlatego wiele usług monitoringu korzysta już z tej usługi. które z nich korzystają. Na przykład googlecloud wtyczka do Genkit korzysta z opentelemetry-operations-go i obsługiwanym przez zespół Google Cloud. Podobnie wiele usług monitorowania udostępnia biblioteki, które implementują standardowych interfejsów slog.

Jeśli natomiast dla danej usługi nie są dostępne żadne takie biblioteki, wdrożenie niezbędnych interfejsów może być pracochłonne.

Sprawdź rejestr OpenTelemetry. lub w dokumentach usługi monitorowania, aby sprawdzić, czy integracje są już dostępne.

Jeśli chcesz utworzyć te integracje samodzielnie, spójrz na źródło oficjalnych eksporterów OpenTelemetry, i stronę A Guide to Write slog Handlers.

Tworzenie wtyczki

Zależności

Każda wtyczka do telemetrii musi zaimportować podstawową bibliotekę Genkit oraz kilka Biblioteki OpenTelemetry:

import {
	// Import the Genkit core library.
	"github.com/firebase/genkit/go/core"

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

Jeśli tworzysz wtyczkę wokół istniejącego rozwiązania OpenTelemetry lub slog musisz zaimportować.

Config

Wtyczka telemetryczna powinna przynajmniej obsługiwać następującą konfigurację opcje:

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
}

W przykładach poniżej zakładamy, że udostępniasz te opcje i podam kilka wskazówek, jak z nimi radzić.

Większość wtyczek zawiera też ustawienia konfiguracji usługi, z której korzysta eksportu do (klucz interfejsu API, nazwa projektu itd.).

Init()

Funkcja Init() wtyczki telemetrycznej powinna wykonywać wszystkie te czynności:

  • Wróć wcześniej, jeśli Genkit działa w środowisku programistycznym (na przykład działa z genkit start), a opcja Config.ForceExport nie jest ustaw:

    shouldExport := cfg.ForceExport || os.Getenv("GENKIT_ENV") != "dev"
    if !shouldExport {
    	return nil
    }
    
  • Zainicjuj eksportera spanów logów czasu i zarejestruj go w Genkit:

    spanProcessor := trace.NewBatchSpanProcessor(YourCustomSpanExporter{})
    core.RegisterSpanProcessor(spanProcessor)
    
  • Zainicjuj eksportera wskaźników i zarejestruj go w OpenTelemetry biblioteka:

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

    Użyj interwału zbierania danych skonfigurowanego przez użytkownika (Config.MetricInterval), gdy inicjuję PeriodicReader.

  • Zarejestruj moduł obsługi slog jako domyślny rejestrator:

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

    Moduł obsługi należy skonfigurować tak, aby przestrzegał określonej przez użytkownika minimalnej wartości logu poziom (Config.LogLevel).

Usuwanie informacji umożliwiających identyfikację osób

Większość procesów związanych z generatywną AI zaczyna się od jakiegoś rodzaju danych wejściowych użytkownika, prawdopodobne, że niektóre ślady przepływu zawierają dane umożliwiające identyfikację osób informacje umożliwiające identyfikację osoby. Aby chronić użytkowników należy usunąć informacje umożliwiające identyfikację, z logów czasu przed ich wyeksportowaniem.

Jeśli tworzysz własny eksporter spanów, możesz utworzyć tę funkcję w grę.

Jeśli Twoja wtyczka jest oparta na istniejącej integracji OpenTelemetry, może opakować podany eksporter spanów niestandardowym eksporterem, który wykonuje tę czynność zadanie. Na przykład wtyczka googlecloud usuwa żądania genkit:input oraz genkit:output atrybutów z każdego spanu przed wyeksportowaniem ich za pomocą opakowania podobnie jak poniżej:

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
}

Rozwiązywanie problemów

Jeśli masz problemy z wyświetleniem danych w oczekiwanym miejscu, OpenTelemetry udostępnia przydatne narzędzie diagnostyczne co pomaga w znalezieniu źródła problemu.