Написание плагина телеметрии Genkit

Библиотеки Firebase Genkit оснащены OpenTelemetry для поддержки сбора трассировок, метрик и журналов. Пользователи Genkit могут экспортировать эти данные телеметрии в инструменты мониторинга и визуализации, установив плагин, который настраивает OpenTelemetry Go SDK для экспорта в конкретную систему с поддержкой OpenTelemetry.

Genkit включает плагин, который настраивает OpenTelemetry для экспорта данных в Google Cloud Monitoring и Cloud Logging . Для поддержки других систем мониторинга вы можете расширить Genkit, написав плагин телеметрии, как описано на этой странице.

Прежде чем начать

Прочтите статью «Написание плагинов Genkit» , чтобы получить информацию о написании любого типа плагина Genkit, включая плагины телеметрии. В частности, обратите внимание, что каждый плагин должен экспортировать функцию Init , которую пользователи должны вызывать перед использованием плагина.

Экспортеры и лесорубы

Как говорилось ранее, основная задача плагина телеметрии — настроить OpenTelemetry (которым уже оснащен Genkit) для экспорта данных в конкретную службу. Для этого вам необходимо следующее:

  • Реализация интерфейса SpanExporter OpenTelemetry, который экспортирует данные в службу по вашему выбору.
  • Реализация интерфейса metric.Exporter OpenTelemetry, который экспортирует данные в службу по вашему выбору.
  • Либо slog.Logger , либо реализация интерфейса slog.Handler , который экспортирует журналы в службу по вашему выбору.

В зависимости от службы, в которую вы заинтересованы в экспорте, это может быть относительно небольшим или большим усилием.

Поскольку OpenTelemetry является отраслевым стандартом, многие службы мониторинга уже имеют библиотеки, реализующие эти интерфейсы. Например, плагин googlecloud для Genkit использует библиотеку opentelemetry-operations-go , поддерживаемую командой Google Cloud. Аналогичным образом, многие службы мониторинга предоставляют библиотеки, реализующие стандартные интерфейсы slog .

С другой стороны, если для вашего сервиса такие библиотеки недоступны, реализация необходимых интерфейсов может оказаться трудоемким проектом.

Проверьте реестр OpenTelemetry или документацию службы мониторинга, чтобы узнать, доступны ли уже интеграции.

Если вам нужно построить эти интеграции самостоятельно, загляните в исходники официальных экспортеров OpenTelemetry и на страницу A Guide to Writes slog Handlers .

Создание плагина

Зависимости

Каждый плагин телеметрии должен импортировать основную библиотеку Genkit и несколько библиотек 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"
}

Если вы создаете плагин на основе существующей интеграции OpenTelemetry или slog , вам также потребуется их импортировать.

Config

Плагин телеметрии должен, как минимум, поддерживать следующие параметры конфигурации:

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
}

В следующих примерах предполагается, что вы предоставляете эти параметры, и даются некоторые рекомендации по их использованию.

Большинство плагинов также включают параметры конфигурации службы, в которую они экспортируются (ключ API, имя проекта и т. д.).

Init()

Функция Init() плагина телеметрии должна выполнять все следующее:

  • Вернитесь раньше, если Genkit работает в среде разработки (например, при запуске с genkit start ) и параметр Config.ForceExport не установлен:

    shouldExport := cfg.ForceExport || os.Getenv("GENKIT_ENV") != "dev"
    if !shouldExport {
    	return nil
    }
    
  • Инициализируйте экспортер диапазона трассировки и зарегистрируйте его в Genkit:

    spanProcessor := trace.NewBatchSpanProcessor(YourCustomSpanExporter{})
    core.RegisterSpanProcessor(spanProcessor)
    
  • Инициализируйте экспортер метрик и зарегистрируйте его в библиотеке OpenTelemetry:

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

    Используйте настроенный пользователем интервал сбора данных ( Config.MetricInterval ) при инициализации PeriodicReader .

  • Зарегистрируйте свой обработчик slog в качестве регистратора по умолчанию:

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

    Вам следует настроить обработчик так, чтобы он учитывал указанный пользователем минимальный уровень журнала ( Config.LogLevel ).

Редактирование личных данных

Поскольку большинство потоков генеративного ИИ начинаются с какого-либо пользовательского ввода, вполне вероятно, что некоторые трассировки потока содержат информацию, позволяющую идентифицировать личность (PII). Чтобы защитить информацию ваших пользователей, вам следует удалить личные данные из следов перед их экспортом.

Если вы создаете свой собственный экспортер интервалов, вы можете встроить в него эту функциональность.

Если вы создаете свой плагин на основе существующей интеграции OpenTelemetry, вы можете обернуть предоставленный экспортер диапазона специальным экспортером, который выполняет эту задачу. Например, плагин googlecloud удаляет атрибуты genkit:input и genkit:output из каждого диапазона перед их экспортом с использованием оболочки, аналогичной следующей:

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
}

Поиск неисправностей

Если у вас возникли проблемы с отображением данных там, где вы ожидаете, OpenTelemetry предоставляет полезный диагностический инструмент , который помогает найти источник проблемы.