Genkit टेलीमेट्री प्लगिन लिखना

OpenTelemetry में ट्रेस, मेट्रिक, और लॉग इकट्ठा करने की सुविधा होती है. Firebase Genkit को Node.js SDK टूल.

कॉन्फ़िगरेशन

टेलीमेट्री एक्सपोर्ट को कंट्रोल करने के लिए, आपके प्लगिन के PluginOptions में telemetry ऑब्जेक्ट जो Genkit के कॉन्फ़िगरेशन में telemetry ब्लॉक के मुताबिक है.

export interface InitializedPlugin {
  ...
  telemetry?: {
    instrumentation?: Provider<TelemetryConfig>;
    logger?: Provider<LoggerConfig>;
  };
}

यह ऑब्जेक्ट दो अलग-अलग कॉन्फ़िगरेशन दे सकता है:

  • instrumentation: Traces के लिए OpenTelemetry कॉन्फ़िगरेशन देता है और Metrics.
  • logger: यह Genkit के ज़रिए लिखने के लिए इस्तेमाल किया गया लॉगर उपलब्ध कराता है स्ट्रक्चर्ड लॉग डेटा जिसमें Genkit फ़्लो के इनपुट और आउटपुट शामिल हों.

Node.js के लिए फ़ंक्शन को लॉग करने की वजह से, डेटा को अलग करना ज़रूरी है OpenTelemetry SDK टूल पर अब भी इस पर काम चल रहा है. डेटा लॉग करने की सुविधा अलग से दी जाती है, ताकि प्लगिन यह कंट्रोल कर सके कि डेटा कहां पर है साफ़ तौर पर लिखा होगा.

import { genkitPlugin, Plugin } from '@genkit-ai/core';

...

export interface MyPluginOptions {
  // [Optional] Your plugin options
}

export const myPlugin: Plugin<[MyPluginOptions] | []> = genkitPlugin(
  'myPlugin',
  async (options?: MyPluginOptions) => {
    return {
      telemetry: {
        instrumentation: {
          id: 'myPlugin',
          value: myTelemetryConfig,
        },
        logger: {
          id: 'myPlugin',
          value: myLogger,
        },
      },
    };
  }
);

export default myPlugin;

ऊपर दिए गए कोड ब्लॉक की मदद से, अब आपका प्लगिन, Genkit के साथ टेलीमेट्री का ऐक्सेस देगा का इस्तेमाल डेवलपर कैसे कर सकते हैं.

इंस्ट्रुमेंटेशन

ट्रेस और मेट्रि�� के एक्सपोर्ट को कंट्रोल करने के लिए, आपके प्लगिन को telemetry ऑब्जेक्ट पर instrumentation प्रॉपर्टी, जो TelemetryConfig इंटरफ़ेस:

interface TelemetryConfig {
  getConfig(): Partial<NodeSDKConfiguration>;
}

यह एक Partial<NodeSDKConfiguration> उपलब्ध कराता है, जिसका इस्तेमाल Genkit फ़्रेमवर्क NodeSDK. इससे प्लगिन को यह पूरा कंट्रोल मिलता है कि OpenTelemetry इंटिग्रेशन का इस्तेमाल कैसे किया जाता है Genkit से.

उदाहरण के लिए, नीचे दिया गया टेलीमेट्री कॉन्फ़िगरेशन, मेमोरी में मौजूद जानकारी का आसान ट्रेस और मेट्रिक एक्सपोर्टर उपलब्ध कराता है:

import { AggregationTemporality, InMemoryMetricExporter, MetricReader, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { AlwaysOnSampler, BatchSpanProcessor, InMemorySpanExporter } from '@opentelemetry/sdk-trace-base';
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
import { Resource } from '@opentelemetry/resources';
import { TelemetryConfig } from '@genkit-ai/core';

...

const myTelemetryConfig: TelemetryConfig = {
  getConfig(): Partial<NodeSDKConfiguration> {
    return {
      resource: new Resource({}),
      spanProcessor: new BatchSpanProcessor(new InMemorySpanExporter()),
      sampler: new AlwaysOnSampler(),
      instrumentations: myPluginInstrumentations,
      metricReader: new PeriodicExportingMetricReader({
        exporter: new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE),
      }),
    };
  },
};

