##// END OF EJS Templates
Convert "message" searches to boolean "and" instead of "or" queries.
cmoyer -
Show More
@@ -1,207 +1,213 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # AppEnlight Enterprise Edition, including its added features, Support
18 # AppEnlight Enterprise Edition, including its added features, Support
19 # services, and proprietary license terms, please see
19 # services, and proprietary license terms, please see
20 # https://rhodecode.com/licenses/
20 # https://rhodecode.com/licenses/
21
21
22 import paginate
22 import paginate
23 import logging
23 import logging
24 import sqlalchemy as sa
24 import sqlalchemy as sa
25
25
26 from appenlight.models.log import Log
26 from appenlight.models.log import Log
27 from appenlight.models import get_db_session, Datastores
27 from appenlight.models import get_db_session, Datastores
28 from appenlight.models.services.base import BaseService
28 from appenlight.models.services.base import BaseService
29 from appenlight.lib.utils import es_index_name_limiter
29 from appenlight.lib.utils import es_index_name_limiter
30
30
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33
33
34 class LogService(BaseService):
34 class LogService(BaseService):
35 @classmethod
35 @classmethod
36 def get_logs(cls, resource_ids=None, filter_settings=None,
36 def get_logs(cls, resource_ids=None, filter_settings=None,
37 db_session=None):
37 db_session=None):
38 # ensure we always have id's passed
38 # ensure we always have id's passed
39 if not resource_ids:
39 if not resource_ids:
40 # raise Exception('No App ID passed')
40 # raise Exception('No App ID passed')
41 return []
41 return []
42 db_session = get_db_session(db_session)
42 db_session = get_db_session(db_session)
43 q = db_session.query(Log)
43 q = db_session.query(Log)
44 q = q.filter(Log.resource_id.in_(resource_ids))
44 q = q.filter(Log.resource_id.in_(resource_ids))
45 if filter_settings.get('start_date'):
45 if filter_settings.get('start_date'):
46 q = q.filter(Log.timestamp >= filter_settings.get('start_date'))
46 q = q.filter(Log.timestamp >= filter_settings.get('start_date'))
47 if filter_settings.get('end_date'):
47 if filter_settings.get('end_date'):
48 q = q.filter(Log.timestamp <= filter_settings.get('end_date'))
48 q = q.filter(Log.timestamp <= filter_settings.get('end_date'))
49 if filter_settings.get('log_level'):
49 if filter_settings.get('log_level'):
50 q = q.filter(
50 q = q.filter(
51 Log.log_level == filter_settings.get('log_level').upper())
51 Log.log_level == filter_settings.get('log_level').upper())
52 if filter_settings.get('request_id'):
52 if filter_settings.get('request_id'):
53 request_id = filter_settings.get('request_id', '')
53 request_id = filter_settings.get('request_id', '')
54 q = q.filter(Log.request_id == request_id.replace('-', ''))
54 q = q.filter(Log.request_id == request_id.replace('-', ''))
55 if filter_settings.get('namespace'):
55 if filter_settings.get('namespace'):
56 q = q.filter(Log.namespace == filter_settings.get('namespace'))
56 q = q.filter(Log.namespace == filter_settings.get('namespace'))
57 q = q.order_by(sa.desc(Log.timestamp))
57 q = q.order_by(sa.desc(Log.timestamp))
58 return q
58 return q
59
59
60 @classmethod
60 @classmethod
61 def es_query_builder(cls, app_ids, filter_settings):
61 def es_query_builder(cls, app_ids, filter_settings):
62 if not filter_settings:
62 if not filter_settings:
63 filter_settings = {}
63 filter_settings = {}
64
64
65 query = {
65 query = {
66 "query": {
66 "query": {
67 "filtered": {
67 "filtered": {
68 "filter": {
68 "filter": {
69 "and": [{"terms": {"resource_id": list(app_ids)}}]
69 "and": [{"terms": {"resource_id": list(app_ids)}}]
70 }
70 }
71 }
71 }
72 }
72 }
73 }
73 }
74
74
75 start_date = filter_settings.get('start_date')
75 start_date = filter_settings.get('start_date')
76 end_date = filter_settings.get('end_date')
76 end_date = filter_settings.get('end_date')
77 filter_part = query['query']['filtered']['filter']['and']
77 filter_part = query['query']['filtered']['filter']['and']
78
78
79 for tag in filter_settings.get('tags', []):
79 for tag in filter_settings.get('tags', []):
80 tag_values = [v.lower() for v in tag['value']]
80 tag_values = [v.lower() for v in tag['value']]
81 key = "tags.%s.values" % tag['name'].replace('.', '_')
81 key = "tags.%s.values" % tag['name'].replace('.', '_')
82 filter_part.append({"terms": {key: tag_values}})
82 filter_part.append({"terms": {key: tag_values}})
83
83
84 date_range = {"range": {"timestamp": {}}}
84 date_range = {"range": {"timestamp": {}}}
85 if start_date:
85 if start_date:
86 date_range["range"]["timestamp"]["gte"] = start_date
86 date_range["range"]["timestamp"]["gte"] = start_date
87 if end_date:
87 if end_date:
88 date_range["range"]["timestamp"]["lte"] = end_date
88 date_range["range"]["timestamp"]["lte"] = end_date
89 if start_date or end_date:
89 if start_date or end_date:
90 filter_part.append(date_range)
90 filter_part.append(date_range)
91
91
92 levels = filter_settings.get('level')
92 levels = filter_settings.get('level')
93 if levels:
93 if levels:
94 filter_part.append({"terms": {'log_level': levels}})
94 filter_part.append({"terms": {'log_level': levels}})
95 namespaces = filter_settings.get('namespace')
95 namespaces = filter_settings.get('namespace')
96 if namespaces:
96 if namespaces:
97 filter_part.append({"terms": {'namespace': namespaces}})
97 filter_part.append({"terms": {'namespace': namespaces}})
98
98
99 request_ids = filter_settings.get('request_id')
99 request_ids = filter_settings.get('request_id')
100 if request_ids:
100 if request_ids:
101 filter_part.append({"terms": {'request_id': request_ids}})
101 filter_part.append({"terms": {'request_id': request_ids}})
102
102
103 messages = filter_settings.get('message')
103 messages = filter_settings.get('message')
104 if messages:
104 if messages:
105 query['query']['filtered']['query'] = {
105 query['query']['filtered']['query'] = {
106 'match': {"message": ' '.join(messages)}}
106 'match': {
107 'message': {
108 'query': ' '.join(messages),
109 'operator': 'and'
110 }
111 }
112 }
107 return query
113 return query
108
114
109 @classmethod
115 @classmethod
110 def get_time_series_aggregate(cls, app_ids=None, filter_settings=None):
116 def get_time_series_aggregate(cls, app_ids=None, filter_settings=None):
111 if not app_ids:
117 if not app_ids:
112 return {}
118 return {}
113 es_query = cls.es_query_builder(app_ids, filter_settings)
119 es_query = cls.es_query_builder(app_ids, filter_settings)
114 es_query["aggs"] = {
120 es_query["aggs"] = {
115 "events_over_time": {
121 "events_over_time": {
116 "date_histogram": {
122 "date_histogram": {
117 "field": "timestamp",
123 "field": "timestamp",
118 "interval": "1h",
124 "interval": "1h",
119 "min_doc_count": 0
125 "min_doc_count": 0
120 }
126 }
121 }
127 }
122 }
128 }
123 log.debug(es_query)
129 log.debug(es_query)
124 index_names = es_index_name_limiter(filter_settings.get('start_date'),
130 index_names = es_index_name_limiter(filter_settings.get('start_date'),
125 filter_settings.get('end_date'),
131 filter_settings.get('end_date'),
126 ixtypes=['logs'])
132 ixtypes=['logs'])
127 if index_names:
133 if index_names:
128 results = Datastores.es.search(
134 results = Datastores.es.search(
129 es_query, index=index_names, doc_type='log', size=0)
135 es_query, index=index_names, doc_type='log', size=0)
130 else:
136 else:
131 results = []
137 results = []
132 return results
138 return results
133
139
134 @classmethod
140 @classmethod
135 def get_search_iterator(cls, app_ids=None, page=1, items_per_page=50,
141 def get_search_iterator(cls, app_ids=None, page=1, items_per_page=50,
136 order_by=None, filter_settings=None, limit=None):
142 order_by=None, filter_settings=None, limit=None):
137 if not app_ids:
143 if not app_ids:
138 return {}, 0
144 return {}, 0
139
145
140 es_query = cls.es_query_builder(app_ids, filter_settings)
146 es_query = cls.es_query_builder(app_ids, filter_settings)
141 sort_query = {
147 sort_query = {
142 "sort": [
148 "sort": [
143 {"timestamp": {"order": "desc"}}
149 {"timestamp": {"order": "desc"}}
144 ]
150 ]
145 }
151 }
146 es_query.update(sort_query)
152 es_query.update(sort_query)
147 log.debug(es_query)
153 log.debug(es_query)
148 es_from = (page - 1) * items_per_page
154 es_from = (page - 1) * items_per_page
149 index_names = es_index_name_limiter(filter_settings.get('start_date'),
155 index_names = es_index_name_limiter(filter_settings.get('start_date'),
150 filter_settings.get('end_date'),
156 filter_settings.get('end_date'),
151 ixtypes=['logs'])
157 ixtypes=['logs'])
152 if not index_names:
158 if not index_names:
153 return {}, 0
159 return {}, 0
154
160
155 results = Datastores.es.search(es_query, index=index_names,
161 results = Datastores.es.search(es_query, index=index_names,
156 doc_type='log', size=items_per_page,
162 doc_type='log', size=items_per_page,
157 es_from=es_from)
163 es_from=es_from)
158 if results['hits']['total'] > 5000:
164 if results['hits']['total'] > 5000:
159 count = 5000
165 count = 5000
160 else:
166 else:
161 count = results['hits']['total']
167 count = results['hits']['total']
162 return results['hits'], count
168 return results['hits'], count
163
169
164 @classmethod
170 @classmethod
165 def get_paginator_by_app_ids(cls, app_ids=None, page=1, item_count=None,
171 def get_paginator_by_app_ids(cls, app_ids=None, page=1, item_count=None,
166 items_per_page=50, order_by=None,
172 items_per_page=50, order_by=None,
167 filter_settings=None,
173 filter_settings=None,
168 exclude_columns=None, db_session=None):
174 exclude_columns=None, db_session=None):
169 if not filter_settings:
175 if not filter_settings:
170 filter_settings = {}
176 filter_settings = {}
171 results, item_count = cls.get_search_iterator(app_ids, page,
177 results, item_count = cls.get_search_iterator(app_ids, page,
172 items_per_page, order_by,
178 items_per_page, order_by,
173 filter_settings)
179 filter_settings)
174 paginator = paginate.Page([],
180 paginator = paginate.Page([],
175 item_count=item_count,
181 item_count=item_count,
176 items_per_page=items_per_page,
182 items_per_page=items_per_page,
177 **filter_settings)
183 **filter_settings)
178 ordered_ids = tuple(item['_source']['pg_id']
184 ordered_ids = tuple(item['_source']['pg_id']
179 for item in results.get('hits', []))
185 for item in results.get('hits', []))
180
186
181 sorted_instance_list = []
187 sorted_instance_list = []
182 if ordered_ids:
188 if ordered_ids:
183 db_session = get_db_session(db_session)
189 db_session = get_db_session(db_session)
184 query = db_session.query(Log)
190 query = db_session.query(Log)
185 query = query.filter(Log.log_id.in_(ordered_ids))
191 query = query.filter(Log.log_id.in_(ordered_ids))
186 query = query.order_by(sa.desc('timestamp'))
192 query = query.order_by(sa.desc('timestamp'))
187 sa_items = query.all()
193 sa_items = query.all()
188 # resort by score
194 # resort by score
189 for i_id in ordered_ids:
195 for i_id in ordered_ids:
190 for item in sa_items:
196 for item in sa_items:
191 if str(item.log_id) == str(i_id):
197 if str(item.log_id) == str(i_id):
192 sorted_instance_list.append(item)
198 sorted_instance_list.append(item)
193 paginator.sa_items = sorted_instance_list
199 paginator.sa_items = sorted_instance_list
194 return paginator
200 return paginator
195
201
196 @classmethod
202 @classmethod
197 def query_by_primary_key_and_namespace(cls, list_of_pairs,
203 def query_by_primary_key_and_namespace(cls, list_of_pairs,
198 db_session=None):
204 db_session=None):
199 db_session = get_db_session(db_session)
205 db_session = get_db_session(db_session)
200 list_of_conditions = []
206 list_of_conditions = []
201 query = db_session.query(Log)
207 query = db_session.query(Log)
202 for pair in list_of_pairs:
208 for pair in list_of_pairs:
203 list_of_conditions.append(sa.and_(
209 list_of_conditions.append(sa.and_(
204 Log.primary_key == pair['pk'], Log.namespace == pair['ns']))
210 Log.primary_key == pair['pk'], Log.namespace == pair['ns']))
205 query = query.filter(sa.or_(*list_of_conditions))
211 query = query.filter(sa.or_(*list_of_conditions))
206 query = query.order_by(sa.asc(Log.timestamp), sa.asc(Log.log_id))
212 query = query.order_by(sa.asc(Log.timestamp), sa.asc(Log.log_id))
207 return query
213 return query
General Comments 0
You need to be logged in to leave comments. Login now