Skip to content
This repository has been archived by the owner on Aug 16, 2019. It is now read-only.

Alarms #50

Merged
merged 51 commits into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
87315c3
example alarm logic
ostr00000 Oct 24, 2018
01238a2
hashbang, basic docstring and authorship information
ostr00000 Nov 4, 2018
9f70185
Merge branch 'develop' of https://github.com/ostr00000/OVERWATCH into…
ostr00000 Nov 6, 2018
a4482c3
Create increasingValueAlarm.py
Nabywaniec Nov 25, 2018
cfc5bb9
Create checkLastNValuesAlarm
Nabywaniec Nov 25, 2018
b3cc3d1
Add files via upload
Nabywaniec Nov 25, 2018
6e00e04
change interface alarms
ostr00000 Nov 25, 2018
6f53a69
python2 fix
ostr00000 Nov 25, 2018
174e203
Update checkLastNAlarms.py
Nabywaniec Nov 27, 2018
7cd7c89
Update and rename checkLastNAlarms.py to checkLastNAlarm.py
Nabywaniec Nov 27, 2018
b9af95d
Update checkLastNValuesAlarm.py
Nabywaniec Nov 27, 2018
a7b3f52
Delete decreasingValueAlarm.py
Nabywaniec Nov 27, 2018
6329965
Update and rename increasingValueAlarm.py to changingValueAlarm.py
Nabywaniec Nov 27, 2018
c97e1a9
Added notifications
arturro96 Nov 27, 2018
fc1c967
Reading configuration update
arturro96 Nov 29, 2018
d1b88c6
Added recipients in object.py
arturro96 Nov 29, 2018
cffd94f
Merge remote-tracking branch 'origin/alarms_logic' into notifications
arturro96 Dec 1, 2018
b2822f9
Merge branch 'master' of https://github.com/raymondEhlers/OVERWATCH i…
ostr00000 Dec 4, 2018
4ddabd7
possible: N trendingObject to N alarms, tests
ostr00000 Dec 4, 2018
7e29275
Merge branches 'alarms_logic' and 'develop' of https://github.com/ost…
ostr00000 Dec 4, 2018
252beab
Merge remote-tracking branch 'origin/alarms_logic' into notifications
arturro96 Dec 5, 2018
581b426
setAlarms fix
ostr00000 Dec 5, 2018
2ae77bc
change alarm names, convert python list to numpy
ostr00000 Dec 5, 2018
725086a
Merge remote-tracking branch 'origin/alarms_logic' into notifications
arturro96 Dec 5, 2018
634cb6d
split previousValue into absolute and relative
ostr00000 Dec 6, 2018
3238ee6
Added alarm collector and docstrings
arturro96 Dec 8, 2018
88466f0
Merge remote-tracking branch 'origin/alarms_logic' into notifications
arturro96 Dec 8, 2018
4d04717
added displaying alarms on webApp
arturro96 Dec 9, 2018
c5f531c
WebApp displaying updates
arturro96 Dec 9, 2018
2cf02fd
Readme added
arturro96 Dec 9, 2018
7753376
Readme update
arturro96 Dec 9, 2018
866c6eb
readme fix
arturro96 Dec 9, 2018
1deaa8d
Exceptions added and changed applying alarms, readme update
arturro96 Dec 10, 2018
5a62554
Small fixes
arturro96 Dec 10, 2018
aef4712
AlarmCollector fix
arturro96 Dec 11, 2018
f51ce65
Update checkLastNAlarm
arturro96 Dec 11, 2018
6ecea70
Deleted recipients
arturro96 Dec 11, 2018
eea6197
Update example.py
arturro96 Dec 11, 2018
10afa10
Update test_alarms.py
Nabywaniec Dec 12, 2018
6000947
Merge remote-tracking branch 'origin/alarms_logic' into notifications
arturro96 Dec 12, 2018
c5de074
Collector update and small fixes
arturro96 Dec 12, 2018
fe2cdaf
Merge remote-tracking branch 'origin/notifications' into notifications
arturro96 Dec 12, 2018
a4ae4e8
Readme update
arturro96 Dec 12, 2018
b74f7eb
Improved displaying alarms on webApp
arturro96 Dec 14, 2018
ddc895e
Displaying fix
arturro96 Dec 14, 2018
1e27f9e
Alarm can invoke itself or by collector, fix tests
ostr00000 Dec 29, 2018
77cc59f
update example
ostr00000 Dec 29, 2018
148d0ba
Merge pull request #5 from ostr00000/notifications
ostr00000 Dec 29, 2018
7d27529
Merge branch 'master' of https://github.com/raymondEhlers/OVERWATCH i…
ostr00000 Dec 29, 2018
d705c96
Merge remote-tracking branch 'remotes/origin/alarms_logic' into develop
ostr00000 Dec 29, 2018
c579a69
Merge pull request #7 from ostr00000/develop
ostr00000 Dec 29, 2018
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
164 changes: 164 additions & 0 deletions overwatch/processing/alarms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@

