Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved error messages #271

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions awslogs/bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import boto3
from botocore.client import ClientError
from botocore.exceptions import NoRegionError, NoCredentialsError
from termcolor import colored

from . import exceptions
Expand Down Expand Up @@ -183,6 +184,17 @@ def add_date_range_arguments(parser, default_start='5m'):
sys.stderr.write(colored("{0}\n".format(hint), "yellow"))
return 4
raise
except NoCredentialsError:
exc = exceptions.InvalidCredentialsError()
sys.stderr.write(colored("{0}\n".format(exc.hint()), "red"))
return exc.code
except NoRegionError:
exc = exceptions.NoRegionSpecifiedError()
sys.stderr.write(colored("{0}\n".format(exc.hint()), "red"))
return exc.code
except exceptions.NoSuchLogGroupError as exc:
sys.stderr.write(colored("{0}\n".format(exc.hint()), "red"))
return exc.code
except exceptions.BaseAWSLogsException as exc:
sys.stderr.write(colored("{0}\n".format(exc.hint()), "red"))
return exc.code
Expand Down
13 changes: 11 additions & 2 deletions awslogs/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import boto3
import botocore
from botocore.compat import json, six, total_seconds
from botocore.exceptions import ClientError

import jmespath

Expand Down Expand Up @@ -97,6 +98,15 @@ def _get_streams_from_pattern(self, group, pattern):
if re.match(reg, stream):
yield stream

def _get_filtered_events(self, **kwargs):
try:
return self.client.filter_log_events(**kwargs)
except ClientError as exc:
if exc.response.get('Error', {}).get('Code') == 'ResourceNotFoundException':
raise exceptions.NoSuchLogGroupError(self.log_group_name)
else:
raise exc

def list_logs(self):
streams = []
if self.log_stream_name != self.ALL_WILDCARD:
Expand Down Expand Up @@ -148,8 +158,7 @@ def generator():
kwargs['filterPattern'] = self.filter_pattern

while True:
response = self.client.filter_log_events(**kwargs)

response = self._get_filtered_events(**kwargs)
for event in response.get('events', []):
if event['eventId'] not in interleaving_sanity:
interleaving_sanity.append(event['eventId'])
Expand Down
24 changes: 24 additions & 0 deletions awslogs/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,27 @@ class NoStreamsFilteredError(BaseAWSLogsException):

def hint(self):
return ("No streams match your pattern '{0}' for the given time period.").format(*self.args)


class NoRegionSpecifiedError(BaseAWSLogsException):

code = 8

def hint(self):
return ("No AWS region specified")


class InvalidCredentialsError(BaseAWSLogsException):

code = 9

def hint(self):
return ("Invalid or missing credentials")


class NoSuchLogGroupError(BaseAWSLogsException):

code = 10

def hint(self):
return ("The specified log group '{0}' does not exist").format(*self.args)
53 changes: 52 additions & 1 deletion tests/test_it.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from io import StringIO

from botocore.compat import total_seconds
from botocore.exceptions import ClientError
from termcolor import colored

try:
Expand All @@ -15,7 +16,9 @@
from unittest.mock import patch, Mock

from awslogs import AWSLogs
from awslogs.exceptions import UnknownDateError
from awslogs.exceptions import (
UnknownDateError, NoSuchLogGroupError, InvalidCredentialsError, NoRegionSpecifiedError
)
from awslogs.bin import main


Expand Down Expand Up @@ -177,6 +180,21 @@ def paginator(value):
client.get_paginator.side_effect = paginator
client.filter_log_events.side_effect = logs

def set_nonexisting_log_group(self, botoclient):
client = Mock()
botoclient.return_value = client

def paginator(value):
mock = Mock()
mock.paginate.return_value = {
'describe_log_groups': [],
'describe_log_streams': []
}.get(value)
return mock

client.get_paginator.side_effect = paginator
client.filter_log_events.side_effect = ClientError({'Error': {'Code': 'ResourceNotFoundException'}}, "filter_log_events")

@patch('awslogs.core.boto3_client')
def test_get_groups(self, botoclient):
client = Mock()
Expand All @@ -197,6 +215,15 @@ def test_get_groups(self, botoclient):
self.assertEqual([g for g in awslogs.get_groups()],
['A', 'B', 'C', 'D', 'E', 'F', 'G'])

@patch('awslogs.core.boto3_client')
def test_get_nonexisting_log_group(self, botoclient):
client = Mock()
botoclient.return_value = client
client.filter_log_events.side_effect = NoSuchLogGroupError
client.get_paginator.return_value.paginate.return_value = []
awslogs = AWSLogs(log_group_name='foobar', log_stream_name='ALL')
self.assertRaises(NoSuchLogGroupError, awslogs.list_logs)

@patch('awslogs.core.boto3_client')
def test_get_groups_with_log_group_prefix(self, botoclient):
client = Mock()
Expand Down Expand Up @@ -603,6 +630,16 @@ def test_unknown_date_error(self, mock_stderr):
"red"))
assert exit_code == 3

@patch('awslogs.core.boto3_client')
@patch('sys.stderr', new_callable=StringIO)
def test_no_such_log_group(self, mock_stderr, botoclient):
self.set_nonexisting_log_group(botoclient)
exit_code = main("awslogs get AAAA".split())
self.assertEqual(mock_stderr.getvalue(),
colored("The specified log group 'AAAA' does not exist\n",
"red"))
assert exit_code == 10

@patch('awslogs.bin.AWSLogs')
@patch('sys.stderr', new_callable=StringIO)
def test_unknown_error(self, mock_stderr, mock_awslogs):
Expand All @@ -613,6 +650,20 @@ def test_unknown_error(self, mock_stderr, mock_awslogs):
self.assertTrue("Exception: Error!" in output)
assert exit_code == 1

@patch('sys.stderr', new_callable=StringIO)
def test_no_region_specified_error(self, mock_stderr):
exit_code = main("awslogs get".split())
output = mock_stderr.getvalue()
self.assertTrue("No AWS region specified" in output)
assert exit_code == 8

@patch('sys.stderr', new_callable=StringIO)
def test_missing_credentials_error(self, mock_stderr):
exit_code = main("awslogs get --aws-region=eu-north-1".split())
output = mock_stderr.getvalue()
self.assertTrue("Invalid or missing credentials" in output)
assert exit_code == 9

@patch('sys.stderr', new_callable=StringIO)
def test_help(self, mock_stderr):
self.assertRaises(SystemExit, main, "awslogs --help".split())
Expand Down