IMetricsCollector
Interface for collecting metrics during migration execution.
Table of Contents
- Overview
- Interface Definition
- Methods
- Usage
- Built-in Implementations
- Custom Implementation
- Best Practices
Overview
IMetricsCollector defines the contract for metrics collection implementations. Collectors receive lifecycle events during migration execution and can send metrics to various destinations (console, files, monitoring services, etc.).
Added in: v0.6.0
Use cases:
- Track migration performance
- Monitor execution times in production
- Debug slow migrations
- Send metrics to APM tools (Datadog, CloudWatch, Prometheus)
- Create audit trails
Interface Definition
interface IMetricsCollector {
recordMigrationStart?(context: IMigrationContext): void | Promise<void>;
recordMigrationComplete?(result: IMigrationResult, duration: number): void | Promise<void>;
recordScriptStart?(script: MigrationScript): void | Promise<void>;
recordScriptComplete?(script: MigrationScript, duration: number): void | Promise<void>;
recordScriptError?(script: MigrationScript, error: Error): void | Promise<void>;
recordRollback?(strategy: RollbackStrategy, success: boolean, duration?: number): void | Promise<void>;
recordValidationErrors?(errors: ValidationError[]): void | Promise<void>;
recordBackup?(backupPath: string, duration: number): void | Promise<void>;
recordError?(error: Error): void | Promise<void>;
close?(): void | Promise<void>;
}
All methods are optional - implement only what you need.
Methods
recordMigrationStart
Called when migration process begins.
recordMigrationStart?(context: IMigrationContext): void | Promise<void>
Parameters:
context: IMigrationContext- Migration context with pending and executed counts
Example:
recordMigrationStart(context: IMigrationContext): void {
console.log(`[METRICS] Migration started - ${context.pending} pending scripts`);
}
recordMigrationComplete
Called when migration process completes (success or failure).
recordMigrationComplete?(result: IMigrationResult, duration: number): void | Promise<void>
Parameters:
result: IMigrationResult- Migration result with success status and executed scriptsduration: number- Total execution time in milliseconds
Example:
recordMigrationComplete(result: IMigrationResult, duration: number): void {
if (result.success) {
console.log(`[METRICS] Migration completed - ${result.executed.length} scripts in ${duration}ms`);
} else {
console.error(`[METRICS] Migration failed after ${duration}ms`);
}
}
recordScriptStart
Called when individual migration script starts executing.
recordScriptStart?(script: MigrationScript): void | Promise<void>
Parameters:
script: MigrationScript- Migration script being executed
Example:
recordScriptStart(script: MigrationScript): void {
console.log(`[METRICS] ${script.name} started`);
}
recordScriptComplete
Called when individual migration script completes successfully.
recordScriptComplete?(script: MigrationScript, duration: number): void | Promise<void>
Parameters:
script: MigrationScript- Migration script that completedduration: number- Execution time in milliseconds
Example:
recordScriptComplete(script: MigrationScript, duration: number): void {
console.log(`[METRICS] ${script.name} completed in ${duration}ms`);
}
recordScriptError
Called when individual migration script fails.
recordScriptError?(script: MigrationScript, error: Error): void | Promise<void>
Parameters:
script: MigrationScript- Migration script that failederror: Error- Error that caused the failure
Example:
recordScriptError(script: MigrationScript, error: Error): void {
console.error(`[METRICS] ${script.name} failed: ${error.message}`);
}
recordRollback
Called when rollback is attempted.
recordRollback?(strategy: RollbackStrategy, success: boolean, duration?: number): void | Promise<void>
Parameters:
strategy: RollbackStrategy- Rollback strategy used (BACKUP, DOWN, BOTH, NONE)success: boolean- Whether rollback succeededduration?: number- Optional rollback duration in milliseconds
Example:
recordRollback(strategy: RollbackStrategy, success: boolean, duration?: number): void {
const status = success ? 'succeeded' : 'failed';
console.log(`[METRICS] Rollback (${strategy}) ${status}${duration ? ` in ${duration}ms` : ''}`);
}
recordValidationErrors
Called when validation errors are found before migration execution.
recordValidationErrors?(errors: ValidationError[]): void | Promise<void>
Parameters:
errors: ValidationError[]- Array of validation errors
Example:
recordValidationErrors(errors: ValidationError[]): void {
console.warn(`[METRICS] Validation errors: ${errors.length} issues found`);
errors.forEach(err => console.warn(`[METRICS] - ${err.message}`));
}
recordBackup
Called when database backup is created.
recordBackup?(backupPath: string, duration: number): void | Promise<void>
Parameters:
backupPath: string- Path or identifier of created backupduration: number- Backup creation time in milliseconds
Example:
recordBackup(backupPath: string, duration: number): void {
console.log(`[METRICS] Backup created in ${duration}ms: ${backupPath}`);
}
recordError
Called when general error occurs (not migration script specific).
recordError?(error: Error): void | Promise<void>
Parameters:
error: Error- Error that occurred
Example:
recordError(error: Error): void {
console.error(`[METRICS] Error: ${error.message}`);
}
close
Called when metrics collector should clean up resources (e.g., close file handles, flush buffers).
close?(): void | Promise<void>
Example:
async close(): Promise<void> {
await this.fileHandle.close();
console.log('[METRICS] Collector closed');
}
Usage
Basic Implementation
import { IMetricsCollector, MigrationScript, IMigrationResult } from '@migration-script-runner/core';
class SimpleMetricsCollector implements IMetricsCollector {
recordScriptComplete(script: MigrationScript, duration: number): void {
console.log(`✓ ${script.name} completed in ${duration}ms`);
}
recordScriptError(script: MigrationScript, error: Error): void {
console.error(`✗ ${script.name} failed: ${error.message}`);
}
}
With Dependency Injection
import { MigrationScriptExecutor } from '@migration-script-runner/core';
const executor = new MigrationScriptExecutor({
handler,
metricsCollectors: [
new SimpleMetricsCollector()
]
}, config);
await executor.up();
Multiple Collectors
const executor = new MigrationScriptExecutor({
handler,
metricsCollectors: [
new ConsoleMetricsCollector(), // Real-time feedback
new JsonMetricsCollector({ // Detailed analysis
filePath: './metrics/migration.json'
}),
new DatadogCollector({ // Production monitoring
apiKey: process.env.DD_API_KEY
})
]
}, config);
Built-in Implementations
MSR includes four production-ready collectors:
ConsoleMetricsCollector
Zero-config console output for development.
import { ConsoleMetricsCollector } from '@migration-script-runner/core';
new ConsoleMetricsCollector()
View ConsoleMetricsCollector docs →
LoggerMetricsCollector
Send metrics through any ILogger implementation.
import { LoggerMetricsCollector, FileLogger } from '@migration-script-runner/core';
new LoggerMetricsCollector({
logger: new FileLogger('./logs/metrics.log')
})
View LoggerMetricsCollector docs →
JsonMetricsCollector
Write detailed JSON metrics for analysis.
import { JsonMetricsCollector } from '@migration-script-runner/core';
new JsonMetricsCollector({
filePath: './metrics/migration.json',
pretty: true
})
View JsonMetricsCollector docs →
CsvMetricsCollector
CSV format for Excel and data analysis.
import { CsvMetricsCollector } from '@migration-script-runner/core';
new CsvMetricsCollector({
filePath: './metrics/migrations.csv'
})
View CsvMetricsCollector docs →
Custom Implementation
Example: Datadog Collector
import { IMetricsCollector, MigrationScript, IMigrationResult } from '@migration-script-runner/core';
import StatsD from 'hot-shots';
export class DatadogCollector implements IMetricsCollector {
private client: StatsD;
constructor(config: { apiKey: string; host?: string; prefix?: string }) {
this.client = new StatsD({
host: config.host || 'localhost',
port: 8125,
prefix: config.prefix || 'msr.',
globalTags: {
env: process.env.NODE_ENV || 'production'
}
});
}
recordScriptComplete(script: MigrationScript, duration: number): void {
this.client.increment('migrations.success', 1, { script: script.name });
this.client.timing('migrations.duration', duration, { script: script.name });
}
recordScriptError(script: MigrationScript, error: Error): void {
this.client.increment('migrations.failed', 1, {
script: script.name,
error: error.constructor.name
});
}
async close(): Promise<void> {
this.client.close();
}
}
View more custom collector examples →
Best Practices
1. Implement Only What You Need
All methods are optional - implement only the metrics relevant to your use case:
// Minimal implementation - only track failures
class ErrorOnlyCollector implements IMetricsCollector {
recordScriptError(script: MigrationScript, error: Error): void {
// Send alert
}
}
2. Handle Errors Gracefully
Metrics collection failures should never stop migrations:
recordScriptComplete(script: MigrationScript, duration: number): void {
try {
this.sendMetric(script, duration);
} catch (error) {
console.error('Metrics error:', error);
// Don't throw - continue with migration
}
}
3. Use Async When Needed
Return Promise<void> for async operations:
async recordScriptComplete(script: MigrationScript, duration: number): Promise<void> {
await this.apiClient.send({
metric: 'migration.duration',
value: duration
});
}
4. Clean Up Resources
Implement close() to flush buffers and close connections:
async close(): Promise<void> {
await this.flush();
await this.fileHandle.close();
}