OpenTelemetry hỗ trợ thu thập dấu vết, chỉ số và nhật ký. Bạn có thể mở rộng Firebase Genkit để xuất tất cả dữ liệu đo từ xa sang bất kỳ hệ thống nào có hỗ trợ OpenTelemetry bằng cách viết một trình bổ trợ đo từ xa để định cấu hình Node.js SDK.
Cấu hình
Để kiểm soát tính năng xuất dữ liệu đo từ xa, PluginOptions
của trình bổ trợ phải cung cấp
Đối tượng telemetry
tuân thủ khối telemetry
trong cấu hình của Genkit.
export interface InitializedPlugin {
...
telemetry?: {
instrumentation?: Provider<TelemetryConfig>;
logger?: Provider<LoggerConfig>;
};
}
Đối tượng này có thể cung cấp 2 cấu hình riêng biệt:
instrumentation
: cung cấp cấu hình OpenTelemetry choTraces
vàMetrics
.logger
: cung cấp trình ghi nhật ký cơ bản mà Genkit sử dụng để ghi dữ liệu nhật ký có cấu trúc, bao gồm cả đầu vào và đầu ra của luồng Genkit.
Việc phân tách này hiện cần thiết vì chức năng ghi nhật ký cho Node.js SDK OpenTelemetry vẫn đang phát triển. Tính năng ghi nhật ký được cung cấp riêng để một trình bổ trợ có thể kiểm soát vị trí lưu trữ của dữ liệu được viết rõ ràng.
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;
Với khối mã ở trên, trình bổ trợ của bạn giờ đây sẽ cung cấp cho Genkit một dữ liệu đo từ xa mà các nhà phát triển có thể sử dụng.
Khả năng đo lường
Để kiểm soát việc xuất dấu vết và chỉ số, trình bổ trợ của bạn phải cung cấp
Thuộc tính instrumentation
trên đối tượng telemetry
tuân thủ
Giao diện TelemetryConfig
:
interface TelemetryConfig {
getConfig(): Partial<NodeSDKConfiguration>;
}
Thao tác này cung cấp Partial<NodeSDKConfiguration>
mà sẽ được sử dụng bởi
khung Genkit để khởi động
NodeSDK
.
Thao tác này cho phép trình bổ trợ kiểm soát hoàn toàn cách sử dụng tính năng tích hợp OpenTelemetry
của Genkit.
Ví dụ: cấu hình đo từ xa sau đây cung cấp một trình xuất chỉ số và dấu vết trong bộ nhớ đơn giản:
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),
}),
};
},
};
Trình ghi nhật ký
Để kiểm soát trình ghi nhật ký mà khung Genkit sử dụng để ghi dữ liệu nhật ký có cấu trúc,
trình bổ trợ này phải cung cấp thuộc tính logger
trên đối tượng telemetry
phù hợp với
Giao diện LoggerConfig
:
interface LoggerConfig {
getLogger(env: string): any;
}
{
debug(...args: any);
info(...args: any);
warn(...args: any);
error(...args: any);
level: string;
}
Hầu hết các khung ghi nhật ký phổ biến đều tuân thủ tiêu chuẩn này. Một trong những khuôn khổ này là winston, cho phép định cấu hình các trình di chuyển có thể trực tiếp đẩy dữ liệu nhật ký đến vị trí bạn chọn.
Ví dụ: để cung cấp một trình ghi nhật ký chiến thắng ghi dữ liệu nhật ký vào bảng điều khiển, bạn có thể cập nhật trình ghi nhật ký trình bổ trợ để sử dụng những tính năng sau:
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}`;
}),
});
}
};
Liên kết nhật ký và dấu vết
Thông thường, bạn nên có các câu lệnh nhật ký tương quan với
Dấu vết OpenTelemetry do trình bổ trợ của bạn xuất. Bởi vì các câu lệnh nhật ký không
được xuất trực tiếp bằng khung OpenTelemetry, điều này không xảy ra ngoài
. Rất may là OpenTelemetry hỗ trợ các công cụ đo lường sẽ sao chép dấu vết
và mở rộng mã nhận dạng vào câu lệnh nhật ký cho các khung ghi nhật ký phổ biến như winston
và pino. Bằng cách sử dụng gói @opentelemetry/auto-instrumentations-node
,
bạn có thể định cấu hình các thiết bị đo lường này (và các công cụ khác), nhưng trong
một số trường hợp bạn có thể cần kiểm soát tên trường và giá trị cho dấu vết và
span. Để làm việc này, bạn cần cung cấp khả năng đo lường LogHook tuỳ chỉnh để
cấu hình NodeSDK do TelemetryConfig
của bạn cung cấp:
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;
},
}),
]);
Ví dụ này bật tất cả các công cụ đo lường tự động cho OpenTelemetry NodeSDK
,
sau đó cung cấp một WinstonInstrumentation
tuỳ chỉnh ghi dấu vết và
mã span vào các trường tuỳ chỉnh trên thông điệp nhật ký.
Khung Genkit sẽ đảm bảo rằng TelemetryConfig
của trình bổ trợ sẽ
được khởi chạy trước LoggerConfig
của trình bổ trợ, nhưng bạn phải chú ý
đảm bảo trình ghi nhật ký cơ bản không được nhập cho đến khi LoggerConfig được
đã khởi chạy. Ví dụ: bạn có thể sửa đổi mức ghi nhật ký ở trên như sau:
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}`;
}),
});
},
};
Ví dụ đầy đủ
Sau đây là ví dụ đầy đủ về trình bổ trợ dữ liệu đo từ xa đã tạo ở trên. Để
một ví dụ thực tế, hãy xem trình bổ trợ @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;
Khắc phục sự cố
Nếu bạn gặp khó khăn khi đưa dữ liệu để hiển thị ở nơi bạn mong đợi, OpenTelemetry cung cấp Công cụ chẩn đoán giúp xác định nguồn gốc vấn đề.