लकड़ी का काम करने वाला

स्ट्रक्चर्ड लॉग डेटा लिखने के लिए Genkit फ़्रेमवर्क के ज़रिए इस्तेमाल किए जाने वाले लॉगर को कंट्रोल करने के लिए, प्लगिन को telemetry ऑब्जेक्ट पर एक logger प्रॉपर्टी देनी होगी, जो LoggerConfig इंटरफ़ेस:

interface LoggerConfig {
  getLogger(env: string): any;
}
{
  debug(...args: any);
  info(...args: any);
  warn(...args: any);
  error(...args: any);
  level: string;
}

ज़्यादातर लोकप्रिय लॉगिंग फ़्रेमवर्क इसका पालन करते हैं. ऐसा ही एक फ़्रेमवर्क है winston, जिसकी मदद से आप कॉन्फ़िगर कर सकते हैं ऐसे ट्रांसपोर्टर जो लॉग डेटा को सीधे आपकी चुनी गई जगह पर भेज सकते हैं.

उदाहरण के लिए, कंसोल में लॉग डेटा लिखने वाला विंस्टन लॉगर उपलब्ध कराने के लिए, तो आप अपने प्लगिन लॉगर को अपडेट करके इनका इस्तेमाल कर सकते हैं:

import * as winston from 'winston';

...

const myLogger: LoggerConfig = {
  getLogger(env: string) {
    return winston.createLogger({
      transports: [new winston.transports.Console()],
      format: winston.format.printf((info): string => {
        return `[${info.level}] ${info.message}`;
      }),
    });
  }
};

लिंक करने के लॉग और ट्रेस

अक्सर आपके लॉग स्टेटमेंट को OpenTelemetry ट्रेस, आपके प्लगिन से एक्सपोर्ट किए जाते हैं. क्योंकि लॉग स्टेटमेंट सीधे OpenTelemetry फ़्रेमवर्क से एक्सपोर्ट किए जाते हैं, तो यह ज़रूरी नहीं है. बॉक्स. अच्छी बात यह है कि OpenTelemetry ऐसे इंस्ट्रुमेंटेशन का इस्तेमाल करता है जो ट्रेस को कॉपी करेंगे और winston जैसे लोकप्रिय लॉगिंग फ़्रेमवर्क के लिए लॉग स्टेटमेंट पर स्पैन आईडी और पीनो. @opentelemetry/auto-instrumentations-node पैकेज का इस्तेमाल करने का मतलब है कि तो ये (और अन्य) इंस्ट्रुमेंटेशन अपने-आप कॉन्फ़िगर हो सकते हैं, लेकिन कुछ मामलों में आपको ट्रेस के फ़ील्ड के नाम और वैल्यू को कंट्रोल करना पड़ सकता है स्पैन. ऐसा करने के लिए, आपको पसंद के मुताबिक LogHook इंस्ट्रुमेंटेशन देना होगा आपके TelemetryConfig से मिला NodeSDK कॉन्फ़िगरेशन:

import { Instrumentation } from '@opentelemetry/instrumentation';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { WinstonInstrumentation } from '@opentelemetry/instrumentation-winston';
import { Span } from '@opentelemetry/api';

const myPluginInstrumentations: Instrumentation[] =
  getNodeAutoInstrumentations().concat([
    new WinstonInstrumentation({
      logHook: (span: Span, record: any) => {
        record['my-trace-id'] = span.spanContext().traceId;
        record['my-span-id'] = span.spanContext().spanId;
        record['is-trace-sampled'] = span.spanContext().traceFlags;
      },
    }),
  ]);

इस उदाहरण में, OpenTelemetry NodeSDK के लिए सभी ऑटो इंस्ट्रुमेंटेशन को चालू किया गया है, इसके बाद, पसंद के मुताबिक बनाया गया WinstonInstrumentation उपलब्ध कराता है, जो ट्रेस लिखता है और स्पैन आईडी को लॉग मैसेज पर कस्टम फ़ील्ड में बदल सकते हैं.

