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

Goonj code refactor #4

Open
wants to merge 3 commits 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 goonj/async_process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import threading


class AsyncProcess(object):
"""
Currently using threads to implement async tasks
"""

@staticmethod
def async_processor(method_to_execute, *args, **kwargs):
thread = threading.Thread(target=method_to_execute, *args, **kwargs)
thread.start()
17 changes: 14 additions & 3 deletions goonj/channels/base_channel.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import abc

from goonj.async_process import AsyncProcess
from goonj.conf.constants import Sev


class BaseChannel(object):
"""
Base class for all alerting channels
"""

@abc.abstractmethod
def send(self, sev, message, subject, error_id, error, tag_list):
def _send_message(self, sev, message, subject=None, error_id=None, error=None, tag_list=None):
raise NotImplemented

def send(self, sev, message, subject=None, error_id=None, error=None, tag_list=None):
"""

:param sev:
:param description:
:param message:
:param subject:
:param error_id:
:param error:
:param tag_list:
:return:
"""

pass
if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')

AsyncProcess.async_processor(self._send_message,
args=(sev, message, subject, error_id, error, tag_list),
kwargs={})
26 changes: 4 additions & 22 deletions goonj/channels/email_channel.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import email.utils
import smtplib
import threading

from email.mime.text import MIMEText

from goonj.channels.base_channel import BaseChannel
from goonj.conf.constants import Sev
from goonj.exception import InvalidImplemnationOfNotifcationService, \
from goonj.exception import InvalidImplementationOfNotificationService, \
EmailChannelNameNotDefined, EmailChannelFromAddressNotDefined, \
EmailChannelToAddressNotDefined

