Files
memecoin-botV2/src/metrics/index.ts
2026-08-16 19:44:30 +00:00

202 lines
7.3 KiB
TypeScript

import { InfluxDB, Point, WriteApi } from '@influxdata/influxdb-client';
import { IMetricsProvider } from '../domain/interfaces.js';
import { logger } from '../logging/index.js';
export class InfluxMetricsProvider implements IMetricsProvider {
private writeApi: WriteApi | null = null;
private influx: InfluxDB | null = null;
constructor(url: string, token: string, org: string, bucket: string) {
try {
this.influx = new InfluxDB({ url, token });
this.writeApi = this.influx.getWriteApi(org, bucket, 'ms', {
writeFailed(error) {
logger.error('InfluxDB metrics point write failed', error);
},
});
logger.info('InfluxDB metrics provider initialized successfully');
} catch (error) {
logger.error(
'Failed to initialize InfluxDB metrics provider. System will run with degraded/no time-series metrics reporting.',
error,
);
}
}
private writePoint(point: Point): void {
if (!this.writeApi) {
logger.debug('InfluxDB write client not initialized, discarding point', {
measurement: point.toLineProtocol(),
});
return;
}
try {
this.writeApi.writePoint(point);
} catch (error) {
logger.error('Error writing point to InfluxDB', error);
}
}
recordWalletDetectionLatency(latencyMs: number, wallet: string): void {
const p = new Point('wallet_detection_latency')
.tag('wallet', wallet)
.floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordSignalProcessingLatency(latencyMs: number): void {
const p = new Point('signal_processing_latency').floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordQuoteLatency(latencyMs: number, provider: string): void {
const p = new Point('quote_latency').tag('provider', provider).floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordExecutionLatency(latencyMs: number, scenario: number): void {
const p = new Point('execution_latency')
.tag('scenario', `${scenario}ms`)
.floatField('latency_ms', latencyMs);
this.writePoint(p);
}
recordPrice(tokenMint: string, priceSol: number): void {
const p = new Point('token_price').tag('token_mint', tokenMint).floatField('price_sol', priceSol);
this.writePoint(p);
}
recordPortfolioBalance(balanceSol: number, scenario: number): void {
const p = new Point('portfolio_balance')
.tag('scenario', `${scenario}ms`)
.floatField('balance_sol', balanceSol);
this.writePoint(p);
}
recordTradePnl(pnlSol: number, scenario: number, tokenMint: string): void {
const p = new Point('trade_pnl')
.tag('scenario', `${scenario}ms`)
.tag('token_mint', tokenMint)
.floatField('pnl_sol', pnlSol);
this.writePoint(p);
}
recordExcursion(mfeSol: number, maeSol: number, scenario: number, tokenMint: string): void {
const p = new Point('trade_excursion')
.tag('scenario', `${scenario}ms`)
.tag('token_mint', tokenMint)
.floatField('mfe_sol', mfeSol)
.floatField('mae_sol', maeSol);
this.writePoint(p);
}
recordQueueDepth(depth: number): void {
const p = new Point('queue_depth').intField('depth', depth);
this.writePoint(p);
}
recordQueueRetries(retries: number, signature: string): void {
const p = new Point('queue_retries').tag('signature', signature).intField('retries', retries);
this.writePoint(p);
}
recordQueue429s(signature: string): void {
const p = new Point('queue_429s').tag('signature', signature).intField('count', 1);
this.writePoint(p);
}
recordWalletEventReceived(wallet: string): void {
const p = new Point('wallet_event_received').tag('wallet', wallet).intField('count', 1);
this.writePoint(p);
}
recordWalletQueueDepth(wallet: string, depth: number): void {
const p = new Point('wallet_queue_depth').tag('wallet', wallet).intField('depth', depth);
this.writePoint(p);
}
recordOldestQueuedAge(wallet: string, ageMs: number): void {
const p = new Point('oldest_queued_age').tag('wallet', wallet).floatField('age_ms', ageMs);
this.writePoint(p);
}
recordDroppedOldestCount(wallet: string): void {
const p = new Point('dropped_oldest_count').tag('wallet', wallet).intField('count', 1);
this.writePoint(p);
}
recordTransactionRelevance(relevant: boolean): void {
const p = new Point('transaction_relevance').tag('relevant', String(relevant)).intField('count', 1);
this.writePoint(p);
}
recordRpcRequestRate(requestsPerSecond: number): void {
const p = new Point('rpc_request_rate').floatField('req_per_sec', requestsPerSecond);
this.writePoint(p);
}
recordQueueProcessed(wallet: string): void {
const p = new Point('queue_processed').tag('wallet', wallet).intField('count', 1);
this.writePoint(p);
}
recordRpcFetchError(wallet: string): void {
const p = new Point('rpc_fetch_error').tag('wallet', wallet).intField('count', 1);
this.writePoint(p);
}
recordWalletState(wallet: string, isHot: boolean): void {
const p = new Point('wallet_state').tag('wallet', wallet).intField('is_hot', isHot ? 1 : 0);
this.writePoint(p);
}
recordWalletIncomingRate(wallet: string, rate: number): void {
const p = new Point('wallet_incoming_rate').tag('wallet', wallet).floatField('rate', rate);
this.writePoint(p);
}
recordWalletProcessedRate(wallet: string, rate: number): void {
const p = new Point('wallet_processed_rate').tag('wallet', wallet).floatField('rate', rate);
this.writePoint(p);
}
async close(): Promise<void> {
if (this.writeApi) {
logger.info('Closing InfluxDB metrics writer...');
try {
await this.writeApi.close();
logger.info('InfluxDB metrics writer closed.');
} catch (error) {
logger.error('Error closing InfluxDB metrics writer', error);
}
}
}
}
// In-Memory/Mock Metrics Provider for local tests and offline dev
export class MockMetricsProvider implements IMetricsProvider {
recordWalletDetectionLatency(_latencyMs: number, _wallet: string): void {}
recordSignalProcessingLatency(_latencyMs: number): void {}
recordQuoteLatency(_latencyMs: number, _provider: string): void {}
recordExecutionLatency(_latencyMs: number, _scenario: number): void {}
recordPrice(_tokenMint: string, _priceSol: number): void {}
recordPortfolioBalance(_balanceSol: number, _scenario: number): void {}
recordTradePnl(_pnlSol: number, _scenario: number, _tokenMint: string): void {}
recordExcursion(_mfeSol: number, _maeSol: number, _scenario: number, _tokenMint: string): void {}
recordQueueDepth(_depth: number): void {}
recordQueueRetries(_retries: number, _signature: string): void {}
recordQueue429s(_signature: string): void {}
recordWalletEventReceived(_wallet: string): void {}
recordWalletQueueDepth(_wallet: string, _depth: number): void {}
recordOldestQueuedAge(_wallet: string, _ageMs: number): void {}
recordDroppedOldestCount(_wallet: string): void {}
recordTransactionRelevance(_relevant: boolean): void {}
recordRpcRequestRate(_requestsPerSecond: number): void {}
recordQueueProcessed(_wallet: string): void {}
recordRpcFetchError(_wallet: string): void {}
recordWalletState(_wallet: string, _isHot: boolean): void {}
recordWalletIncomingRate(_wallet: string, _rate: number): void {}
recordWalletProcessedRate(_wallet: string, _rate: number): void {}
}