Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import contextlib | 5 import contextlib |
| 6 import datetime | 6 import datetime |
| 7 import datetime_encoder | 7 import datetime_encoder |
| 8 import json | 8 import json |
| 9 import logging | 9 import logging |
| 10 import urllib | 10 import urllib |
| 11 import webapp2 | 11 import webapp2 |
| 12 import zlib | 12 import zlib |
| 13 | 13 |
| 14 import cloudstorage as gcs | 14 import cloudstorage as gcs |
| 15 | 15 |
| 16 from google.appengine.api import app_identity | 16 from google.appengine.api import app_identity |
| 17 from google.appengine.api import memcache | 17 from google.appengine.api import memcache |
| 18 from google.appengine.api import modules | |
| 19 from google.appengine.api import urlfetch | |
| 18 from google.appengine.api import users | 20 from google.appengine.api import users |
| 19 from google.appengine.datastore import datastore_query | 21 from google.appengine.datastore import datastore_query |
| 20 from google.appengine.ext import ndb | 22 from google.appengine.ext import ndb |
| 21 | 23 |
| 22 LOGGER = logging.getLogger(__name__) | 24 LOGGER = logging.getLogger(__name__) |
| 23 | 25 |
| 24 | 26 |
| 25 class AlertsJSON(ndb.Model): | 27 class AlertsJSON(ndb.Model): |
| 26 type = ndb.StringProperty() | 28 type = ndb.StringProperty() |
| 27 json = ndb.BlobProperty(compressed=True) | 29 json = ndb.BlobProperty(compressed=True) |
| 28 date = ndb.DateTimeProperty(auto_now_add=True) | 30 date = ndb.DateTimeProperty(auto_now_add=True) |
| 29 # TODO(remove this property) | 31 # TODO(remove this property) |
| 30 use_gcs = ndb.BooleanProperty() | 32 use_gcs = ndb.BooleanProperty() |
| 31 gcs_filename = ndb.StringProperty() | 33 gcs_filename = ndb.StringProperty() |
| 32 | 34 |
| 33 | 35 |
| 34 class LastUpdated(ndb.Model): | 36 class LastUpdated(ndb.Model): |
| 35 date = ndb.DateTimeProperty(auto_now=True) | 37 date = ndb.DateTimeProperty(auto_now=True) |
| 36 type = ndb.StringProperty() | 38 type = ndb.StringProperty() |
| 37 haddiff = ndb.BooleanProperty() | 39 haddiff = ndb.BooleanProperty() |
| 38 | 40 |
| 39 | 41 |
| 42 def increment_monarch(endpoint): | |
|
agable
2015/08/10 23:04:37
Might be nice to implement this somewhere more gen
| |
| 43 base_url = app_identity.get_default_version_hostname() | |
| 44 url = 'http://%s-dot-%s/monitoring/%s' % ('monitoring', base_url, endpoint) | |
| 45 logging.info(url) | |
|
agable
2015/08/10 23:04:37
Log a more useful message here :) or nothing at al
| |
| 46 return urlfetch.fetch(url=url, method=urlfetch.GET) | |
|
agable
2015/08/10 23:04:37
Using GET here makes me a very sad panda. You neve
jshu
2015/08/11 21:57:18
lol yea put didn't work either. ok.
| |
| 47 | |
| 48 | |
| 40 class AlertsHandler(webapp2.RequestHandler): | 49 class AlertsHandler(webapp2.RequestHandler): |
| 41 ALERT_TYPE = 'alerts' | 50 ALERT_TYPE = 'alerts' |
| 42 # Max number of bytes that AppEngine allows writing to Memcache | 51 # Max number of bytes that AppEngine allows writing to Memcache |
| 43 MAX_JSON_SIZE = 10**6 - 10**5 | 52 MAX_JSON_SIZE = 10**6 - 10**5 |
| 44 | 53 |
| 45 # New alerts should be posted at least every 30 minutes | 54 # New alerts should be posted at least every 30 minutes |
| 46 MAX_STALENESS = 60*30 | 55 MAX_STALENESS = 60*30 |
| 47 | 56 |
| 48 # Has no 'response' member. | 57 # Has no 'response' member. |
| 49 # pylint: disable=E1101 | 58 # pylint: disable=E1101 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 def get_from_memcache(self): | 126 def get_from_memcache(self): |
| 118 compressed = memcache.get(self.ALERT_TYPE) | 127 compressed = memcache.get(self.ALERT_TYPE) |
| 119 if compressed: | 128 if compressed: |
| 120 logging.info('Reading alerts from memcache') | 129 logging.info('Reading alerts from memcache') |
| 121 uncompressed = zlib.decompress(compressed) | 130 uncompressed = zlib.decompress(compressed) |
| 122 data = json.loads(uncompressed) | 131 data = json.loads(uncompressed) |
| 123 return data | 132 return data |
| 124 return False | 133 return False |
| 125 | 134 |
| 126 def get(self): | 135 def get(self): |
| 136 increment_monarch('alerts') | |
| 127 data = self.get_from_memcache() or self.get_from_datastore() | 137 data = self.get_from_memcache() or self.get_from_datastore() |
| 128 if data: | 138 if data: |
| 129 self.send_json_data(data) | 139 self.send_json_data(data) |
| 130 else: | 140 else: |
| 131 self.response.write({}) | 141 self.response.write({}) |
| 132 | 142 |
| 133 def store_alerts(self, alerts): | 143 def store_alerts(self, alerts): |
| 134 last_entry = self.get_last_datastore(self.ALERT_TYPE) | 144 last_entry = self.get_last_datastore(self.ALERT_TYPE) |
| 135 last_alerts = {} | 145 last_alerts = {} |
| 136 if last_entry: | 146 if last_entry: |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 188 alerts.update({'date': datetime.datetime.utcnow()}) | 198 alerts.update({'date': datetime.datetime.utcnow()}) |
| 189 self.store_alerts(alerts) | 199 self.store_alerts(alerts) |
| 190 | 200 |
| 191 def post(self): | 201 def post(self): |
| 192 self.update_alerts() | 202 self.update_alerts() |
| 193 | 203 |
| 194 | 204 |
| 195 class NewAlertsHandler(AlertsHandler): | 205 class NewAlertsHandler(AlertsHandler): |
| 196 # pylint: disable=arguments-differ | 206 # pylint: disable=arguments-differ |
| 197 def get(self, tree): | 207 def get(self, tree): |
| 208 increment_monarch('api/v1/alerts') | |
| 198 self.ALERT_TYPE = 'new-alerts/%s' % tree | 209 self.ALERT_TYPE = 'new-alerts/%s' % tree |
| 199 super(NewAlertsHandler, self).get() | 210 super(NewAlertsHandler, self).get() |
| 200 | 211 |
| 201 # pylint: disable=arguments-differ | 212 # pylint: disable=arguments-differ |
| 202 def post(self, tree): | 213 def post(self, tree): |
| 203 self.ALERT_TYPE = 'new-alerts/%s' % tree | 214 self.ALERT_TYPE = 'new-alerts/%s' % tree |
| 204 super(NewAlertsHandler, self).post() | 215 super(NewAlertsHandler, self).post() |
| 205 | 216 |
| 206 | 217 |
| 207 app = webapp2.WSGIApplication([ | 218 app = webapp2.WSGIApplication([ |
| 208 ('/alerts', AlertsHandler), | 219 ('/alerts', AlertsHandler), |
| 209 ('/api/v1/alerts/(.*)', NewAlertsHandler) | 220 ('/api/v1/alerts/(.*)', NewAlertsHandler) |
| 210 ]) | 221 ]) |
| OLD | NEW |