network-performance-analyzer
Version:
Automated analysis tool for network performance test datasets containing DNS testing results and iperf3 performance measurements
859 lines (845 loc) • 42.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NetworkPerformanceAnalyzer = void 0;
exports.createNetworkPerformanceAnalyzer = createNetworkPerformanceAnalyzer;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const DatasetDiscoveryService_1 = require("./DatasetDiscoveryService");
const DataParser_1 = require("./DataParser");
const AnalysisEngine_1 = require("./AnalysisEngine");
const ReportGenerator_1 = require("./ReportGenerator");
const ErrorHandler_1 = require("../utils/ErrorHandler");
const ConfigurationManager_1 = require("../config/ConfigurationManager");
const PluginManager_1 = require("../plugins/PluginManager");
const ReportTemplateManager_1 = require("./ReportTemplateManager");
/**
* Main orchestrator class for the Network Performance Analyzer
* Coordinates the end-to-end workflow from dataset discovery to report generation
*/
const PerformanceMonitor_1 = require("../utils/PerformanceMonitor");
class NetworkPerformanceAnalyzer {
/**
* Create a new NetworkPerformanceAnalyzer instance
* @param discoveryService Service for discovering datasets
* @param dataParser Service for parsing dataset files
* @param analysisEngine Service for analyzing performance data
* @param reportGenerator Service for generating reports
* @param errorHandler Service for handling errors
* @param config Configuration options for the analyzer
*/
constructor(discoveryService, dataParser, analysisEngine, reportGenerator, errorHandler, config = {}) {
this.performanceMonitor = null;
this.discoveryService = discoveryService;
this.dataParser = dataParser;
this.analysisEngine = analysisEngine;
this.reportGenerator = reportGenerator;
this.errorHandler = errorHandler;
// Set default configuration values
this.config = {
continueOnError: config.continueOnError !== undefined ? config.continueOnError : true,
logProgress: config.logProgress !== undefined ? config.logProgress : true,
reportOutputPath: config.reportOutputPath,
anomalyThresholds: config.anomalyThresholds
? { ...config.anomalyThresholds }
: {},
useParallelProcessing: config.useParallelProcessing !== undefined
? config.useParallelProcessing
: true,
maxParallelTasks: config.maxParallelTasks || 4,
enablePerformanceMonitoring: config.enablePerformanceMonitoring !== undefined
? config.enablePerformanceMonitoring
: false,
memoryThresholdPercent: config.memoryThresholdPercent || 80,
configPath: config.configPath,
environment: config.environment || "development",
pluginDirectories: config.pluginDirectories || [],
reportTemplateId: config.reportTemplateId || "default",
includeSections: config.includeSections || [],
};
// Initialize performance monitoring if enabled
if (this.config.enablePerformanceMonitoring) {
this.initializePerformanceMonitoring();
}
}
/**
* Initialize performance monitoring
*/
initializePerformanceMonitoring() {
this.performanceMonitor = new PerformanceMonitor_1.PerformanceMonitor({
monitoringInterval: 5000,
memoryThresholdPercent: this.config.memoryThresholdPercent || 80,
...(this.config.logProgress !== undefined
? { logToConsole: this.config.logProgress }
: {}),
});
// Set up event listeners
this.performanceMonitor.on("memory-threshold-exceeded", (data) => {
this.logProgress(`Memory threshold exceeded: ${data.current.toFixed(1)}% > ${data.threshold}%`);
});
// Start monitoring
this.performanceMonitor.start();
}
/**
* Run the complete analysis workflow
* @param rootPath Path to the directory containing dataset directories
* @returns A promise that resolves to the generated report
*/
async analyze(rootPath) {
try {
this.logProgress(`Starting analysis of datasets in ${rootPath}`);
// Step 1: Discover datasets
this.logProgress("Discovering datasets...");
const datasets = await this.discoverDatasets(rootPath);
if (datasets.length === 0) {
const error = new Error(`No valid datasets found in ${rootPath}`);
this.errorHandler.logError(error, "Dataset discovery failed");
if (this.config.continueOnError) {
this.logProgress("Continuing with empty dataset list due to continueOnError=true");
return this.generateEmptyReport();
}
throw error;
}
this.logProgress(`Found ${datasets.length} datasets for analysis`);
// Step 2: Load and parse dataset files
this.logProgress("Loading and parsing dataset files...");
const parsedDatasets = await this.parseDatasetFiles(datasets);
if (parsedDatasets.length === 0) {
const error = new Error("No datasets could be successfully parsed");
this.errorHandler.logError(error, "Dataset parsing failed");
if (this.config.continueOnError) {
this.logProgress("Continuing with empty dataset list due to continueOnError=true");
return this.generateEmptyReport();
}
throw error;
}
this.logProgress(`Successfully parsed ${parsedDatasets.length} datasets`);
// Step 3: Perform analysis
this.logProgress("Performing analysis...");
const analysisResults = await this.performAnalysis(parsedDatasets);
// Step 4: Generate report
this.logProgress("Generating report...");
const report = await this.reportGenerator.generateReport(analysisResults);
// Step 5: Save report if output path is provided
if (this.config.reportOutputPath) {
await this.saveReport(report, this.config.reportOutputPath);
this.logProgress(`Report saved to ${this.config.reportOutputPath}`);
}
this.logProgress("Analysis completed successfully");
return report;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
this.errorHandler.logError(error instanceof Error ? error : new Error(errorMessage), "Error during analysis workflow");
// If configured to continue on error, return an error report
if (this.config.continueOnError) {
this.logProgress("Generating error report due to continueOnError=true");
return this.generateErrorReport(errorMessage);
}
throw error;
}
}
/**
* Generate a report for when no datasets are available
* @returns A simple markdown report indicating no datasets were found
* @private
*/
generateEmptyReport() {
return `# Network Performance Analysis Report
## Error: No Valid Datasets
No valid datasets were found or could be successfully parsed. Please check the following:
1. Ensure the dataset directories follow the naming pattern: \`(coredns|stock)-mtu\\d+-aws-logs_(enabled|disabled)\`
2. Verify that each dataset directory contains either:
- A parameters file named \`parameters-results_*.json\`
- A results file named \`results_*.json\`
3. Check the error log for specific parsing or validation errors
## Troubleshooting
- Verify file permissions and accessibility
- Ensure JSON files are properly formatted
- Check for missing required fields in the dataset files
- Review the application logs for detailed error information
*Report generated on ${new Date().toISOString()}*
`;
}
/**
* Generate a report for when an error occurs during analysis
* @param errorMessage The error message to include in the report
* @returns A simple markdown report with the error information
* @private
*/
generateErrorReport(errorMessage) {
return `# Network Performance Analysis Report
## Error During Analysis
An error occurred during the analysis process:
\`\`\`
${errorMessage}
\`\`\`
### Partial Results
The analysis could not be completed successfully. Any partial results may be incomplete or inaccurate.
## Troubleshooting
- Check the error log for detailed information about the failure
- Verify that all dataset files contain valid and complete data
- Ensure sufficient system resources are available for analysis
- Try running the analysis with a smaller subset of datasets
*Report generated on ${new Date().toISOString()}*
`;
}
/**
* Discover datasets in the given root path
* @param rootPath Path to the directory containing dataset directories
* @returns A promise that resolves to an array of discovered datasets
* @private
*/
async discoverDatasets(rootPath) {
try {
// Use the discovery service to find datasets
const datasets = await this.discoveryService.discoverDatasets(rootPath);
// Log information about each dataset
datasets.forEach((dataset) => {
this.logProgress(`Found dataset: ${dataset.name} (MTU: ${dataset.configuration.mtu}, AWS Logging: ${dataset.configuration.awsLogging ? "enabled" : "disabled"})`);
});
return datasets;
}
catch (error) {
this.errorHandler.logError(error, "Error discovering datasets");
// If configured to continue on error, return empty array
if (this.config.continueOnError) {
return [];
}
throw error;
}
}
/**
* Parse dataset files for all discovered datasets
* @param datasets The datasets to parse files for
* @returns A promise that resolves to an array of datasets with parsed results
* @private
*/
async parseDatasetFiles(datasets) {
// Start performance monitoring for this operation
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("parseDatasetFiles");
}
try {
const parsedDatasets = [];
// Use parallel processing if enabled
if (this.config.useParallelProcessing && datasets.length > 1) {
this.logProgress(`Using parallel processing for ${datasets.length} datasets (max ${this.config.maxParallelTasks} concurrent tasks)`);
// Process datasets in batches to limit concurrency
const batches = [];
const batchSize = Math.min(this.config.maxParallelTasks || 4, datasets.length);
// Create batches of datasets
for (let i = 0; i < datasets.length; i += batchSize) {
batches.push(datasets.slice(i, i + batchSize));
}
// Process each batch in parallel
for (const batch of batches) {
// Create parsing promises for all datasets in the batch
const parsingPromises = batch.map(async (dataset) => {
try {
this.logProgress(`Parsing dataset: ${dataset.name}`);
// Parse parameters file if it exists
let parameters = null;
if (dataset.parametersFile &&
(await fs_extra_1.default.pathExists(dataset.parametersFile))) {
this.logProgress(`Parsing parameters file: ${path_1.default.basename(dataset.parametersFile)}`);
parameters = await this.dataParser.parseParameters(dataset.parametersFile);
}
// Parse results file if it exists
let results = null;
if (dataset.resultsFile &&
(await fs_extra_1.default.pathExists(dataset.resultsFile))) {
this.logProgress(`Parsing results file: ${path_1.default.basename(dataset.resultsFile)}`);
results = await this.dataParser.parseResults(dataset.resultsFile);
}
// Add parsed data to dataset
const parsedDataset = {
...dataset,
parameters,
results,
};
// Only return datasets with results
if (parsedDataset.results) {
this.logProgress(`Successfully parsed dataset: ${dataset.name}`);
return parsedDataset;
}
else {
this.logProgress(`Skipping dataset ${dataset.name} - no results found`);
return null;
}
}
catch (error) {
this.errorHandler.logError(error, `Error parsing dataset: ${dataset.name}`);
// If configured to continue on error, return null
if (this.config.continueOnError) {
return null;
}
throw error;
}
});
// Wait for all parsing promises in this batch to complete
const batchResults = await Promise.all(parsingPromises);
// Add successful results to the parsed datasets array
parsedDatasets.push(...batchResults.filter((result) => result !== null));
}
}
else {
// Use sequential processing for a single dataset or if parallel processing is disabled
for (const dataset of datasets) {
try {
this.logProgress(`Parsing dataset: ${dataset.name}`);
// Parse parameters file if it exists
let parameters = null;
if (dataset.parametersFile &&
(await fs_extra_1.default.pathExists(dataset.parametersFile))) {
this.logProgress(`Parsing parameters file: ${path_1.default.basename(dataset.parametersFile)}`);
parameters = await this.dataParser.parseParameters(dataset.parametersFile);
}
// Parse results file if it exists
let results = null;
if (dataset.resultsFile &&
(await fs_extra_1.default.pathExists(dataset.resultsFile))) {
this.logProgress(`Parsing results file: ${path_1.default.basename(dataset.resultsFile)}`);
results = await this.dataParser.parseResults(dataset.resultsFile);
}
// Add parsed data to dataset
const parsedDataset = {
...dataset,
parameters,
results,
};
// Only add datasets with results
if (parsedDataset.results) {
parsedDatasets.push(parsedDataset);
this.logProgress(`Successfully parsed dataset: ${dataset.name}`);
}
else {
this.logProgress(`Skipping dataset ${dataset.name} - no results found`);
}
}
catch (error) {
this.errorHandler.logError(error, `Error parsing dataset: ${dataset.name}`);
// If configured to continue on error, skip this dataset
if (!this.config.continueOnError) {
throw error;
}
}
}
}
return parsedDatasets;
}
finally {
// End performance monitoring for this operation
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("parseDatasetFiles");
if (duration) {
this.logProgress(`Dataset parsing completed in ${duration.toFixed(2)}ms`);
}
}
}
}
/**
* Perform analysis on the parsed datasets
* @param datasets The datasets to analyze
* @returns A promise that resolves to the analysis results
* @private
*/
async performAnalysis(datasets) {
// Execute analyzer plugins if available
let pluginResults = [];
if (this.pluginManager) {
try {
pluginResults = await this.pluginManager.executePlugins("analyzer", {
datasets,
});
}
catch (error) {
console.error("Error executing analyzer plugins:", error);
}
}
// Start performance monitoring for this operation
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("performAnalysis");
}
try {
let iperfAnalysis, dnsAnalysis, configurationComparison, anomalies;
// Use parallel processing if enabled
if (this.config.useParallelProcessing) {
this.logProgress("Using parallel processing for analysis tasks");
// Run analysis tasks in parallel
[iperfAnalysis, dnsAnalysis, configurationComparison, anomalies] =
await Promise.all([
// Task 1: Analyze iperf performance
(async () => {
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("analyzeIperfPerformance");
}
this.logProgress("Analyzing iperf performance...");
try {
const result = await this.analysisEngine.analyzeIperfPerformance(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("analyzeIperfPerformance");
if (duration) {
this.logProgress(`Iperf analysis completed in ${duration.toFixed(2)}ms`);
}
}
return result;
}
catch (error) {
this.errorHandler.logError(error, "Error analyzing iperf performance");
throw error;
}
})(),
// Task 2: Analyze DNS performance
(async () => {
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("analyzeDnsPerformance");
}
this.logProgress("Analyzing DNS performance...");
try {
const result = await this.analysisEngine.analyzeDnsPerformance(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("analyzeDnsPerformance");
if (duration) {
this.logProgress(`DNS analysis completed in ${duration.toFixed(2)}ms`);
}
}
return result;
}
catch (error) {
this.errorHandler.logError(error, "Error analyzing DNS performance");
throw error;
}
})(),
// Task 3: Compare configurations
(async () => {
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("compareConfigurations");
}
this.logProgress("Comparing configurations...");
try {
const result = await this.analysisEngine.compareConfigurations(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("compareConfigurations");
if (duration) {
this.logProgress(`Configuration comparison completed in ${duration.toFixed(2)}ms`);
}
}
return result;
}
catch (error) {
this.errorHandler.logError(error, "Error comparing configurations");
throw error;
}
})(),
// Task 4: Detect anomalies
(async () => {
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("detectAnomalies");
}
this.logProgress("Detecting performance anomalies...");
try {
const result = await this.analysisEngine.detectAnomalies(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("detectAnomalies");
if (duration) {
this.logProgress(`Anomaly detection completed in ${duration.toFixed(2)}ms`);
}
}
return result;
}
catch (error) {
this.errorHandler.logError(error, "Error detecting anomalies");
throw error;
}
})(),
]);
}
else {
// Sequential processing
// Step 1: Analyze iperf performance
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("analyzeIperfPerformance");
}
this.logProgress("Analyzing iperf performance...");
iperfAnalysis = await this.analysisEngine.analyzeIperfPerformance(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("analyzeIperfPerformance");
if (duration) {
this.logProgress(`Iperf analysis completed in ${duration.toFixed(2)}ms`);
}
}
// Step 2: Analyze DNS performance
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("analyzeDnsPerformance");
}
this.logProgress("Analyzing DNS performance...");
dnsAnalysis = await this.analysisEngine.analyzeDnsPerformance(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("analyzeDnsPerformance");
if (duration) {
this.logProgress(`DNS analysis completed in ${duration.toFixed(2)}ms`);
}
}
// Step 3: Compare configurations
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("compareConfigurations");
}
this.logProgress("Comparing configurations...");
configurationComparison =
await this.analysisEngine.compareConfigurations(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("compareConfigurations");
if (duration) {
this.logProgress(`Configuration comparison completed in ${duration.toFixed(2)}ms`);
}
}
// Step 4: Detect anomalies
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("detectAnomalies");
}
this.logProgress("Detecting performance anomalies...");
anomalies = await this.analysisEngine.detectAnomalies(datasets);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("detectAnomalies");
if (duration) {
this.logProgress(`Anomaly detection completed in ${duration.toFixed(2)}ms`);
}
}
}
// Step 5: Create executive summary
if (this.performanceMonitor) {
this.performanceMonitor.startOperation("createExecutiveSummary");
}
this.logProgress("Creating executive summary...");
const summary = this.createExecutiveSummary(datasets, iperfAnalysis, dnsAnalysis, configurationComparison, anomalies);
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("createExecutiveSummary");
if (duration) {
this.logProgress(`Executive summary created in ${duration.toFixed(2)}ms`);
}
}
// Combine all analysis results
return {
iperfAnalysis,
dnsAnalysis,
configurationComparison,
anomalies,
summary,
};
}
catch (error) {
this.errorHandler.logError(error, "Error performing analysis");
throw error;
}
finally {
// End performance monitoring for this operation
if (this.performanceMonitor) {
const duration = this.performanceMonitor.endOperation("performAnalysis");
if (duration) {
this.logProgress(`Analysis completed in ${duration.toFixed(2)}ms`);
// Generate performance report if monitoring is enabled
if (this.config.enablePerformanceMonitoring) {
const perfReport = this.performanceMonitor.generateReport();
this.logProgress("Performance report generated");
// Save performance report if output path is provided
if (this.config.reportOutputPath) {
const perfReportPath = this.config.reportOutputPath.replace(/\.md$/, "-performance.md");
try {
fs_extra_1.default.writeFileSync(perfReportPath, perfReport);
this.logProgress(`Performance report saved to ${perfReportPath}`);
}
catch (error) {
this.errorHandler.logError(error, "Error saving performance report");
}
}
}
}
}
}
}
/**
* Create an executive summary from the analysis results
* @param datasets The analyzed datasets
* @param iperfAnalysis The iperf performance analysis
* @param dnsAnalysis The DNS performance analysis
* @param configurationComparison The configuration comparison
* @param anomalies The detected anomalies
* @returns The executive summary
* @private
*/
createExecutiveSummary(datasets, iperfAnalysis, dnsAnalysis, configurationComparison, anomalies) {
// Find optimal configuration
const optimalConfig = configurationComparison.overallRanking.length > 0
? configurationComparison.overallRanking.sort((a, b) => a.rank - b.rank)[0].configuration
: "Unknown";
// Generate key findings
const keyFindings = [];
// Add MTU impact finding
if (configurationComparison.mtuImpact &&
configurationComparison.mtuImpact.optimalMtu) {
keyFindings.push(`MTU ${configurationComparison.mtuImpact.optimalMtu} provides the best overall network performance.`);
}
// Add AWS logging impact finding
if (configurationComparison.loggingImpact) {
const impact = configurationComparison.loggingImpact.performanceImpact;
const direction = impact > 0 ? "improves" : "degrades";
const magnitude = Math.abs(impact);
if (magnitude > 0.05) {
// 5% threshold for significance
keyFindings.push(`AWS logging ${direction} overall performance by approximately ${(magnitude * 100).toFixed(1)}%.`);
}
else {
keyFindings.push("AWS logging has minimal impact on overall network performance.");
}
}
// Add bandwidth finding
if (iperfAnalysis.bandwidthComparison &&
iperfAnalysis.bandwidthComparison.length > 0) {
const bestBandwidth = [...iperfAnalysis.bandwidthComparison].sort((a, b) => b.avgBandwidthMbps - a.avgBandwidthMbps)[0];
keyFindings.push(`Highest average bandwidth of ${bestBandwidth.avgBandwidthMbps.toFixed(2)} Mbps achieved with ${bestBandwidth.configuration} configuration.`);
}
// Add DNS performance finding
if (dnsAnalysis.performanceMetrics &&
dnsAnalysis.performanceMetrics.length > 0) {
const bestDns = [...dnsAnalysis.performanceMetrics].sort((a, b) => a.avgResponseTimeMs - b.avgResponseTimeMs)[0];
keyFindings.push(`Fastest DNS resolution (${bestDns.avgResponseTimeMs.toFixed(2)} ms) achieved with ${bestDns.configuration} configuration.`);
}
// Add anomaly finding if any exist
if (anomalies && anomalies.length > 0) {
const highSeverity = anomalies.filter((a) => a.severity === "high");
if (highSeverity.length > 0) {
keyFindings.push(`Detected ${highSeverity.length} high severity performance anomalies that require attention.`);
}
}
// Generate recommendations
const recommendations = [];
// Add MTU recommendations
if (configurationComparison.mtuImpact &&
configurationComparison.mtuImpact.recommendations) {
recommendations.push(...configurationComparison.mtuImpact.recommendations);
}
// Add logging recommendations
if (configurationComparison.loggingImpact &&
configurationComparison.loggingImpact.recommendations) {
recommendations.push(...configurationComparison.loggingImpact.recommendations);
}
// Add anomaly recommendations
if (anomalies && anomalies.length > 0) {
const highSeverityRecs = anomalies
.filter((a) => a.severity === "high")
.flatMap((a) => a.recommendations);
// Add unique recommendations
const uniqueRecs = new Set(highSeverityRecs);
recommendations.push(...uniqueRecs);
}
// Generate performance highlights
const performanceHighlights = [];
// Add bandwidth highlight
if (iperfAnalysis.bandwidthComparison &&
iperfAnalysis.bandwidthComparison.length > 1) {
const sorted = [...iperfAnalysis.bandwidthComparison].sort((a, b) => b.avgBandwidthMbps - a.avgBandwidthMbps);
const best = sorted[0];
const worst = sorted[sorted.length - 1];
const difference = ((best.avgBandwidthMbps - worst.avgBandwidthMbps) /
worst.avgBandwidthMbps) *
100;
performanceHighlights.push(`Bandwidth varies by up to ${difference.toFixed(1)}% across different configurations.`);
}
// Add latency highlight
if (iperfAnalysis.latencyAnalysis &&
iperfAnalysis.latencyAnalysis.length > 0) {
const bestLatency = [...iperfAnalysis.latencyAnalysis].sort((a, b) => a.avgLatencyMs - b.avgLatencyMs)[0];
performanceHighlights.push(`Lowest average latency (${bestLatency.avgLatencyMs.toFixed(2)} ms) achieved with ${bestLatency.configuration} configuration.`);
}
// Add reliability highlight
if (iperfAnalysis.reliabilityMetrics &&
iperfAnalysis.reliabilityMetrics.length > 0) {
const bestReliability = [...iperfAnalysis.reliabilityMetrics].sort((a, b) => b.successRate - a.successRate)[0];
performanceHighlights.push(`Highest reliability (${(bestReliability.successRate * 100).toFixed(2)}% success rate) achieved with ${bestReliability.configuration} configuration.`);
}
return {
totalDatasets: datasets.length,
keyFindings,
recommendations,
optimalConfiguration: optimalConfig,
performanceHighlights,
};
}
/**
* Save the generated report to a file
* @param report The report content to save
* @param outputPath The path to save the report to
* @returns A promise that resolves when the report is saved
* @private
*/
async saveReport(report, outputPath) {
try {
// Ensure the directory exists
await fs_extra_1.default.ensureDir(path_1.default.dirname(outputPath));
// Write the report to the file
await fs_extra_1.default.writeFile(outputPath, report, "utf8");
}
catch (error) {
this.errorHandler.logError(error, `Error saving report to ${outputPath}`);
throw error;
}
}
/**
* Log progress information if enabled
* @param message The progress message to log
* @private
*/
logProgress(message) {
if (this.config.logProgress) {
console.log(`[NetworkPerformanceAnalyzer] ${message}`);
}
}
}
exports.NetworkPerformanceAnalyzer = NetworkPerformanceAnalyzer;
/**
* Factory function to create a new NetworkPerformanceAnalyzer instance with configuration and plugin support
* @param config Configuration options for the analyzer
* @returns A new NetworkPerformanceAnalyzer instance
*/
function createNetworkPerformanceAnalyzer(config = {}) {
// Initialize configuration manager
const configManager = new ConfigurationManager_1.ConfigurationManager();
// Load configuration from file if provided
if (config.configPath) {
configManager.loadFromFile(config.configPath);
}
// Set environment if provided
if (config.environment) {
configManager.setEnvironment(config.environment);
}
// Merge provided config with loaded config
configManager.update({
...(config.continueOnError !== undefined ||
config.logProgress !== undefined ||
config.useParallelProcessing !== undefined ||
config.maxParallelTasks !== undefined ||
config.enablePerformanceMonitoring !== undefined ||
config.memoryThresholdPercent !== undefined
? {
analysis: {
...(config.continueOnError !== undefined
? { continueOnError: config.continueOnError }
: {}),
...(config.logProgress !== undefined
? { logProgress: config.logProgress }
: {}),
...(config.useParallelProcessing !== undefined
? { useParallelProcessing: config.useParallelProcessing }
: {}),
...(config.maxParallelTasks !== undefined
? { maxParallelTasks: config.maxParallelTasks }
: {}),
...(config.enablePerformanceMonitoring !== undefined
? {
enablePerformanceMonitoring: config.enablePerformanceMonitoring,
}
: {}),
...(config.memoryThresholdPercent !== undefined
? { memoryThresholdPercent: config.memoryThresholdPercent }
: {}),
},
}
: {}),
...(config.anomalyThresholds
? {
anomalyThresholds: Object.fromEntries(Object.entries(config.anomalyThresholds).filter(([_, value]) => value !== undefined))
}
: {}),
...(config.reportOutputPath || config.includeSections
? {
reporting: {
...(config.reportOutputPath
? {
outputDirectory: path_1.default.dirname(config.reportOutputPath),
defaultFilename: path_1.default.basename(config.reportOutputPath),
}
: {}),
...(config.includeSections
? { includeSections: config.includeSections }
: {}),
},
}
: {}),
});
// Get final analyzer config
const analyzerConfig = configManager.getAnalyzerConfig();
// Initialize plugin manager
const pluginManager = new PluginManager_1.PluginManager(configManager);
// Add plugin directories if provided
if (config.pluginDirectories) {
for (const dir of config.pluginDirectories) {
pluginManager.addPluginDirectory(dir);
}
}
// Add default plugin directory
pluginManager.addPluginDirectory(path_1.default.join(__dirname, "../plugins"));
// Initialize template manager
const templateManager = new ReportTemplateManager_1.ReportTemplateManager(configManager);
// Set active template if provided
if (config.reportTemplateId) {
try {
templateManager.setActiveTemplate(config.reportTemplateId);
}
catch (error) {
console.warn(`Template ${config.reportTemplateId} not found, using default template`);
}
}
// Create services
const discoveryService = new DatasetDiscoveryService_1.DefaultDatasetDiscoveryService();
const dataParser = new DataParser_1.DefaultDataParser();
const analysisEngine = new AnalysisEngine_1.DefaultAnalysisEngine();
// Create custom report generator that integrates with plugins and templates
const reportGenerator = new (class extends ReportGenerator_1.DefaultReportGenerator {
async generateReport(analysis) {
try {
// Execute reporter plugins
const pluginResults = await pluginManager.executePlugins("reporter", {
datasets: [], // We don't have the original datasets here
analysisResults: analysis,
});
// Merge plugin results with analysis results
const reportData = {
...analysis,
...pluginResults.reduce((acc, result) => ({ ...acc, ...result }), {}),
};
// Use template manager to generate report
const template = templateManager.getActiveTemplate();
return templateManager.applyTemplate(template, reportData);
}
catch (error) {
console.error("Error generating report with plugins:", error);
// Fall back to default report generation
return super.generateReport(analysis);
}
}
})();
const errorHandler = new ErrorHandler_1.DefaultErrorHandler();
// Create analyzer with configured services
const analyzer = new NetworkPerformanceAnalyzer(discoveryService, dataParser, analysisEngine, reportGenerator, errorHandler, analyzerConfig);
// Discover and load plugins
(async () => {
try {
await pluginManager.discoverPlugins();
await pluginManager.loadEnabledPlugins();
const enabledPlugins = pluginManager.getEnabledPlugins();
if (enabledPlugins.length > 0 && analyzerConfig.logProgress) {
console.log(`Loaded ${enabledPlugins.length} plugins: ${enabledPlugins
.map((p) => p.name)
.join(", ")}`);
}
}
catch (error) {
console.error("Error loading plugins:", error);
}
})();
return analyzer;
}
//# sourceMappingURL=NetworkPerformanceAnalyzer.js.map