Enhance ComboHandler and orchestrator functionality with access control and error handling improvements
- Added AccessControl to ComboHandler for role-based access management. - Implemented gas estimation for plan execution and improved gas limit checks. - Updated execution and preparation methods to enforce step count limits and role restrictions. - Enhanced error handling in orchestrator API endpoints with AppError for better validation feedback. - Integrated request timeout middleware for improved request management. - Updated Swagger documentation to reflect new API structure and parameters.
This commit is contained in:
80
orchestrator/src/logging/logAggregation.ts
Normal file
80
orchestrator/src/logging/logAggregation.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { logger } from "./logger";
|
||||
|
||||
/**
|
||||
* Log aggregation service
|
||||
* In production, this would integrate with ELK Stack, Datadog, or Splunk
|
||||
*/
|
||||
|
||||
export interface LogAggregator {
|
||||
sendLog(level: string, message: string, metadata?: any): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* ELK Stack aggregator (mock implementation)
|
||||
*/
|
||||
export class ELKAggregator implements LogAggregator {
|
||||
private endpoint: string;
|
||||
|
||||
constructor(endpoint: string) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
async sendLog(level: string, message: string, metadata?: any): Promise<void> {
|
||||
// In production, send to Logstash or Elasticsearch
|
||||
// const logEntry = {
|
||||
// timestamp: new Date().toISOString(),
|
||||
// level,
|
||||
// message,
|
||||
// ...metadata,
|
||||
// };
|
||||
// await fetch(`${this.endpoint}/logs`, {
|
||||
// method: "POST",
|
||||
// body: JSON.stringify(logEntry),
|
||||
// });
|
||||
|
||||
// For now, just log normally
|
||||
logger[level as keyof typeof logger](metadata || {}, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Datadog aggregator (mock implementation)
|
||||
*/
|
||||
export class DatadogAggregator implements LogAggregator {
|
||||
private apiKey: string;
|
||||
|
||||
constructor(apiKey: string) {
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
async sendLog(level: string, message: string, metadata?: any): Promise<void> {
|
||||
// In production, send to Datadog API
|
||||
// await fetch("https://http-intake.logs.datadoghq.com/v1/input/", {
|
||||
// method: "POST",
|
||||
// headers: {
|
||||
// "DD-API-KEY": this.apiKey,
|
||||
// },
|
||||
// body: JSON.stringify({
|
||||
// level,
|
||||
// message,
|
||||
// ...metadata,
|
||||
// }),
|
||||
// });
|
||||
|
||||
logger[level as keyof typeof logger](metadata || {}, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get log aggregator instance
|
||||
*/
|
||||
export function getLogAggregator(): LogAggregator | null {
|
||||
if (process.env.LOG_AGGREGATOR === "elk" && process.env.ELK_ENDPOINT) {
|
||||
return new ELKAggregator(process.env.ELK_ENDPOINT);
|
||||
}
|
||||
if (process.env.LOG_AGGREGATOR === "datadog" && process.env.DATADOG_API_KEY) {
|
||||
return new DatadogAggregator(process.env.DATADOG_API_KEY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
86
orchestrator/src/logging/logRotation.ts
Normal file
86
orchestrator/src/logging/logRotation.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { promises as fs } from "fs";
|
||||
import path from "path";
|
||||
|
||||
/**
|
||||
* Log rotation service
|
||||
*/
|
||||
export class LogRotationService {
|
||||
private logDir: string;
|
||||
private maxSize: number;
|
||||
private maxFiles: number;
|
||||
|
||||
constructor(logDir = "./logs", maxSize = 10 * 1024 * 1024, maxFiles = 10) {
|
||||
this.logDir = logDir;
|
||||
this.maxSize = maxSize; // 10MB
|
||||
this.maxFiles = maxFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate log file if needed
|
||||
*/
|
||||
async rotateIfNeeded(logFile: string): Promise<void> {
|
||||
try {
|
||||
const stats = await fs.stat(logFile);
|
||||
|
||||
if (stats.size > this.maxSize) {
|
||||
await this.rotate(logFile);
|
||||
}
|
||||
} catch (error) {
|
||||
// File doesn't exist yet, that's okay
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate log file
|
||||
*/
|
||||
private async rotate(logFile: string): Promise<void> {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
||||
const rotatedFile = `${logFile}.${timestamp}`;
|
||||
|
||||
// Rename current log file
|
||||
await fs.rename(logFile, rotatedFile);
|
||||
|
||||
// Clean up old log files
|
||||
await this.cleanupOldLogs(path.dirname(logFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old log files
|
||||
*/
|
||||
private async cleanupOldLogs(logDir: string): Promise<void> {
|
||||
try {
|
||||
const files = await fs.readdir(logDir);
|
||||
const logFiles = files
|
||||
.filter((f) => f.endsWith(".log") || f.match(/\.log\.\d{4}-\d{2}-\d{2}/))
|
||||
.map((f) => ({
|
||||
name: f,
|
||||
path: path.join(logDir, f),
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
// Sort by modification time (newest first)
|
||||
return 0; // Simplified
|
||||
});
|
||||
|
||||
// Keep only maxFiles
|
||||
if (logFiles.length > this.maxFiles) {
|
||||
const toDelete = logFiles.slice(this.maxFiles);
|
||||
for (const file of toDelete) {
|
||||
await fs.unlink(file.path);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Archive old logs
|
||||
*/
|
||||
async archiveLogs(archiveDir: string): Promise<void> {
|
||||
// Move logs older than 30 days to archive
|
||||
// Implementation depends on archive system
|
||||
}
|
||||
}
|
||||
|
||||
export const logRotation = new LogRotationService();
|
||||
|
||||
Reference in New Issue
Block a user