Show More
@@ -29,6 +29,10 b' To run celery queue processing:' | |||
|
29 | 29 | |
|
30 | 30 | celery worker -A appenlight.celery -Q "reports,logs,metrics,default" --ini=development.ini |
|
31 | 31 | |
|
32 | To run celery beats scheduling: | |
|
33 | ||
|
34 | celery beat -A appenlight.celery --ini=development.ini | |
|
35 | ||
|
32 | 36 | You should also run the channelstream websocket server for real-time notifications |
|
33 | 37 | |
|
34 | 38 | channelstream -i filename.ini |
@@ -188,6 +188,10 b' class Rule(RuleBase):' | |||
|
188 | 188 | rule = OR(self.config['rules'], self.type_matrix, |
|
189 | 189 | config_manipulator=self.config_manipulator) |
|
190 | 190 | return rule.match(struct) |
|
191 | elif field_name == '__NOT__': | |
|
192 | rule = NOT(self.config['rules'], self.type_matrix, | |
|
193 | config_manipulator=self.config_manipulator) | |
|
194 | return rule.match(struct) | |
|
191 | 195 | |
|
192 | 196 | if test_value is None: |
|
193 | 197 | return False |
@@ -236,6 +240,16 b' class AND(Rule):' | |||
|
236 | 240 | in self.rules]) |
|
237 | 241 | |
|
238 | 242 | |
|
243 | class NOT(Rule): | |
|
244 | def __init__(self, rules, *args, **kwargs): | |
|
245 | super(NOT, self).__init__({}, *args, **kwargs) | |
|
246 | self.rules = rules | |
|
247 | ||
|
248 | def match(self, struct): | |
|
249 | return all([not self.subrule_check(r_conf, struct) for r_conf | |
|
250 | in self.rules]) | |
|
251 | ||
|
252 | ||
|
239 | 253 | class OR(Rule): |
|
240 | 254 | def __init__(self, rules, *args, **kwargs): |
|
241 | 255 | super(OR, self).__init__({}, *args, **kwargs) |
@@ -266,7 +280,8 b' class RuleService(object):' | |||
|
266 | 280 | if manipulator_func is None: |
|
267 | 281 | def label_rewriter_func(rule): |
|
268 | 282 | field = rule.config.get('field') |
|
269 |
if not field or rule.config['field'] in ['__OR__', |
|
|
283 | if not field or rule.config['field'] in ['__OR__', | |
|
284 | '__AND__', '__NOT__']: | |
|
270 | 285 | return |
|
271 | 286 | |
|
272 | 287 | to_map = field_mappings.get(rule.config['field']) |
@@ -5376,11 +5376,11 b' function kickstartAE() {' | |||
|
5376 | 5376 | " {{rule_ctrlr.readOnlyPossibleFields[rule_ctrlr.rule.field]}}\n" + |
|
5377 | 5377 | " </span>\n" + |
|
5378 | 5378 | "\n" + |
|
5379 | " <span ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'\">\n" + | |
|
5379 | " <span ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'\">\n" + | |
|
5380 | 5380 | " is {{rule_ctrlr.ruleDefinitions.allOps[rule_ctrlr.rule.op]}} {{rule_ctrlr.rule.value}}\n" + |
|
5381 | 5381 | " </span>\n" + |
|
5382 | 5382 | "\n" + |
|
5383 | " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'\">\n" + | |
|
5383 | " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'\">\n" + | |
|
5384 | 5384 | " <p ng-if=\"parent\"><strong>Subrules</strong></p>\n" + |
|
5385 | 5385 | " <div ng-repeat=\"subrule in rule_ctrlr.rule.rules\" class=\"m-l-2\">\n" + |
|
5386 | 5386 | "\n" + |
@@ -5408,7 +5408,7 b' function kickstartAE() {' | |||
|
5408 | 5408 | " ng-options=\"key as label for (key, label) in rule_ctrlr.ruleDefinitions.possibleFields\"></select>\n" + |
|
5409 | 5409 | " </div>\n" + |
|
5410 | 5410 | "\n" + |
|
5411 | " <div ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'\" class=\"form-group\">\n" + | |
|
5411 | " <div ng-if=\"rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'\" class=\"form-group\">\n" + | |
|
5412 | 5412 | "\n" + |
|
5413 | 5413 | " <select ng-model=\"rule_ctrlr.rule.op\" class=\"form-control\"\n" + |
|
5414 | 5414 | " ng-change=\"rule_ctrlr.setDirty()\"\n" + |
@@ -5419,7 +5419,7 b' function kickstartAE() {' | |||
|
5419 | 5419 | "\n" + |
|
5420 | 5420 | " </div>\n" + |
|
5421 | 5421 | "\n" + |
|
5422 | " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'\">\n" + | |
|
5422 | " <span ng-if=\"rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'\">\n" + | |
|
5423 | 5423 | " <p ng-if=\"parent\"><strong>Subrules</strong></p>\n" + |
|
5424 | 5424 | " <div ng-repeat=\"subrule in rule_ctrlr.rule.rules\" class=\"m-l-2\">\n" + |
|
5425 | 5425 | " <div class=\"panel panel-default\">\n" + |
@@ -10694,6 +10694,7 b' function AlertChannelsController(userSelfPropertyResource, applicationsNoIdResou' | |||
|
10694 | 10694 | var possibleFields = { |
|
10695 | 10695 | '__AND__': 'All met (composite rule)', |
|
10696 | 10696 | '__OR__': 'One met (composite rule)', |
|
10697 | '__NOT__': 'Not met (composite rule)', | |
|
10697 | 10698 | 'http_status': 'HTTP Status', |
|
10698 | 10699 | 'duration': 'Request duration', |
|
10699 | 10700 | 'group:priority': 'Group -> Priority', |
@@ -11610,6 +11611,7 b" angular.module('appenlight.directives.postProcessAction', []).directive('postPro" | |||
|
11610 | 11611 | var possibleFields = { |
|
11611 | 11612 | '__AND__': 'All met (composite rule)', |
|
11612 | 11613 | '__OR__': 'One met (composite rule)', |
|
11614 | '__NOT__': 'Not met (composite rule)', | |
|
11613 | 11615 | 'http_status': 'HTTP Status', |
|
11614 | 11616 | 'duration': 'Request duration', |
|
11615 | 11617 | 'group:priority': 'Group -> Priority', |
@@ -11927,8 +11929,9 b" angular.module('appenlight.directives.rule', []).directive('rule', function () {" | |||
|
11927 | 11929 | }; |
|
11928 | 11930 | |
|
11929 | 11931 | vm.fieldChange = function () { |
|
11930 |
var |
|
|
11931 |
var |
|
|
11932 | var compound_types = ['__AND__', '__OR__', '__NOT__']; | |
|
11933 | var new_is_compound = compound_types.indexOf(vm.rule.field) !== -1; | |
|
11934 | var old_was_compound = compound_types.indexOf(vm.oldField) !== -1; | |
|
11932 | 11935 | |
|
11933 | 11936 | if (!new_is_compound) { |
|
11934 | 11937 | vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0]; |
@@ -1031,6 +1031,38 b' class TestRulesParsing():' | |||
|
1031 | 1031 | |
|
1032 | 1032 | @pytest.mark.usefixtures('report_type_matrix') |
|
1033 | 1033 | class TestNestedRuleParsing(): |
|
1034 | ||
|
1035 | @pytest.mark.parametrize("data, result", [ | |
|
1036 | ({"http_status": 501, "group": {"priority": 7, "occurences": 11}}, | |
|
1037 | False), | |
|
1038 | ({"http_status": 101, "group": {"priority": 7, "occurences": 11}}, | |
|
1039 | False), | |
|
1040 | ({"http_status": 500, "group": {"priority": 1, "occurences": 11}}, | |
|
1041 | False), | |
|
1042 | ({"http_status": 101, "group": {"priority": 3, "occurences": 5}}, | |
|
1043 | True), | |
|
1044 | ]) | |
|
1045 | def test_NOT_rule(self, data, result, report_type_matrix): | |
|
1046 | from appenlight.lib.rule import Rule | |
|
1047 | rule_config = { | |
|
1048 | "field": "__NOT__", | |
|
1049 | "rules": [ | |
|
1050 | { | |
|
1051 | "op": "ge", | |
|
1052 | "field": "group:occurences", | |
|
1053 | "value": "10" | |
|
1054 | }, | |
|
1055 | { | |
|
1056 | "op": "ge", | |
|
1057 | "field": "group:priority", | |
|
1058 | "value": "4" | |
|
1059 | } | |
|
1060 | ] | |
|
1061 | } | |
|
1062 | ||
|
1063 | rule = Rule(rule_config, report_type_matrix) | |
|
1064 | assert rule.match(data) is result | |
|
1065 | ||
|
1034 | 1066 | @pytest.mark.parametrize("data, result", [ |
|
1035 | 1067 | ({"http_status": 501, "group": {"priority": 7, "occurences": 11}}, |
|
1036 | 1068 | True), |
@@ -716,7 +716,7 b' def build_rule_schema(ruleset, check_matrix):' | |||
|
716 | 716 | schema = colander.SchemaNode(colander.Mapping()) |
|
717 | 717 | schema.add(colander.SchemaNode(colander.String(), name='field')) |
|
718 | 718 | |
|
719 | if ruleset['field'] in ['__AND__', '__OR__']: | |
|
719 | if ruleset['field'] in ['__AND__', '__OR__', '__NOT__']: | |
|
720 | 720 | subrules = colander.SchemaNode(colander.Tuple(), name='rules') |
|
721 | 721 | for rule in ruleset['rules']: |
|
722 | 722 | subrules.add(build_rule_schema(rule, check_matrix)) |
@@ -70,6 +70,7 b' function AlertChannelsController(userSelfPropertyResource, applicationsNoIdResou' | |||
|
70 | 70 | var possibleFields = { |
|
71 | 71 | '__AND__': 'All met (composite rule)', |
|
72 | 72 | '__OR__': 'One met (composite rule)', |
|
73 | '__NOT__': 'Not met (composite rule)', | |
|
73 | 74 | 'http_status': 'HTTP Status', |
|
74 | 75 | 'duration': 'Request duration', |
|
75 | 76 | 'group:priority': 'Group -> Priority', |
@@ -61,6 +61,7 b" angular.module('appenlight.directives.postProcessAction', []).directive('postPro" | |||
|
61 | 61 | var possibleFields = { |
|
62 | 62 | '__AND__': 'All met (composite rule)', |
|
63 | 63 | '__OR__': 'One met (composite rule)', |
|
64 | '__NOT__': 'Not met (composite rule)', | |
|
64 | 65 | 'http_status': 'HTTP Status', |
|
65 | 66 | 'duration': 'Request duration', |
|
66 | 67 | 'group:priority': 'Group -> Priority', |
@@ -56,8 +56,9 b" angular.module('appenlight.directives.rule', []).directive('rule', function () {" | |||
|
56 | 56 | }; |
|
57 | 57 | |
|
58 | 58 | vm.fieldChange = function () { |
|
59 |
var |
|
|
60 |
var |
|
|
59 | var compound_types = ['__AND__', '__OR__', '__NOT__']; | |
|
60 | var new_is_compound = compound_types.indexOf(vm.rule.field) !== -1; | |
|
61 | var old_was_compound = compound_types.indexOf(vm.oldField) !== -1; | |
|
61 | 62 | |
|
62 | 63 | if (!new_is_compound) { |
|
63 | 64 | vm.rule.op = vm.ruleDefinitions.fieldOps[vm.rule.field][0]; |
@@ -7,7 +7,7 b'' | |||
|
7 | 7 | ng-options="key as label for (key, label) in rule_ctrlr.ruleDefinitions.possibleFields"></select> |
|
8 | 8 | </div> |
|
9 | 9 | |
|
10 | <div ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'" class="form-group"> | |
|
10 | <div ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'" class="form-group"> | |
|
11 | 11 | |
|
12 | 12 | <select ng-model="rule_ctrlr.rule.op" class="form-control" |
|
13 | 13 | ng-change="rule_ctrlr.setDirty()" |
@@ -18,7 +18,7 b'' | |||
|
18 | 18 | |
|
19 | 19 | </div> |
|
20 | 20 | |
|
21 | <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'"> | |
|
21 | <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'"> | |
|
22 | 22 | <p ng-if="parent"><strong>Subrules</strong></p> |
|
23 | 23 | <div ng-repeat="subrule in rule_ctrlr.rule.rules" class="m-l-2"> |
|
24 | 24 | <div class="panel panel-default"> |
@@ -4,11 +4,11 b'' | |||
|
4 | 4 | {{rule_ctrlr.readOnlyPossibleFields[rule_ctrlr.rule.field]}} |
|
5 | 5 | </span> |
|
6 | 6 | |
|
7 | <span ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__'"> | |
|
7 | <span ng-if="rule_ctrlr.rule.field != '__AND__' && rule_ctrlr.rule.field !='__OR__' && rule_ctrlr.rule.field !='__NOT__'"> | |
|
8 | 8 | is {{rule_ctrlr.ruleDefinitions.allOps[rule_ctrlr.rule.op]}} {{rule_ctrlr.rule.value}} |
|
9 | 9 | </span> |
|
10 | 10 | |
|
11 | <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__'"> | |
|
11 | <span ng-if="rule_ctrlr.rule.field == '__AND__' || rule_ctrlr.rule.field =='__OR__' || rule_ctrlr.rule.field =='__NOT__'"> | |
|
12 | 12 | <p ng-if="parent"><strong>Subrules</strong></p> |
|
13 | 13 | <div ng-repeat="subrule in rule_ctrlr.rule.rules" class="m-l-2"> |
|
14 | 14 |
General Comments 0
You need to be logged in to leave comments.
Login now