Browse Source

Segment info #693 (#700)

pull/1/head
Alexandr Velikiy 5 years ago committed by Evgeny Smyshlyaev
parent
commit
5374c45b36
  1. 6
      analytics/analytics/analytic_types/segment.py
  2. 1
      analytics/analytics/detectors/anomaly_detector.py
  3. 30
      analytics/analytics/detectors/threshold_detector.py
  4. 1
      analytics/analytics/utils/common.py
  5. 7
      analytics/tests/test_detectors.py
  6. 4
      server/src/controllers/analytics_controller.ts
  7. 8
      server/src/models/segment_model.ts
  8. 14
      server/src/services/alert_service.ts
  9. 2
      server/src/services/notification_service.ts

6
analytics/analytics/analytic_types/segment.py

@ -5,14 +5,16 @@ class Segment:
Used for segment manipulation instead of { 'from': ..., 'to': ... } dict Used for segment manipulation instead of { 'from': ..., 'to': ... } dict
''' '''
def __init__(self, from_timestamp: int, to_timestamp: int): def __init__(self, from_timestamp: int, to_timestamp: int, message: str = None):
if to_timestamp < from_timestamp: if to_timestamp < from_timestamp:
raise ValueError(f'Can`t create segment with to < from: {to_timestamp} < {from_timestamp}') raise ValueError(f'Can`t create segment with to < from: {to_timestamp} < {from_timestamp}')
self.from_timestamp = from_timestamp self.from_timestamp = from_timestamp
self.to_timestamp = to_timestamp self.to_timestamp = to_timestamp
self.message = message
def to_json(self): def to_json(self):
return { return {
'from': self.from_timestamp, 'from': self.from_timestamp,
'to': self.to_timestamp 'to': self.to_timestamp,
'message': self.message
} }

1
analytics/analytics/detectors/anomaly_detector.py

@ -116,6 +116,7 @@ class AnomalyDetector(ProcessingDetector):
segments = [Segment( segments = [Segment(
utils.convert_pd_timestamp_to_ms(dataframe['timestamp'][segment[0]]), utils.convert_pd_timestamp_to_ms(dataframe['timestamp'][segment[0]]),
utils.convert_pd_timestamp_to_ms(dataframe['timestamp'][segment[1]]), utils.convert_pd_timestamp_to_ms(dataframe['timestamp'][segment[1]]),
f'{data[segment[0]]} out of bound'
) for segment in segments] ) for segment in segments]
last_dataframe_time = dataframe.iloc[-1]['timestamp'] last_dataframe_time = dataframe.iloc[-1]['timestamp']

30
analytics/analytics/detectors/threshold_detector.py

@ -1,5 +1,6 @@
import logging as log import logging as log
import operator
import pandas as pd import pandas as pd
import numpy as np import numpy as np
from typing import Optional, List from typing import Optional, List
@ -49,24 +50,23 @@ class ThresholdDetector(Detector):
# TODO: merge segments # TODO: merge segments
if pd.isnull(current_value): if pd.isnull(current_value):
if condition == 'NO_DATA': if condition == 'NO_DATA':
segment.message = 'NO_DATA detected'
segments.append(segment) segments.append(segment)
continue continue
if condition == '>': comparators = {
if current_value > value: '>': operator.gt,
segments.append(segment) '<': operator.lt,
elif condition == '>=': '=': operator.eq,
if current_value >= value: '>=': operator.ge,
segments.append(segment) '<=': operator.le
elif condition == '=': }
if current_value == value:
segments.append(segment) assert condition in comparators.keys(), f'condition {condition} not allowed'
elif condition == '<=':
if current_value <= value: if comparators[condition](current_value, value):
segments.append(segment) segment.message = f"{current_value} {condition} threshold's value {value}"
elif condition == '<': segments.append(segment)
if current_value < value:
segments.append(segment)
last_entry = dataframe.iloc[-1] last_entry = dataframe.iloc[-1]
last_detection_time = utils.convert_pd_timestamp_to_ms(last_entry['timestamp']) last_detection_time = utils.convert_pd_timestamp_to_ms(last_entry['timestamp'])

1
analytics/analytics/utils/common.py

@ -137,6 +137,7 @@ def merge_intersecting_segments(segments: List[Segment], time_step: int) -> List
previous_segment = segments[0] previous_segment = segments[0]
for i in range(1, len(segments)): for i in range(1, len(segments)):
if segments[i].from_timestamp <= previous_segment.to_timestamp + time_step: if segments[i].from_timestamp <= previous_segment.to_timestamp + time_step:
segments[i].message = segments[-1].message
segments[i].from_timestamp = min(previous_segment.from_timestamp, segments[i].from_timestamp) segments[i].from_timestamp = min(previous_segment.from_timestamp, segments[i].from_timestamp)
segments[i].to_timestamp = max(previous_segment.to_timestamp, segments[i].to_timestamp) segments[i].to_timestamp = max(previous_segment.to_timestamp, segments[i].to_timestamp)
segments[i - 1] = None segments[i - 1] = None

