Add support for HTTP OpenTelemetry exporters (#6357)
This commit is contained in:
parent
4896c7739f
commit
d57cc0b930
|
@ -435,6 +435,8 @@ Arguments passed directly when running the CLI can override other configurations
|
|||
- Sets the telemetry target. See [telemetry](../telemetry.md) for more information.
|
||||
- **`--telemetry-otlp-endpoint`**:
|
||||
- Sets the OTLP endpoint for telemetry. See [telemetry](../telemetry.md) for more information.
|
||||
- **`--telemetry-otlp-protocol`**:
|
||||
- Sets the OTLP protocol for telemetry (`grpc` or `http`). Defaults to `grpc`. See [telemetry](../telemetry.md) for more information.
|
||||
- **`--telemetry-log-prompts`**:
|
||||
- Enables logging of prompts for telemetry. See [telemetry](../telemetry.md) for more information.
|
||||
- **`--checkpointing`**:
|
||||
|
|
|
@ -74,7 +74,11 @@ gemini --telemetry \
|
|||
## Running an OTEL Collector
|
||||
|
||||
An OTEL Collector is a service that receives, processes, and exports telemetry data.
|
||||
The CLI sends data using the OTLP/gRPC protocol.
|
||||
The CLI can send data using either the OTLP/gRPC or OTLP/HTTP protocol.
|
||||
You can specify which protocol to use via the `--telemetry-otlp-protocol` flag
|
||||
or the `telemetry.otlpProtocol` setting in your `settings.json` file. See the
|
||||
[configuration docs](./cli/configuration.md#--telemetry-otlp-protocol) for more
|
||||
details.
|
||||
|
||||
Learn more about OTEL exporter standard configuration in [documentation][otel-config-docs].
|
||||
|
||||
|
|
|
@ -1626,6 +1626,25 @@
|
|||
"@opentelemetry/api": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/exporter-logs-otlp-http": {
|
||||
"version": "0.52.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.52.1.tgz",
|
||||
"integrity": "sha512-qKgywId2DbdowPZpOBXQKp0B8DfhfIArmSic15z13Nk/JAOccBUQdPwDjDnjsM5f0ckZFMVR2t/tijTUAqDZoA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/api-logs": "0.52.1",
|
||||
"@opentelemetry/core": "1.25.1",
|
||||
"@opentelemetry/otlp-exporter-base": "0.52.1",
|
||||
"@opentelemetry/otlp-transformer": "0.52.1",
|
||||
"@opentelemetry/sdk-logs": "0.52.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@opentelemetry/exporter-metrics-otlp-grpc": {
|
||||
"version": "0.52.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.52.1.tgz",
|
||||
|
@ -12496,8 +12515,11 @@
|
|||
"@modelcontextprotocol/sdk": "^1.11.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/exporter-logs-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "^0.52.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "^0.52.0",
|
||||
"@opentelemetry/exporter-trace-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.52.0",
|
||||
"@opentelemetry/instrumentation-http": "^0.52.0",
|
||||
"@opentelemetry/sdk-node": "^0.52.0",
|
||||
"@types/glob": "^8.1.0",
|
||||
|
|
|
@ -536,6 +536,60 @@ describe('loadCliConfig telemetry', () => {
|
|||
const config = await loadCliConfig(settings, [], 'test-session', argv);
|
||||
expect(config.getTelemetryLogPromptsEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('should use telemetry OTLP protocol from settings if CLI flag is not present', async () => {
|
||||
process.argv = ['node', 'script.js'];
|
||||
const argv = await parseArguments();
|
||||
const settings: Settings = {
|
||||
telemetry: { otlpProtocol: 'http' },
|
||||
};
|
||||
const config = await loadCliConfig(settings, [], 'test-session', argv);
|
||||
expect(config.getTelemetryOtlpProtocol()).toBe('http');
|
||||
});
|
||||
|
||||
it('should prioritize --telemetry-otlp-protocol CLI flag over settings', async () => {
|
||||
process.argv = ['node', 'script.js', '--telemetry-otlp-protocol', 'http'];
|
||||
const argv = await parseArguments();
|
||||
const settings: Settings = {
|
||||
telemetry: { otlpProtocol: 'grpc' },
|
||||
};
|
||||
const config = await loadCliConfig(settings, [], 'test-session', argv);
|
||||
expect(config.getTelemetryOtlpProtocol()).toBe('http');
|
||||
});
|
||||
|
||||
it('should use default protocol if no OTLP protocol is provided via CLI or settings', async () => {
|
||||
process.argv = ['node', 'script.js'];
|
||||
const argv = await parseArguments();
|
||||
const settings: Settings = { telemetry: { enabled: true } };
|
||||
const config = await loadCliConfig(settings, [], 'test-session', argv);
|
||||
expect(config.getTelemetryOtlpProtocol()).toBe('grpc');
|
||||
});
|
||||
|
||||
it('should reject invalid --telemetry-otlp-protocol values', async () => {
|
||||
process.argv = [
|
||||
'node',
|
||||
'script.js',
|
||||
'--telemetry-otlp-protocol',
|
||||
'invalid',
|
||||
];
|
||||
|
||||
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
|
||||
throw new Error('process.exit called');
|
||||
});
|
||||
|
||||
const mockConsoleError = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => {});
|
||||
|
||||
await expect(parseArguments()).rejects.toThrow('process.exit called');
|
||||
|
||||
expect(mockConsoleError).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Invalid values:'),
|
||||
);
|
||||
|
||||
mockExit.mockRestore();
|
||||
mockConsoleError.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Hierarchical Memory Loading (config.ts) - Placeholder Suite', () => {
|
||||
|
|
|
@ -64,6 +64,7 @@ export interface CliArgs {
|
|||
checkpointing: boolean | undefined;
|
||||
telemetryTarget: string | undefined;
|
||||
telemetryOtlpEndpoint: string | undefined;
|
||||
telemetryOtlpProtocol: string | undefined;
|
||||
telemetryLogPrompts: boolean | undefined;
|
||||
telemetryOutfile: string | undefined;
|
||||
allowedMcpServerNames: string[] | undefined;
|
||||
|
@ -172,6 +173,12 @@ export async function parseArguments(): Promise<CliArgs> {
|
|||
description:
|
||||
'Set the OTLP endpoint for telemetry. Overrides environment variables and settings files.',
|
||||
})
|
||||
.option('telemetry-otlp-protocol', {
|
||||
type: 'string',
|
||||
choices: ['grpc', 'http'],
|
||||
description:
|
||||
'Set the OTLP protocol for telemetry (grpc or http). Overrides settings files.',
|
||||
})
|
||||
.option('telemetry-log-prompts', {
|
||||
type: 'boolean',
|
||||
description:
|
||||
|
@ -491,6 +498,11 @@ export async function loadCliConfig(
|
|||
argv.telemetryOtlpEndpoint ??
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
|
||||
settings.telemetry?.otlpEndpoint,
|
||||
otlpProtocol: (['grpc', 'http'] as const).find(
|
||||
(p) =>
|
||||
p ===
|
||||
(argv.telemetryOtlpProtocol ?? settings.telemetry?.otlpProtocol),
|
||||
),
|
||||
logPrompts: argv.telemetryLogPrompts ?? settings.telemetry?.logPrompts,
|
||||
outfile: argv.telemetryOutfile ?? settings.telemetry?.outfile,
|
||||
},
|
||||
|
|
|
@ -24,8 +24,11 @@
|
|||
"@modelcontextprotocol/sdk": "^1.11.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/exporter-logs-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "^0.52.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "^0.52.0",
|
||||
"@opentelemetry/exporter-trace-otlp-grpc": "^0.52.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.52.0",
|
||||
"@opentelemetry/instrumentation-http": "^0.52.0",
|
||||
"@opentelemetry/sdk-node": "^0.52.0",
|
||||
"@types/glob": "^8.1.0",
|
||||
|
|
|
@ -567,5 +567,30 @@ describe('Server Config (config.ts)', () => {
|
|||
const config = new Config(paramsWithoutTelemetry);
|
||||
expect(config.getTelemetryOtlpEndpoint()).toBe(DEFAULT_OTLP_ENDPOINT);
|
||||
});
|
||||
|
||||
it('should return provided OTLP protocol', () => {
|
||||
const params: ConfigParameters = {
|
||||
...baseParams,
|
||||
telemetry: { enabled: true, otlpProtocol: 'http' },
|
||||
};
|
||||
const config = new Config(params);
|
||||
expect(config.getTelemetryOtlpProtocol()).toBe('http');
|
||||
});
|
||||
|
||||
it('should return default OTLP protocol if not provided', () => {
|
||||
const params: ConfigParameters = {
|
||||
...baseParams,
|
||||
telemetry: { enabled: true },
|
||||
};
|
||||
const config = new Config(params);
|
||||
expect(config.getTelemetryOtlpProtocol()).toBe('grpc');
|
||||
});
|
||||
|
||||
it('should return default OTLP protocol if telemetry object is not provided', () => {
|
||||
const paramsWithoutTelemetry: ConfigParameters = { ...baseParams };
|
||||
delete paramsWithoutTelemetry.telemetry;
|
||||
const config = new Config(paramsWithoutTelemetry);
|
||||
expect(config.getTelemetryOtlpProtocol()).toBe('grpc');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -81,6 +81,7 @@ export interface TelemetrySettings {
|
|||
enabled?: boolean;
|
||||
target?: TelemetryTarget;
|
||||
otlpEndpoint?: string;
|
||||
otlpProtocol?: 'grpc' | 'http';
|
||||
logPrompts?: boolean;
|
||||
outfile?: string;
|
||||
}
|
||||
|
@ -292,6 +293,7 @@ export class Config {
|
|||
enabled: params.telemetry?.enabled ?? false,
|
||||
target: params.telemetry?.target ?? DEFAULT_TELEMETRY_TARGET,
|
||||
otlpEndpoint: params.telemetry?.otlpEndpoint ?? DEFAULT_OTLP_ENDPOINT,
|
||||
otlpProtocol: params.telemetry?.otlpProtocol,
|
||||
logPrompts: params.telemetry?.logPrompts ?? true,
|
||||
outfile: params.telemetry?.outfile,
|
||||
};
|
||||
|
@ -564,6 +566,10 @@ export class Config {
|
|||
return this.telemetrySettings.otlpEndpoint ?? DEFAULT_OTLP_ENDPOINT;
|
||||
}
|
||||
|
||||
getTelemetryOtlpProtocol(): 'grpc' | 'http' {
|
||||
return this.telemetrySettings.otlpProtocol ?? 'grpc';
|
||||
}
|
||||
|
||||
getTelemetryTarget(): TelemetryTarget {
|
||||
return this.telemetrySettings.target ?? DEFAULT_TELEMETRY_TARGET;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { Config } from '../config/config.js';
|
||||
import { initializeTelemetry, shutdownTelemetry } from './sdk.js';
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
|
||||
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
|
||||
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
|
||||
import { OTLPTraceExporter as OTLPTraceExporterHttp } from '@opentelemetry/exporter-trace-otlp-http';
|
||||
import { OTLPLogExporter as OTLPLogExporterHttp } from '@opentelemetry/exporter-logs-otlp-http';
|
||||
import { OTLPMetricExporter as OTLPMetricExporterHttp } from '@opentelemetry/exporter-metrics-otlp-http';
|
||||
import { NodeSDK } from '@opentelemetry/sdk-node';
|
||||
|
||||
vi.mock('@opentelemetry/exporter-trace-otlp-grpc');
|
||||
vi.mock('@opentelemetry/exporter-logs-otlp-grpc');
|
||||
vi.mock('@opentelemetry/exporter-metrics-otlp-grpc');
|
||||
vi.mock('@opentelemetry/exporter-trace-otlp-http');
|
||||
vi.mock('@opentelemetry/exporter-logs-otlp-http');
|
||||
vi.mock('@opentelemetry/exporter-metrics-otlp-http');
|
||||
vi.mock('@opentelemetry/sdk-node');
|
||||
|
||||
describe('Telemetry SDK', () => {
|
||||
let mockConfig: Config;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockConfig = {
|
||||
getTelemetryEnabled: () => true,
|
||||
getTelemetryOtlpEndpoint: () => 'http://localhost:4317',
|
||||
getTelemetryOtlpProtocol: () => 'grpc',
|
||||
getTelemetryOutfile: () => undefined,
|
||||
getDebugMode: () => false,
|
||||
getSessionId: () => 'test-session',
|
||||
} as unknown as Config;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await shutdownTelemetry(mockConfig);
|
||||
});
|
||||
|
||||
it('should use gRPC exporters when protocol is grpc', () => {
|
||||
initializeTelemetry(mockConfig);
|
||||
|
||||
expect(OTLPTraceExporter).toHaveBeenCalledWith({
|
||||
url: 'http://localhost:4317',
|
||||
compression: 'gzip',
|
||||
});
|
||||
expect(OTLPLogExporter).toHaveBeenCalledWith({
|
||||
url: 'http://localhost:4317',
|
||||
compression: 'gzip',
|
||||
});
|
||||
expect(OTLPMetricExporter).toHaveBeenCalledWith({
|
||||
url: 'http://localhost:4317',
|
||||
compression: 'gzip',
|
||||
});
|
||||
expect(NodeSDK.prototype.start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use HTTP exporters when protocol is http', () => {
|
||||
vi.spyOn(mockConfig, 'getTelemetryEnabled').mockReturnValue(true);
|
||||
vi.spyOn(mockConfig, 'getTelemetryOtlpProtocol').mockReturnValue('http');
|
||||
vi.spyOn(mockConfig, 'getTelemetryOtlpEndpoint').mockReturnValue(
|
||||
'http://localhost:4318',
|
||||
);
|
||||
|
||||
initializeTelemetry(mockConfig);
|
||||
|
||||
expect(OTLPTraceExporterHttp).toHaveBeenCalledWith({
|
||||
url: 'http://localhost:4318/',
|
||||
});
|
||||
expect(OTLPLogExporterHttp).toHaveBeenCalledWith({
|
||||
url: 'http://localhost:4318/',
|
||||
});
|
||||
expect(OTLPMetricExporterHttp).toHaveBeenCalledWith({
|
||||
url: 'http://localhost:4318/',
|
||||
});
|
||||
expect(NodeSDK.prototype.start).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should parse gRPC endpoint correctly', () => {
|
||||
vi.spyOn(mockConfig, 'getTelemetryOtlpEndpoint').mockReturnValue(
|
||||
'https://my-collector.com',
|
||||
);
|
||||
initializeTelemetry(mockConfig);
|
||||
expect(OTLPTraceExporter).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ url: 'https://my-collector.com' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse HTTP endpoint correctly', () => {
|
||||
vi.spyOn(mockConfig, 'getTelemetryOtlpProtocol').mockReturnValue('http');
|
||||
vi.spyOn(mockConfig, 'getTelemetryOtlpEndpoint').mockReturnValue(
|
||||
'https://my-collector.com',
|
||||
);
|
||||
initializeTelemetry(mockConfig);
|
||||
expect(OTLPTraceExporterHttp).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ url: 'https://my-collector.com/' }),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -8,6 +8,9 @@ import { DiagConsoleLogger, DiagLogLevel, diag } from '@opentelemetry/api';
|
|||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
|
||||
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
|
||||
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
|
||||
import { OTLPTraceExporter as OTLPTraceExporterHttp } from '@opentelemetry/exporter-trace-otlp-http';
|
||||
import { OTLPLogExporter as OTLPLogExporterHttp } from '@opentelemetry/exporter-logs-otlp-http';
|
||||
import { OTLPMetricExporter as OTLPMetricExporterHttp } from '@opentelemetry/exporter-metrics-otlp-http';
|
||||
import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base';
|
||||
import { NodeSDK } from '@opentelemetry/sdk-node';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
||||
|
@ -45,8 +48,9 @@ export function isTelemetrySdkInitialized(): boolean {
|
|||
return telemetryInitialized;
|
||||
}
|
||||
|
||||
function parseGrpcEndpoint(
|
||||
function parseOtlpEndpoint(
|
||||
otlpEndpointSetting: string | undefined,
|
||||
protocol: 'grpc' | 'http',
|
||||
): string | undefined {
|
||||
if (!otlpEndpointSetting) {
|
||||
return undefined;
|
||||
|
@ -56,9 +60,13 @@ function parseGrpcEndpoint(
|
|||
|
||||
try {
|
||||
const url = new URL(trimmedEndpoint);
|
||||
// OTLP gRPC exporters expect an endpoint in the format scheme://host:port
|
||||
// The `origin` property provides this, stripping any path, query, or hash.
|
||||
return url.origin;
|
||||
if (protocol === 'grpc') {
|
||||
// OTLP gRPC exporters expect an endpoint in the format scheme://host:port
|
||||
// The `origin` property provides this, stripping any path, query, or hash.
|
||||
return url.origin;
|
||||
}
|
||||
// For http, use the full href.
|
||||
return url.href;
|
||||
} catch (error) {
|
||||
diag.error('Invalid OTLP endpoint URL provided:', trimmedEndpoint, error);
|
||||
return undefined;
|
||||
|
@ -77,43 +85,70 @@ export function initializeTelemetry(config: Config): void {
|
|||
});
|
||||
|
||||
const otlpEndpoint = config.getTelemetryOtlpEndpoint();
|
||||
const grpcParsedEndpoint = parseGrpcEndpoint(otlpEndpoint);
|
||||
const useOtlp = !!grpcParsedEndpoint;
|
||||
const otlpProtocol = config.getTelemetryOtlpProtocol();
|
||||
const parsedEndpoint = parseOtlpEndpoint(otlpEndpoint, otlpProtocol);
|
||||
const useOtlp = !!parsedEndpoint;
|
||||
const telemetryOutfile = config.getTelemetryOutfile();
|
||||
|
||||
const spanExporter = useOtlp
|
||||
? new OTLPTraceExporter({
|
||||
url: grpcParsedEndpoint,
|
||||
let spanExporter:
|
||||
| OTLPTraceExporter
|
||||
| OTLPTraceExporterHttp
|
||||
| FileSpanExporter
|
||||
| ConsoleSpanExporter;
|
||||
let logExporter:
|
||||
| OTLPLogExporter
|
||||
| OTLPLogExporterHttp
|
||||
| FileLogExporter
|
||||
| ConsoleLogRecordExporter;
|
||||
let metricReader: PeriodicExportingMetricReader;
|
||||
|
||||
if (useOtlp) {
|
||||
if (otlpProtocol === 'http') {
|
||||
spanExporter = new OTLPTraceExporterHttp({
|
||||
url: parsedEndpoint,
|
||||
});
|
||||
logExporter = new OTLPLogExporterHttp({
|
||||
url: parsedEndpoint,
|
||||
});
|
||||
metricReader = new PeriodicExportingMetricReader({
|
||||
exporter: new OTLPMetricExporterHttp({
|
||||
url: parsedEndpoint,
|
||||
}),
|
||||
exportIntervalMillis: 10000,
|
||||
});
|
||||
} else {
|
||||
// grpc
|
||||
spanExporter = new OTLPTraceExporter({
|
||||
url: parsedEndpoint,
|
||||
compression: CompressionAlgorithm.GZIP,
|
||||
})
|
||||
: telemetryOutfile
|
||||
? new FileSpanExporter(telemetryOutfile)
|
||||
: new ConsoleSpanExporter();
|
||||
const logExporter = useOtlp
|
||||
? new OTLPLogExporter({
|
||||
url: grpcParsedEndpoint,
|
||||
});
|
||||
logExporter = new OTLPLogExporter({
|
||||
url: parsedEndpoint,
|
||||
compression: CompressionAlgorithm.GZIP,
|
||||
})
|
||||
: telemetryOutfile
|
||||
? new FileLogExporter(telemetryOutfile)
|
||||
: new ConsoleLogRecordExporter();
|
||||
const metricReader = useOtlp
|
||||
? new PeriodicExportingMetricReader({
|
||||
});
|
||||
metricReader = new PeriodicExportingMetricReader({
|
||||
exporter: new OTLPMetricExporter({
|
||||
url: grpcParsedEndpoint,
|
||||
url: parsedEndpoint,
|
||||
compression: CompressionAlgorithm.GZIP,
|
||||
}),
|
||||
exportIntervalMillis: 10000,
|
||||
})
|
||||
: telemetryOutfile
|
||||
? new PeriodicExportingMetricReader({
|
||||
exporter: new FileMetricExporter(telemetryOutfile),
|
||||
exportIntervalMillis: 10000,
|
||||
})
|
||||
: new PeriodicExportingMetricReader({
|
||||
exporter: new ConsoleMetricExporter(),
|
||||
exportIntervalMillis: 10000,
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if (telemetryOutfile) {
|
||||
spanExporter = new FileSpanExporter(telemetryOutfile);
|
||||
logExporter = new FileLogExporter(telemetryOutfile);
|
||||
metricReader = new PeriodicExportingMetricReader({
|
||||
exporter: new FileMetricExporter(telemetryOutfile),
|
||||
exportIntervalMillis: 10000,
|
||||
});
|
||||
} else {
|
||||
spanExporter = new ConsoleSpanExporter();
|
||||
logExporter = new ConsoleLogRecordExporter();
|
||||
metricReader = new PeriodicExportingMetricReader({
|
||||
exporter: new ConsoleMetricExporter(),
|
||||
exportIntervalMillis: 10000,
|
||||
});
|
||||
}
|
||||
|
||||
sdk = new NodeSDK({
|
||||
resource,
|
||||
|
|
Loading…
Reference in New Issue