OpenTelemetry obsługuje zbieranie logów czasu, wskaźników i logów. Firebase Genkit można rozszerzyć do eksportowania wszystkich danych telemetrycznych do dowolnego systemu obsługującego OpenTelemetry. W tym celu należy napisać wtyczkę telemetryczną, która konfiguruje Node.js SDK.
Konfiguracja
Aby kontrolować eksportowanie danych telemetrycznych, PluginOptions
wtyczki musi udostępniać
Obiekt telemetry
zgodny z blokiem telemetry
w konfiguracji Genkit.
export interface InitializedPlugin {
...
telemetry?: {
instrumentation?: Provider<TelemetryConfig>;
logger?: Provider<LoggerConfig>;
};
}
Ten obiekt może udostępniać 2 oddzielne konfiguracje:
instrumentation
: udostępnia konfigurację OpenTelemetry dla interfejsówTraces
iMetrics
logger
: udostępnia rejestrator używany przez Genkit do zapisu. uporządkowane dane dziennika, w tym dane wejściowe i wyjściowe przepływów Genkit.
Ten rozdział jest obecnie potrzebny, ponieważ funkcja logowania w Node.js Pakiet OpenTelemetry SDK jest nadal rozwijany. Logowanie jest dostępne oddzielnie, więc wtyczka może kontrolować, gdzie znajdują się dane napisane wprost.
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;
Dzięki powyższemu blokowi kodu wtyczka będzie teraz udostępniać Genkit dane telemetryczne , z której mogą korzystać programiści.
Instrumentacja
Aby kontrolować eksportowanie logów czasu i wskaźników, wtyczka musi udostępniać
właściwość instrumentation
w obiekcie telemetry
zgodną z
Interfejs TelemetryConfig
:
interface TelemetryConfig {
getConfig(): Partial<NodeSDKConfiguration>;
}
Zapewnia to obiekt Partial<NodeSDKConfiguration>
, który będzie używany przez
Genkit do uruchamiania
NodeSDK
.
Daje to wtyczce pełną kontrolę nad sposobem korzystania z integracji OpenTelemetry
od Genkit.
Na przykład ta konfiguracja telemetrii zapewnia prosty eksporter śledzenia i wskaźników w pamięci:
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),
}),
};
},
};
Rejestrator
Aby kontrolować rejestrator używany przez platformę Genkit do zapisywania uporządkowanych danych logów:
wtyczka musi zawierać w obiekcie telemetry
właściwość logger
zgodną z
Interfejs LoggerConfig
:
interface LoggerConfig {
getLogger(env: string): any;
}
{
debug(...args: any);
info(...args: any);
warn(...args: any);
error(...args: any);
level: string;
}
Zgodne są z tym większość popularnych platform logowania. Jednym z takich rozwiązań jest winston, która umożliwia skonfigurowanie Transportery, które mogą bezpośrednio przenosić dane dziennika do wybranej lokalizacji.
Aby na przykład udostępnić rejestrator Winston, który zapisuje dane dziennika w konsoli, możesz zaktualizować rejestrator wtyczek, aby używał:
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}`;
}),
});
}
};
Łączenie logów i logów czasu
Często dobrze jest, aby instrukcje dziennika były powiązane z
Logi czasu OpenTelemetry wyeksportowane przez Twoją wtyczkę. Ponieważ wyciągi dziennika nie są
eksportowanych bezpośrednio przez platformę OpenTelemetry. Nie zdarza się to bezpośrednio w
. Na szczęście OpenTelemetry obsługuje instrumenty, które skopiują log czasu.
i dodawania identyfikatorów span do instrukcji logowania w przypadku popularnych platform logowania, takich jak winston.
i pino. Korzystając z pakietu @opentelemetry/auto-instrumentations-node
,
możesz skonfigurować te (i inne) instrumenty automatycznie, ale
w niektórych przypadkach trzeba kontrolować nazwy i wartości pól w śladach oraz
spany. Aby to zrobić, musisz udostępnić niestandardową instrumentację LogHook do
konfiguracja NodeSDK udostępniona przez 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;
},
}),
]);
Ten przykład włącza wszystkie instrumenty automatyczne na potrzeby OpenTelemetry NodeSDK
,
a potem udostępnia niestandardowy element WinstonInstrumentation
, który zapisuje ślad i
identyfikatory spanów do pól niestandardowych w komunikacie logu.
Platforma Genkit gwarantuje, że TelemetryConfig
wtyczki zostanie
została zainicjowana przed żądaniem LoggerConfig
wtyczki, ale musisz sprawdzić, czy
upewnij się, że bazowy rejestrator nie zostanie zaimportowany, dopóki konfiguracja LoggerConfig nie zostanie
zainicjowano. Na przykład powyższą konfigurację LoggingConfig można zmodyfikować w ten sposób:
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}`;
}),
});
},
};
Pełny przykład
Poniżej znajdziesz pełny przykład utworzonej powyżej wtyczki telemetrycznej. Dla:
z jakiegoś przykładu, przyjrzyj się wtyczce @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;
Rozwiązywanie problemów
Jeśli masz problemy z wyświetleniem danych w oczekiwanych miejscach, OpenTelemetry Narzędzie diagnostyczne co pomaga w znalezieniu źródła problemu.