7
analytics/tests/test_detectors.py

@ -2,6 +2,7 @@ import unittest
import pandas as pd import pandas as pd
from detectors import pattern_detector, threshold_detector, anomaly_detector from detectors import pattern_detector, threshold_detector, anomaly_detector
from analytic_types.detector_typing import DetectionResult
class TestPatternDetector(unittest.TestCase): class TestPatternDetector(unittest.TestCase):
@ -44,6 +45,8 @@ class TestAnomalyDetector(unittest.TestCase):
'timeStep': 1 'timeStep': 1
} }
detector = anomaly_detector.AnomalyDetector('test_id') detector = anomaly_detector.AnomalyDetector('test_id')
detect_result = detector.detect(dataframe, cache) detect_result: DetectionResult = detector.detect(dataframe, cache)
detected_segments = list(map(lambda s: {'from': s.from_timestamp, 'to': s.to_timestamp}, detect_result.segments))
result = [{ 'from': 1523889000005.0, 'to': 1523889000005.0 }] result = [{ 'from': 1523889000005.0, 'to': 1523889000005.0 }]
self.assertEqual(result, detect_result.to_json()['segments']) self.assertEqual(result, detected_segments)

4
server/src/controllers/analytics_controller.ts

@ -451,9 +451,9 @@ async function processDetectionResult(analyticUnitId: AnalyticUnit.AnalyticUnitI
} }
console.log(`got detection result for ${analyticUnitId} with ${detectionResult.segments.length} segments`); console.log(`got detection result for ${analyticUnitId} with ${detectionResult.segments.length} segments`);
const sortedSegments: {from, to}[] = _.sortBy(detectionResult.segments, 'from'); const sortedSegments: {from, to, message?}[] = _.sortBy(detectionResult.segments, 'from');
const segments = sortedSegments.map( const segments = sortedSegments.map(
segment => new Segment.Segment(analyticUnitId, segment.from, segment.to, false, false) segment => new Segment.Segment(analyticUnitId, segment.from, segment.to, false, false, undefined, segment.message)
); );
return { return {

8
server/src/models/segment_model.ts

@ -17,7 +17,7 @@ export class Segment {
public labeled: boolean = false, public labeled: boolean = false,
public deleted: boolean = false, public deleted: boolean = false,
public id?: SegmentId, public id?: SegmentId,
public params?: any public message?: string
) { ) {
if(analyticUnitId === undefined) { if(analyticUnitId === undefined) {
throw new Error('AnalyticUnitId is undefined'); throw new Error('AnalyticUnitId is undefined');
@ -43,7 +43,8 @@ export class Segment {
from: this.from, from: this.from,
to: this.to, to: this.to,
labeled: this.labeled, labeled: this.labeled,
deleted: this.deleted deleted: this.deleted,
message: this.message
}; };
} }
@ -54,7 +55,8 @@ export class Segment {
return new Segment( return new Segment(
obj.analyticUnitId, obj.analyticUnitId,
+obj.from, +obj.to, +obj.from, +obj.to,
obj.labeled, obj.deleted, obj._id obj.labeled, obj.deleted,
obj._id, obj.message
); );
} }

14
server/src/services/alert_service.ts

@ -33,7 +33,8 @@ export class Alert {
analyticUnitId: this.analyticUnit.id, analyticUnitId: this.analyticUnit.id,
grafanaUrl, grafanaUrl,
from: segment.from, from: segment.from,
to: segment.to to: segment.to,
message: segment.message
}; };
return alert; return alert;
@ -46,7 +47,8 @@ export class Alert {
``, ``,
`From: ${new Date(meta.from)}`, `From: ${new Date(meta.from)}`,
`To: ${new Date(meta.to)}`, `To: ${new Date(meta.to)}`,
`ID: ${meta.analyticUnitId}` `ID: ${meta.analyticUnitId}`,
`Message: ${meta.message}`
].join('\n'); ].join('\n');
} }
} }
@ -111,12 +113,8 @@ class ThresholdAlert extends Alert {
`ID: ${meta.analyticUnitId}` `ID: ${meta.analyticUnitId}`
].join('\n'); ].join('\n');
if(meta.params !== undefined) { if(meta.message !== undefined) {
const metrics = ` message += meta.message;
Metrics:
${this.analyticUnit.metric.targets[0].expr}: ${meta.params.value}
`;
message += metrics;
} }
return message; return message;
} }

2
server/src/services/notification_service.ts

@ -25,7 +25,7 @@ export declare type AnalyticMeta = {
grafanaUrl: string, grafanaUrl: string,
from: number, from: number,
to: number to: number
params?: any, message?: any,
regionImage?: any regionImage?: any
} }

Loading…
Cancel
Save