# Alarms

This module is responsible for generating alarms and sending notifications about them.

Class Alarm has an abstract method `checkAlarm()`, which allows us to implement our own alarms.

Alarms can be aggregated by logic functions or/and.

Examples of alarms can be found in impl package.

## BetweenValuesAlarm

Checks if trend is between minimal and maximal allowed values.

![betweenAlarm example](./doc/betweenAlarm.png)

## MeanInRangeAlarm

Checks if mean from N last measurements is in the range.
![No alarm](./doc/meanRange1.png)
![No alarm](./doc/meanRange2.png)
![No alarm](./doc/meanRange3.png)
![Alarm](./doc/meanRange4.png)

## AbsolutePreviousValueAlarm

Check if (new value - old value) is different more than delta.

![absolutePreviousValueAlarm example](./doc/absolute.png)

## RelativeProviousValueAlarm

Check if new value is between (previous value)/ratio and (previous value)*ratio.

![No alarm](./doc/relative.png)
![Alarm](./doc/relative1.png)
![No alarm](./doc/relative2.png)
![Alarm](./doc/relative3.png)


## CheckLastNAlarm

Check if minimum ratio*N last N alarms are in range.

![No alarm](./doc/last.png)
![No alarm](./doc/last1.png)
![Alarm](./doc/last2.png)
![No alarm](./doc/last3.png)


## Displaying on the webApp
When histogram is processed and alarms are generated, they are displayed above this histogram on the webApp.

# Class Diagram
![Diagram](./doc/alarms_class_diag.png)

# Notifications

Each generated alarm is collected by AlarmCollector. It allows us send notifications about alarms when we want:
after processing trending object, after processing histogram or when all histograms are processed. To send messages via email
you have to call
`announceOnEmail()` method on alarmCollector object. To print messages on console call `showOnConsole()` method. To
send on Slack call `announceOnSlack()`

## Emails

There is possibility to send notifications about alarms via email. To send emails add to configuration file following information:

```yaml
# Email configuration for gmail
emailDelivery:
smtpSettings:
address: "smtp.gmail.com"
port: 587
userName: "email@address"
password: "password"
```

## Slack

To send messages on Slack add to configuration file:

```yaml
# Slack configuration
# Define token and channel
slack:
apiToken: 'token'
slackChannel: "alarms"
```

# Usage

To specify alarms and receivers write for example following function:

```python
def alarmConfig():
recipients = ["test1@mail", "test2@mail"]
mailSender = MailSender(recipients)
slackSender = SlackNotification()
borderWarning = BetweenValuesAlarm(minVal=0, maxVal=50, alarmText="WARNING")

borderWarning.receivers = [printCollector]

borderError = BetweenValuesAlarm(minVal=0, maxVal=70, alarmText="ERROR")
borderError.receivers = [mailSender, slackSender]

bva = BetweenValuesAlarm(minVal=0, maxVal=90, alarmText='BETWEEN')
# TODO add second alarm to andAlarm
seriousAlarm = AndAlarm([bva], "Serious Alarm")
seriousAlarm.addReceiver(mailSender)

return [borderWarning, borderError, seriousAlarm]
```

You can define separate alarms to different trending objects:

```python
def alarmMeanConfig():
slack = SlackNotification()
lastAlarm = CheckLastNAlarm(alarmText="ERROR")
lastAlarm.receivers = [printCollector, slack]

return [lastAlarm]

def alarmStdConfig():
slack = SlackNotification()
meanInRangeWarning = MeanInRangeAlarm(alarmText="WARNING")
meanInRangeWarning.receivers = [printCollector, slack]

return [meanInRangeWarning]

def alarmMaxConfig():
recipients = ["test1@mail", "test2@mail"]
mailSender = MailSender(recipients)
borderWarning = BetweenValuesAlarm(minVal=0, maxVal=50, alarmText="WARNING")
borderWarning.receivers = [printCollector, mailSender]

return [borderWarning]
```