Expand Down Expand Up @@ -62,7 +62,7 @@ def register_custom_email_notifcation_service(cls,
notification_service):
if not isinstance(notification_service,
BaseCustomEmailNotificationService):
raise InvalidImplemnationOfNotifcationService('Custom '
raise InvalidImplementationOfNotificationService('Custom '
'Notification '
'service should '
'implement '
Expand All @@ -74,9 +74,7 @@ def register_custom_email_notifcation_service(cls,
def register_smtp_server_config(cls, smtp_server_config):
cls.smtp_server_config = smtp_server_config

def send_message(self, sev, message, subject=None, error_id=None,
error=None,
tag_list=None):
def _send_message(self, sev, message, subject=None, error_id=None, error=None, tag_list=None):

if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')
Expand Down Expand Up @@ -110,19 +108,3 @@ def send_message(self, sev, message, subject=None, error_id=None,
pass # check how to handle logging in libraries
finally:
server.quit()

# send email asynchronously
def send(self, sev, message, subject=None, error_id=None,
error=None,
tag_list=None):
if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')

thread = threading.Thread(target=self.send_message, args=(sev, message,
subject,
error_id,
error,
tag_list),
kwargs={})
thread.start()
# thread.join()
21 changes: 2 additions & 19 deletions goonj/channels/slack_channel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
import threading

import requests

Expand Down Expand Up @@ -28,9 +27,7 @@ def __init__(self, **kwargs):
self.name = kwargs['name']
self.webhook = kwargs['webhook']

def send_message(self, sev, message, subject=None, error_id=None,
error=None,
tag_list=None):
def _send_message(self, sev, message, subject=None, error_id=None, error=None, tag_list=None):

if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')
Expand All @@ -47,18 +44,4 @@ def send_message(self, sev, message, subject=None, error_id=None,
except Exception as e:
logger.error("Error while alerting in slack(Ignoring) %s", e)

# should it be asynchronous or synchrnoonus
def send(self, sev, message, subject=None, error_id=None,
error=None,
tag_list=None):
if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')

thread = threading.Thread(target=self.send_message, args=(sev, message,
subject,
error_id,
error,
tag_list),
kwargs={})
thread.start()
# thread.join() #no need to wait for notfication thread

28 changes: 5 additions & 23 deletions goonj/channels/sms_channel.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import threading

from goonj.channels.base_channel import BaseChannel
from goonj.conf.constants import Sev
from goonj.exception import SmsChannelNameNotDefined, \
InvalidImplemnationOfNotifcationService
InvalidImplementationOfNotificationService


class BaseCustomSmsNotificationService(object):
Expand All @@ -25,21 +23,19 @@ def __init__(self, **kwargs):
self.phone_numbers = kwargs['phone_numbers']

@classmethod
def register_custom_sms_notifcation_service(self,
notification_service):
def register_custom_sms_notifcation_service(self, notification_service):

if not isinstance(notification_service,
BaseCustomSmsNotificationService):
raise InvalidImplemnationOfNotifcationService('Custom '
raise InvalidImplementationOfNotificationService('Custom '
'Notification '
'service should '
'implement '
'BaseCustomSmsNotificationService')

self.notification_service = notification_service

def send_message(self, sev, message, subject=None, error_id=None,
error=None,
tag_list=None):
def _send_message(self, sev, message, subject=None, error_id=None, error=None, tag_list=None):

if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')
Expand All @@ -55,17 +51,3 @@ def send_message(self, sev, message, subject=None, error_id=None,
error,
tag_list)

# send sms asynchronously
def send(self, sev, message, subject=None, error_id=None,
error=None,
tag_list=None):
if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')

thread = threading.Thread(target=self.send_message, args=(sev, message,
subject,
error_id,
error,
tag_list),
kwargs={})
thread.start()
45 changes: 27 additions & 18 deletions goonj/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from goonj.conf.constants import DEFAULT_CONFIG_FILE_PATH
from goonj.exception import GoonjNotInitalized, SourceNotDefined
from goonj.smart_alert import SmartAlert
from goonj.singleton import Singleton

_sources = {}
goonj = None
Expand All @@ -11,39 +12,47 @@ def get_smart_alert(name, logger=None):
"""

:param name: name of the source
:param logger: logger instance
:return: source initailized with all the sev's and associated channels

"""
if name in _sources:
return _sources[name]

if goonj is None:
if not goonj:
raise GoonjNotInitalized

if goonj.config.sources.alert_sources[name] is None:
raise SourceNotDefined('source {} is not defined in configuration '
'file '.format(name))
if not goonj.config.sources.alert_sources[name]:
raise SourceNotDefined('source {} is not defined in configuration file '.format(name))

_sources[name] = goonj.config.sources.alert_sources[name]
_sources[name] = SmartAlert(name, goonj.config.sources.alert_sources[name], logger)

return SmartAlert(name, _sources[name], logger)
return _sources[name]


class Goonj(object):
__instance = None

def __new__(cls, **kwargs):
if cls.__instance is None:
cls.__instance = super(Goonj, cls).__new__(cls)
cls.__instance.__initialized = False
return cls.__instance
class Goonj(object, metaclass=Singleton):

def __init__(self, config_file_path=DEFAULT_CONFIG_FILE_PATH):
global goonj
if (self.__initialized):
return
self.__initialized = True

self.config = Configuration(config_file=config_file_path)
self.config.email = None

"""
Goonj object content-
goonj = {
'config': <goonj.conf.configuration.Configuration at 0x10e8aba58>
}
config = {
'app_id': 'DefaultApp',
'import_paths': '.',
'config_file': 'samples/goonj.yaml',
'sms_settings': <goonj.conf.email_sms_settings.SmsSettings at 0x10e8d14e0>,
'email_settings': <goonj.conf.email_sms_settings.EmailSettings at 0x10e8d8ac8>,
'channels': <goonj.conf.channel_settings.ChannelSettings at 0x10e5f03c8>,
'sources': <goonj.conf.source_setting.SourceSettings at 0x10e8d1400>,
'db': None,
'email': None
}
"""

goonj = self
10 changes: 1 addition & 9 deletions goonj/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class SourceNotDefined(Exception):
pass


class InvalidImplemnationOfNotifcationService(Exception):
class InvalidImplementationOfNotificationService(Exception):
pass


Expand Down Expand Up @@ -62,14 +62,6 @@ class ChannelsNotDefined(Exception):
pass


class EmailChannelNotDefined(Exception):
pass


class SlackChannelNotDefined(Exception):
pass


class SMSChannelNotDefined(Exception):
pass

Expand Down
8 changes: 8 additions & 0 deletions goonj/singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Singleton(type):
_instances = {}

def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)

return cls._instances[cls]
30 changes: 17 additions & 13 deletions goonj/smart_alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,9 @@ def exception(self, message, sev=None, subject=None, error_id=None, error=None,

def log_and_alert_message(self, function_name, message, sev=None, subject=None, error_id=None, error=None,
tag_list=None, *args, **kwargs):
if self.logger is not None:

if sev is None:
sev_value = 'No Sev'
else:
sev_value = sev.value
custom_message = CustomMessage(tag_list, sev_value, message, error, error_id, subject)
getattr(self.logger, function_name)(custom_message, *args, **kwargs)
self.log_message(function_name, message, sev=sev, subject=subject, error_id=error_id, error=error,
tag_list=tag_list, *args, **kwargs)

self.__alert(sev, message, subject, error_id, error, tag_list)

def __alert(self, sev, message, subject, error_id, error, tag_list):
Expand All @@ -61,19 +56,28 @@ def __alert(self, sev, message, subject, error_id, error, tag_list):
if not isinstance(sev, Sev):
raise TypeError('Sev must be an instance of type Sev')

for channel in self.source.default_channels:
channel.send(sev, message, subject, error_id, error,
tag_list)
# for channel in self.source.default_channels:
# channel.send(sev, message, subject, error_id, error,
# tag_list)

try:
if self.source.severity:
severity = self.source.severity[sev.value]

for channel in severity.channels:
channel.send(sev, message, subject, error_id, error,
tag_list)
channel.send(sev, message, subject, error_id, error, tag_list)
except KeyError as e:
pass
# Can supresss this excpetion need to check behaviour
# raise ChannelsNotDefinedForSev('Channels are not defined for {} '
# 'sev in config file'
# ''.format(sev.value))

def log_message(self, function_name, message, sev=None, subject=None, error_id=None, error=None,
tag_list=None, *args, **kwargs):
if not self.logger:
return

sev_value = sev.value if sev else 'No Sev'
custom_message = CustomMessage(tag_list, sev_value, message, error, error_id, subject)
getattr(self.logger, function_name)(custom_message, *args, **kwargs)
23 changes: 23 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
appnope==0.1.0
backcall==0.1.0
certifi==2018.4.16
chardet==3.0.4
decorator==4.3.0
idna==2.6
ipdb==0.11
ipython==6.4.0
ipython-genutils==0.2.0
jedi==0.12.0
parso==0.2.1
pexpect==4.6.0
pickleshare==0.7.4
prompt-toolkit==1.0.15
ptyprocess==0.5.2
Pygments==2.2.0
PyYAML==3.12
requests==2.18.4
simplegeneric==0.8.1
six==1.11.0
traitlets==4.3.2
urllib3==1.22
wcwidth==0.1.7
Loading