import { CloudWatchLogsClient, DescribeLogGroupsCommand, DescribeLogGroupsCommandInput, GetLogEventsCommand, GetLogEventsCommandInput, FilterLogEventsCommand, FilterLogEventsCommandInput, OutputLogEvent, LogGroup } from '@aws-sdk/client-cloudwatch-logs'; import { cloudWatchLogsClient } from '../../config/aws-config.js'; import { getLogger } from '../../utils/logging.js'; import { handleAwsError } from '../../utils/error-handling.js'; const logger = getLogger(); /** * Interface for CloudWatch Logs service */ export interface CloudWatchLogsService { /** * Test connection to CloudWatch Logs */ testConnection(): Promise; /** * List log groups with optional filtering */ listLogGroups(options?: { prefix?: string; limit?: number; }): Promise; /** * Get log events from a specific log group and stream */ getLogEvents(options: { logGroupName: string; logStreamName: string; startTime?: number; endTime?: number; limit?: number; }): Promise; /** * Filter log events across streams within a log group */ filterLogEvents(options: { logGroupName: string; logStreamNames?: string[]; filterPattern?: string; startTime?: number; endTime?: number; limit?: number; }): Promise; } /** * Implementation of CloudWatch Logs service */ export class CloudWatchLogsServiceImpl implements CloudWatchLogsService { private client: CloudWatchLogsClient; constructor(client?: CloudWatchLogsClient) { this.client = client || cloudWatchLogsClient; } /** * Test connection to CloudWatch Logs * @returns Success message with log group name if found */ async testConnection(): Promise { try { const command = new DescribeLogGroupsCommand({ limit: 1 }); const response = await this.client.send(command); if (response.logGroups && response.logGroups.length > 0) { return `AWS connection successful. Found log group: ${response.logGroups[0].logGroupName}`; } else { return 'AWS connection successful, but no log groups found.'; } } catch (error) { // Use the enhanced AWS error handler throw handleAwsError(error, 'CloudWatchLogs', 'testConnection'); } } /** * List log groups with optional filtering * @param options Filtering options * @returns Array of log groups */ async listLogGroups(options: { prefix?: string; limit?: number; } = {}): Promise { try { const { prefix, limit } = options; logger.info('Listing CloudWatch log groups', { prefix: prefix || 'none', limit: limit || 50 }); const params: DescribeLogGroupsCommandInput = { logGroupNamePrefix: prefix, limit: limit || 50 }; const command = new DescribeLogGroupsCommand(params); const response = await this.client.send(command); const logGroups = response.logGroups || []; logger.debug(`Found ${logGroups.length} log groups`); return logGroups; } catch (error) { logger.error('Error listing log groups:', error); throw handleAwsError(error, 'CloudWatchLogs', 'listLogGroups'); } } /** * Get log events from a specific log group and stream * @param options Query options * @returns Array of log events */ async getLogEvents(options: { logGroupName: string; logStreamName: string; startTime?: number; endTime?: number; limit?: number; }): Promise { try { const { logGroupName, logStreamName, startTime, endTime, limit } = options; logger.info('Getting CloudWatch log events', { logGroupName, logStreamName, startTime: startTime ? new Date(startTime).toISOString() : 'undefined', endTime: endTime ? new Date(endTime).toISOString() : 'undefined', limit: limit || 100 }); const params: GetLogEventsCommandInput = { logGroupName, logStreamName, startTime, endTime, limit: limit || 100 }; const command = new GetLogEventsCommand(params); const response = await this.client.send(command); const events = response.events || []; logger.debug(`Retrieved ${events.length} log events`); return events; } catch (error) { logger.error('Error getting log events:', error); throw handleAwsError(error, 'CloudWatchLogs', 'getLogEvents'); } } /** * Filter log events across streams within a log group * @param options Filter options * @returns Array of filtered log events */ async filterLogEvents(options: { logGroupName: string; logStreamNames?: string[]; filterPattern?: string; startTime?: number; endTime?: number; limit?: number; }): Promise { try { const { logGroupName, logStreamNames, filterPattern, startTime, endTime, limit } = options; logger.info('Filtering CloudWatch log events', { logGroupName, streamCount: logStreamNames?.length || 'all', filterPattern: filterPattern || 'none', startTime: startTime ? new Date(startTime).toISOString() : 'undefined', endTime: endTime ? new Date(endTime).toISOString() : 'undefined', limit: limit || 100 }); const params: FilterLogEventsCommandInput = { logGroupName, logStreamNames, filterPattern, startTime, endTime, limit: limit || 100 }; const command = new FilterLogEventsCommand(params); const response = await this.client.send(command); const events = response.events || []; logger.debug(`Filtered ${events.length} log events`); return events; } catch (error) { logger.error('Error filtering log events:', error); throw handleAwsError(error, 'CloudWatchLogs', 'filterLogEvents'); } } } /** * Create a new CloudWatch Logs service instance * @param client Optional CloudWatch Logs client * @returns CloudWatch Logs service */ export function createCloudWatchLogsService(client?: CloudWatchLogsClient): CloudWatchLogsService { return new CloudWatchLogsServiceImpl(client); }