To use alarms, define them in EMC.py or other detector file in `getTrendingObjectInfo()`:

```python
trendingNameToObject = {
"max": trendingObjects.MaximumTrending,
"mean": trendingObjects.MeanTrending,
"stdDev": trendingObjects.StdDevTrending,
}
# Assign created earlier alarms to particular trending objects
alarms = {
"max": alarmMaxConfig(),
"mean": alarmMeanConfig(),
"stdDev": alarmStdConfig()
}
trendingInfo = []
for prefix, cls in trendingNameToObject.items():
for dependingFile, desc in infoList:
infoObject = TrendingInfo(prefix + dependingFile, desc, [dependingFile], cls)
if prefix in alarms:
infoObject.addAlarm(alarms[prefix]) # Set alarms
trendingInfo.append(infoObject)
return trendingInfo
```
Empty file.
45 changes: 45 additions & 0 deletions overwatch/processing/alarms/aggregatingAlarm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python
""" Base class for alarms which manage of aggregation alarms.

.. code-author: Pawel Ostrowski <[email protected]>, AGH University of Science and Technology
"""

from overwatch.processing.alarms.alarm import Alarm

try:
from typing import * # noqa
except ImportError:
pass


class AggregatingAlarm(Alarm):
def __init__(self, children, alarmText=''): # type: (List[Alarm], str) -> None
super(AggregatingAlarm, self).__init__(alarmText=alarmText)

# None - no value, True/False - last value returned from alarm
self.children = {c: None for c in children} # type: Dict[Alarm, Optional[bool]]

for child in children:
child.parent = self

def addChild(self, child): # type: (Alarm) -> None
assert child.parent is None
child.parent = self
self.children[child] = None

def isAllAlarmsCompleted(self):
return all(c is not None for c in self.children.values())

def checkAlarm(self, *args, **kwargs): # type: () -> (bool, str)
"""abstract method"""
raise NotImplementedError

def childProcessed(self, child, result):
if self.children[child] is not None:
print("WARNING: last result ignored")

self.children[child] = result

if self.isAllAlarmsCompleted():
self.processCheck()
self.children = {c: None for c in self.children}
62 changes: 62 additions & 0 deletions overwatch/processing/alarms/alarm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python
""" Base class for alarms.

.. code-author: Pawel Ostrowski <[email protected]>, AGH University of Science and Technology
"""
import numpy as np
from overwatch.processing.alarms.collectors import alarmCollector

try:
from typing import * # noqa
except ImportError:
# Imports in this block below here are used solely for typing information
from ..trending.objects.object import TrendingObject # noqa
from overwatch.processing.alarms.aggregatingAlarm import AggregatingAlarm # noqa


class Alarm(object):
def __init__(self, alarmText='', collector=None):
self.alarmText = alarmText
self.collector = collector
self.receivers = []
self.parent = None # type: Optional[AggregatingAlarm]

def addReceiver(self, receiver): # type: (callable) -> None
self.receivers.append(receiver)

def processCheck(self, trend=None): # type: (Optional[TrendingObject]) -> None
args = (self.prepareTrendValues(trend),) if trend else ()
result = self.checkAlarm(*args)
isAlarm, msg = result

if isAlarm:
msg = "[{alarmText}]: {msg}".format(alarmText=self.alarmText, msg=msg)

# aggregating alarms don't have trend
if trend:
trend.alarmsMessages.append(msg)

# tell collector about alarm or announce alarm itself
if self.collector:
alarmCollector.collectMessage(self, "[{trendName}]{msg}".format(trendName=trend.name, msg=msg))
else:
self._announceAlarm(msg)
if self.parent:
self.parent.childProcessed(child=self, result=isAlarm)

@staticmethod
def prepareTrendValues(trend): # type: (TrendingObject) -> np.ndarray
trendingValues = np.array(trend.trendedValues)
if len(trendingValues.shape) == 2:
trendingValues = trendingValues[:, 0]
if len(trendingValues.shape) > 2:
raise TypeError
return trendingValues

def checkAlarm(self, trend): # type: (np.ndarray) -> (bool, str)
"""abstract method"""
raise NotImplementedError

def _announceAlarm(self, msg): # type: (str) -> None
for receiver in self.receivers:
receiver(msg)
Loading