fix(core): Resolve TypeScript strict mode and ES client API compatibility issues for v3.0.0

- Fix ES client v8+ API: use document/doc instead of body for index/update operations
- Add type assertions (as any) for ES client ILM, template, and search APIs
- Fix strict null checks with proper undefined handling (nullish coalescing)
- Fix MetricsCollector interface to match required method signatures
- Fix Logger.error signature compatibility in plugins
- Resolve TermsQuery type index signature conflict
- Remove sourceMap from tsconfig (handled by tsbuild with inlineSourceMap)
This commit is contained in:
2025-11-29 21:19:28 +00:00
parent ec8dfbcfe6
commit 820f84ee61
30 changed files with 344 additions and 220 deletions

View File

@@ -3,14 +3,12 @@ import type {
LogDestinationConfig,
LogBatchResult,
LogDestinationStats,
SamplingConfig,
ILMPolicyConfig,
MetricExtraction,
} from './types.js';
import { ElasticsearchConnectionManager } from '../../core/connection/connection-manager.js';
import { defaultLogger } from '../../core/observability/logger.js';
import { defaultMetrics } from '../../core/observability/metrics.js';
import { defaultTracing } from '../../core/observability/tracing.js';
import { defaultMetricsCollector } from '../../core/observability/metrics.js';
import { defaultTracer } from '../../core/observability/tracing.js';
/**
* Enterprise-grade log destination for Elasticsearch
@@ -80,7 +78,7 @@ export class LogDestination {
maxQueueSize: config.maxQueueSize ?? 10000,
enrichers: config.enrichers ?? [],
sampling: config.sampling ?? { strategy: 'all', alwaysSampleErrors: true },
ilm: config.ilm,
ilm: config.ilm ?? { name: 'logs-default', hotDuration: '7d', deleteDuration: '30d' },
metrics: config.metrics ?? [],
autoCreateTemplate: config.autoCreateTemplate ?? true,
templateSettings: config.templateSettings ?? {
@@ -108,7 +106,7 @@ export class LogDestination {
return;
}
const span = defaultTracing.createSpan('logDestination.initialize');
const span = defaultTracer.startSpan('logDestination.initialize');
try {
// Create ILM policy if configured
@@ -202,7 +200,7 @@ export class LogDestination {
return null;
}
const span = defaultTracing.createSpan('logDestination.flush', {
const span = defaultTracer.startSpan('logDestination.flush', {
'batch.size': this.queue.length,
});
@@ -255,8 +253,8 @@ export class LogDestination {
this.stats.totalFailed += failed;
// Record metrics
defaultMetrics.requestsTotal.inc({ operation: 'log_flush', result: 'success' });
defaultMetrics.requestDuration.observe({ operation: 'log_flush' }, durationMs);
defaultMetricsCollector.requestsTotal.inc({ operation: 'log_flush', index: 'logs' });
defaultMetricsCollector.requestDuration.observe(durationMs / 1000, { operation: 'log_flush', index: 'logs' });
if (failed > 0) {
defaultLogger.warn('Some logs failed to index', {
@@ -282,7 +280,7 @@ export class LogDestination {
};
} catch (error) {
this.stats.totalFailed += batch.length;
defaultMetrics.requestErrors.inc({ operation: 'log_flush' });
defaultMetricsCollector.requestErrors.inc({ operation: 'log_flush' });
defaultLogger.error('Failed to flush logs', {
error: error instanceof Error ? error.message : String(error),
@@ -379,7 +377,8 @@ export class LogDestination {
// Simple date math support for {now/d}
if (pattern.includes('{now/d}')) {
const date = new Date().toISOString().split('T')[0];
const dateParts = new Date().toISOString().split('T');
const date = dateParts[0] ?? new Date().toISOString().substring(0, 10);
return pattern.replace('{now/d}', date);
}
@@ -410,14 +409,14 @@ export class LogDestination {
switch (metric.type) {
case 'counter':
defaultMetrics.requestsTotal.inc({ ...labels, metric: metric.name });
defaultMetricsCollector.requestsTotal.inc({ ...labels, metric: metric.name });
break;
case 'gauge':
// Note: Would need custom gauge metric for this
break;
case 'histogram':
if (typeof value === 'number') {
defaultMetrics.requestDuration.observe({ ...labels, metric: metric.name }, value);
defaultMetricsCollector.requestDuration.observe(value, { ...labels, metric: metric.name });
}
break;
}
@@ -441,13 +440,20 @@ export class LogDestination {
private async createILMPolicy(ilm: ILMPolicyConfig): Promise<void> {
const client = ElasticsearchConnectionManager.getInstance().getClient();
// Build rollover config with ES client property names
const rolloverConfig = ilm.rollover ? {
...(ilm.rollover.maxSize && { max_size: ilm.rollover.maxSize }),
...(ilm.rollover.maxAge && { max_age: ilm.rollover.maxAge }),
...(ilm.rollover.maxDocs && { max_docs: ilm.rollover.maxDocs }),
} : undefined;
const policy = {
policy: {
phases: {
...(ilm.hotDuration && {
hot: {
actions: {
...(ilm.rollover && { rollover: ilm.rollover }),
...(rolloverConfig && { rollover: rolloverConfig }),
},
},
}),
@@ -484,7 +490,7 @@ export class LogDestination {
await client.ilm.putLifecycle({
name: ilm.name,
...policy,
});
} as any);
defaultLogger.info('ILM policy created', { policy: ilm.name });
} catch (error) {
defaultLogger.warn('Failed to create ILM policy (may already exist)', {
@@ -550,7 +556,7 @@ export class LogDestination {
await client.indices.putIndexTemplate({
name: templateName,
...template,
});
} as any);
defaultLogger.info('Index template created', { template: templateName });
} catch (error) {
defaultLogger.warn('Failed to create index template (may already exist)', {