OpenTelemetry รองรับการรวบรวมการติดตาม เมตริก และบันทึก คุณสามารถขยาย Firebase Genkit เพื่อส่งออกข้อมูลการวัดและส่งข้อมูลทางไกลทั้งหมดไปยังระบบที่รองรับ OpenTelemetry ได้โดยการเขียนปลั๊กอินการวัดและส่งข้อมูลทางไกลที่กำหนดค่า Node.js SDK
การกำหนดค่า
ในการควบคุมการส่งออกการวัดและส่งข้อมูลทางไกล PluginOptions
ของปลั๊กอินต้องระบุ
telemetry
ที่สอดคล้องกับบล็อก telemetry
ในการกำหนดค่าของ Genkit
export interface InitializedPlugin {
...
telemetry?: {
instrumentation?: Provider<TelemetryConfig>;
logger?: Provider<LoggerConfig>;
};
}
ออบเจ็กต์นี้มีการกำหนดค่าแยกกันได้ 2 รายการ ดังนี้
instrumentation
: มีการกำหนดค่า OpenTelemetry สำหรับTraces
และ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 Congiguration ที่นักพัฒนาซอฟต์แวร์สามารถใช้ได้
การวัดคุม
ในการควบคุมการส่งออกการติดตามและเมตริก ปลั๊กอินของคุณต้องระบุ
พร็อพเพอร์ตี้ instrumentation
ในออบเจ็กต์ telemetry
ที่สอดคล้องกับ
อินเทอร์เฟซ 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 ใช้เพื่อเขียนข้อมูลบันทึกที่มีโครงสร้าง
ปลั๊กอินต้องระบุพร็อพเพอร์ตี้ logger
ในออบเจ็กต์ telemetry
ที่สอดคล้องกับ
อินเทอร์เฟซ LoggerConfig
:
interface LoggerConfig {
getLogger(env: string): any;
}
{
debug(...args: any);
info(...args: any);
warn(...args: any);
error(...args: any);
level: string;
}
เฟรมเวิร์กการบันทึกที่ได้รับความนิยมมากที่สุดจะสอดคล้องกับแนวทางนี้ เฟรมเวิร์กอย่างหนึ่งคือ winston ซึ่งช่วยให้กำหนดค่า ผู้ขนส่งที่สามารถพุชข้อมูลบันทึกไปยังตำแหน่งที่คุณเลือกได้โดยตรง
ตัวอย่างเช่น ในการระบุ Winston Logger ที่เขียนข้อมูลบันทึกไปยังคอนโซล คุณสามารถอัปเดตตัวบันทึกปลั๊กอินเพื่อใช้สิ่งต่อไปนี้
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
และ pino เมื่อใช้แพ็กเกจ @opentelemetry/auto-instrumentations-node
คุณสามารถกำหนดค่าเครื่องมือเหล่านี้ (และอื่นๆ) ได้โดยอัตโนมัติ แต่
ในบางกรณี คุณอาจต้องควบคุมชื่อช่องและค่าสำหรับการติดตามและ
ระยะเวลา ในการดำเนินการ คุณจะต้องระบุเครื่องมือ LogHook ที่กำหนดเองเพื่อ
การกำหนดค่า NodeSDK ที่ได้จาก TelemetryConfig
ของคุณ:
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
ได้เริ่มต้นแล้ว เช่น แก้ไข LoggingConfig ด้านบนได้ดังนี้
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 เครื่องมือวินิจฉัย ซึ่งช่วยค้นหาที่มาของปัญหา