Genkit फ़्रेमवर्क इस बात की गारंटी देगा कि आपके प्लगिन का TelemetryConfig आपके प्लग इन के LoggerConfig से पहले शुरू किया गया होता है, लेकिन आपको इन बातों का ध्यान रखना होगा पक्का करें कि मौजूदा लॉगर को तब तक इंपोर्ट न किया जा��, जब तक LoggerConfig शुरू किया गया. उदाहरण के लिए, ऊपर दिए गए LogConfig में इस तरह से बदलाव किया जा सकता है:

const myLogger: LoggerConfig = {
  async getLogger(env: string) {
    // Do not import winston before calling getLogger so that the NodeSDK
    // instrumentations can be registered first.
    const winston = await import('winston');

    return winston.createLogger({
      transports: [new winston.transports.Console()],
      format: winston.format.printf((info): string => {
        return `[${info.level}] ${info.message}`;
      }),
    });
  },
};

पूरा उदाहरण

ऊपर बनाए गए टेलीमेट्री प्लगिन का पूरा उदाहरण नीचे दिया गया है. इसके लिए व्यावहारिक उदाहरण के लिए, @genkit-ai/google-cloud प्लगिन पर एक नज़र डालें.

import {
  genkitPlugin,
  LoggerConfig,
  Plugin,
  TelemetryConfig,
} from '@genkit-ai/core';
import { Span } from '@opentelemetry/api';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Instrumentation } from '@opentelemetry/instrumentation';
import { WinstonInstrumentation } from '@opentelemetry/instrumentation-winston';
import { Resource } from '@opentelemetry/resources';
import {
  AggregationTemporality,
  InMemoryMetricExporter,
  PeriodicExportingMetricReader,
} from '@opentelemetry/sdk-metrics';
import { NodeSDKConfiguration } from '@opentelemetry/sdk-node';
import {
  AlwaysOnSampler,
  BatchSpanProcessor,
  InMemorySpanExporter,
} from '@opentelemetry/sdk-trace-base';

export interface MyPluginOptions {
  // [Optional] Your plugin options
}

const myPluginInstrumentations: Instrumentation[] =
  getNodeAutoInstrumentations().concat([
    new WinstonInstrumentation({
      logHook: (span: Span, record: any) => {
        record['my-trace-id'] = span.spanContext().traceId;
        record['my-span-id'] = span.spanContext().spanId;
        record['is-trace-sampled'] = span.spanContext().traceFlags;
      },
    }),
  ]);

const myTelemetryConfig: TelemetryConfig = {
  getConfig(): Partial<NodeSDKConfiguration> {
    return {
      resource: new Resource({}),
      spanProcessor: new BatchSpanProcessor(new InMemorySpanExporter()),
      sampler: new AlwaysOnSampler(),
      instrumentations: myPluginInstrumentations,
      metricReader: new PeriodicExportingMetricReader({
        exporter: new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE),
      }),
    };
  },
};

const myLogger: LoggerConfig = {
  async getLogger(env: string) {
    // Do not import winston before calling getLogger so that the NodeSDK
    // instrumentations can be registered first.
    const winston = await import('winston');

    return winston.createLogger({
      transports: [new winston.transports.Console()],
      format: winston.format.printf((info): string => {
        return `[${info.level}] ${info.message}`;
      }),
    });
  },
};

export const myPlugin: Plugin<[MyPluginOptions] | []> = genkitPlugin(
  'myPlugin',
  async (options?: MyPluginOptions) => {
    return {
      telemetry: {
        instrumentation: {
          id: 'myPlugin',
          value: myTelemetryConfig,
        },
        logger: {
          id: 'myPlugin',
          value: myLogger,
        },
      },
    };
  }
);

export default myPlugin;

समस्या का हल

अगर आपको अपनी उम्मीद के मुताबिक डेटा नहीं मिल रहा है, तो OpenTelemetry आपके लिए डाइग्नोस्टिक टूल जो समस्या के सोर्स का पता लगाने में मदद करती है.