class Incident(Model): __core__ = True objects = IncidentManager() organization = FlexibleForeignKey('sentry.Organization') projects = models.ManyToManyField( 'sentry.Project', related_name='incidents', through=IncidentProject, ) groups = models.ManyToManyField( 'sentry.Group', related_name='incidents', through=IncidentGroup, ) # Incrementing id that is specific to the org. identifier = models.IntegerField() # Identifier used to match incoming events from the detection algorithm detection_uuid = UUIDField(null=True, db_index=True) status = models.PositiveSmallIntegerField() title = models.TextField() # Query used to fetch events related to an incident query = models.TextField() # When we suspect the incident actually started date_started = models.DateTimeField(default=timezone.now) # When we actually detected the incident date_detected = models.DateTimeField(default=timezone.now) date_added = models.DateTimeField(default=timezone.now) date_closed = models.DateTimeField(null=True) class Meta: app_label = 'sentry' db_table = 'sentry_incident' unique_together = (('organization', 'identifier'), )
class MonitorCheckIn(Model): __core__ = False guid = UUIDField(unique=True, auto_add=True) project_id = BoundedPositiveIntegerField(db_index=True) monitor = FlexibleForeignKey("sentry.Monitor") location = FlexibleForeignKey("sentry.MonitorLocation", null=True) status = BoundedPositiveIntegerField(default=0, choices=CheckInStatus.as_choices()) config = EncryptedJsonField(default=dict) duration = BoundedPositiveIntegerField(null=True) date_added = models.DateTimeField(default=timezone.now) date_updated = models.DateTimeField(default=timezone.now) objects = BaseManager(cache_fields=("guid", )) class Meta: app_label = "sentry" db_table = "sentry_monitorcheckin" __repr__ = sane_repr("guid", "project_id", "status") def save(self, *args, **kwargs): if not self.date_added: self.date_added = timezone.now() if not self.date_updated: self.date_updated = self.date_added return super().save(*args, **kwargs) # XXX(dcramer): BaseModel is trying to automatically set date_updated which is not # what we want to happen, so kill it here def _update_timestamps(self): pass
class Incident(Model): __core__ = True objects = IncidentManager() organization = FlexibleForeignKey('sentry.Organization') projects = models.ManyToManyField( 'sentry.Project', related_name='incidents', through=IncidentProject, ) groups = models.ManyToManyField( 'sentry.Group', related_name='incidents', through=IncidentGroup, ) alert_rule = models.ForeignKey( 'sentry.AlertRule', null=True, on_delete=models.SET_NULL, ) # Incrementing id that is specific to the org. identifier = models.IntegerField() # Identifier used to match incoming events from the detection algorithm detection_uuid = UUIDField(null=True, db_index=True) status = models.PositiveSmallIntegerField( default=IncidentStatus.OPEN.value) type = models.PositiveSmallIntegerField(default=IncidentType.CREATED.value) title = models.TextField() # Query used to fetch events related to an incident query = models.TextField() # When we suspect the incident actually started date_started = models.DateTimeField(default=timezone.now) # When we actually detected the incident date_detected = models.DateTimeField(default=timezone.now) date_added = models.DateTimeField(default=timezone.now) date_closed = models.DateTimeField(null=True) class Meta: app_label = 'sentry' db_table = 'sentry_incident' unique_together = (('organization', 'identifier'), ) @property def current_end_date(self): """ Returns the current end of the incident. Either the date it was closed, or the current time if it's still open. """ return self.date_closed if self.date_closed else timezone.now() @property def duration(self): return self.current_end_date - self.date_started
class SentryAppComponent(Model): __core__ = True uuid = UUIDField(unique=True, auto_add=True) sentry_app = FlexibleForeignKey("sentry.SentryApp", related_name="components") type = models.CharField(max_length=64) schema = EncryptedJsonField() class Meta: app_label = "sentry" db_table = "sentry_sentryappcomponent"
class Incident(Model): __core__ = True objects = IncidentManager() organization = FlexibleForeignKey("sentry.Organization") projects = models.ManyToManyField("sentry.Project", related_name="incidents", through=IncidentProject) groups = models.ManyToManyField("sentry.Group", related_name="incidents", through=IncidentGroup) alert_rule = FlexibleForeignKey("sentry.AlertRule", null=True, on_delete=models.SET_NULL) # Incrementing id that is specific to the org. identifier = models.IntegerField() # Identifier used to match incoming events from the detection algorithm detection_uuid = UUIDField(null=True, db_index=True) status = models.PositiveSmallIntegerField( default=IncidentStatus.OPEN.value) status_method = models.PositiveSmallIntegerField( default=IncidentStatusMethod.RULE_TRIGGERED.value) type = models.PositiveSmallIntegerField() aggregation = models.PositiveSmallIntegerField( default=QueryAggregations.TOTAL.value) title = models.TextField() # Query used to fetch events related to an incident query = models.TextField() # When we suspect the incident actually started date_started = models.DateTimeField(default=timezone.now) # When we actually detected the incident date_detected = models.DateTimeField(default=timezone.now) date_added = models.DateTimeField(default=timezone.now) date_closed = models.DateTimeField(null=True) class Meta: app_label = "sentry" db_table = "sentry_incident" unique_together = (("organization", "identifier"), ) index_together = (("alert_rule", "type", "status"), ) @property def current_end_date(self): """ Returns the current end of the incident. Either the date it was closed, or the current time if it's still open. """ return self.date_closed if self.date_closed else timezone.now() @property def duration(self): return self.current_end_date - self.date_started
class MonitorLocation(Model): __core__ = True guid = UUIDField(unique=True, auto_add=True) name = models.CharField(max_length=128) date_added = models.DateTimeField(default=timezone.now) objects = BaseManager(cache_fields=('guid', )) class Meta: app_label = 'sentry' db_table = 'sentry_monitorlocation' __repr__ = sane_repr('guid', 'name')
class MonitorLocation(Model): __include_in_export__ = True guid = UUIDField(unique=True, auto_add=True) name = models.CharField(max_length=128) date_added = models.DateTimeField(default=timezone.now) objects = BaseManager(cache_fields=("guid", )) class Meta: app_label = "sentry" db_table = "sentry_monitorlocation" __repr__ = sane_repr("guid", "name")
class MonitorCheckIn(Model): __core__ = True guid = UUIDField(unique=True, auto_add=True) project_id = BoundedPositiveIntegerField(db_index=True) monitor = FlexibleForeignKey('sentry.Monitor') location = FlexibleForeignKey('sentry.MonitorLocation', null=True) status = BoundedPositiveIntegerField( default=0, choices=CheckInStatus.as_choices(), ) config = EncryptedJsonField(default=dict) duration = BoundedPositiveIntegerField(null=True) date_added = models.DateTimeField(default=timezone.now) date_updated = models.DateTimeField(default=timezone.now) objects = BaseManager(cache_fields=('guid', )) class Meta: app_label = 'sentry' db_table = 'sentry_monitorcheckin' __repr__ = sane_repr('guid', 'project_id', 'status')
class Monitor(Model): __core__ = True guid = UUIDField(unique=True, auto_add=True) organization_id = BoundedPositiveIntegerField(db_index=True) project_id = BoundedPositiveIntegerField(db_index=True) name = models.CharField(max_length=128) status = BoundedPositiveIntegerField(default=MonitorStatus.ACTIVE, choices=MonitorStatus.as_choices()) type = BoundedPositiveIntegerField( default=MonitorType.UNKNOWN, choices=[(k, six.text_type(v)) for k, v in MonitorType.as_choices()], ) config = EncryptedJsonField(default=dict) next_checkin = models.DateTimeField(null=True) last_checkin = models.DateTimeField(null=True) date_added = models.DateTimeField(default=timezone.now) class Meta: app_label = "sentry" db_table = "sentry_monitor" index_together = (("type", "next_checkin"), ) __repr__ = sane_repr("guid", "project_id", "name") def get_schedule_type_display(self): return ScheduleType.get_name( self.config.get("schedule_type", ScheduleType.CRONTAB)) def get_audit_log_data(self): return { "name": self.name, "type": self.type, "status": self.status, "config": self.config } def get_next_scheduled_checkin(self, last_checkin=None): if last_checkin is None: last_checkin = self.last_checkin tz = pytz.timezone(self.config.get("timezone") or "UTC") schedule_type = self.config.get("schedule_type", ScheduleType.CRONTAB) base_datetime = last_checkin.astimezone(tz) next_checkin = get_next_schedule(base_datetime, schedule_type, self.config["schedule"]) return next_checkin + timedelta( minutes=int(self.config.get("checkin_margin") or 0)) def mark_failed(self, last_checkin=None, reason=MonitorFailure.UNKNOWN): from sentry.coreapi import insert_data_to_database_legacy from sentry.event_manager import EventManager from sentry.models import Project from sentry.signals import monitor_failed if last_checkin is None: next_checkin_base = timezone.now() last_checkin = self.last_checkin or timezone.now() else: next_checkin_base = last_checkin affected = (type(self).objects.filter( Q(last_checkin__lte=last_checkin) | Q(last_checkin__isnull=True), id=self.id).update( next_checkin=self.get_next_scheduled_checkin( next_checkin_base), status=MonitorStatus.ERROR, last_checkin=last_checkin, )) if not affected: return False event_manager = EventManager( { "logentry": { "message": "Monitor failure: %s (%s)" % (self.name, reason) }, "contexts": { "monitor": get_monitor_context(self) }, "fingerprint": ["monitor", six.text_type(self.guid), reason], }, project=Project(id=self.project_id), ) event_manager.normalize() data = event_manager.get_data() insert_data_to_database_legacy(data) monitor_failed.send(monitor=self, sender=type(self)) return True
class Monitor(Model): __core__ = True guid = UUIDField(unique=True, auto_add=True) organization_id = BoundedPositiveIntegerField(db_index=True) project_id = BoundedPositiveIntegerField(db_index=True) name = models.CharField(max_length=128) status = BoundedPositiveIntegerField( default=MonitorStatus.ACTIVE, choices=MonitorStatus.as_choices(), ) type = BoundedPositiveIntegerField( default=MonitorType.UNKNOWN, choices=MonitorType.as_choices(), ) config = EncryptedJsonField(default=dict) next_checkin = models.DateTimeField(null=True) last_checkin = models.DateTimeField(null=True) date_added = models.DateTimeField(default=timezone.now) class Meta: app_label = 'sentry' db_table = 'sentry_monitor' index_together = (('type', 'next_checkin'), ) __repr__ = sane_repr('guid', 'project_id', 'name') def get_audit_log_data(self): return { 'name': self.name, 'type': self.type, 'status': self.status, 'config': self.config, } def get_next_scheduled_checkin(self, last_checkin=None): if last_checkin is None: last_checkin = self.last_checkin tz = pytz.timezone(self.config.get('timezone') or 'UTC') schedule_type = self.config.get('schedule_type', ScheduleType.CRONTAB) base_datetime = last_checkin.astimezone(tz) next_checkin = get_next_schedule(base_datetime, schedule_type, self.config['schedule']) return next_checkin + timedelta( minutes=int(self.config.get('checkin_margin') or 0)) def mark_failed(self, last_checkin=None): from sentry.coreapi import ClientApiHelper from sentry.event_manager import EventManager from sentry.models import Project from sentry.signals import monitor_failed if last_checkin is None: next_checkin_base = timezone.now() last_checkin = self.last_checkin else: next_checkin_base = last_checkin affected = type(self).objects.filter( id=self.id, last_checkin=self.last_checkin, ).update( next_checkin=self.get_next_scheduled_checkin(next_checkin_base), status=MonitorStatus.ERROR, last_checkin=last_checkin, ) if not affected: return False event_manager = EventManager( { 'logentry': { 'message': 'Monitor failure: %s' % (self.name, ), }, 'contexts': { 'monitor': { 'id': six.text_type(self.guid), }, }, }, project=Project(id=self.project_id), ) event_manager.normalize() data = event_manager.get_data() helper = ClientApiHelper(project_id=self.project_id) helper.insert_data_to_database(data) monitor_failed.send(monitor=self, sender=type(self)) return True