def test_message_with_culprit(): def gen(message, culprit): return { "sentry.interfaces.Message": { "message": message, "params": [], "formatted": message }, "culprit": culprit, "message": message } # sentry-php client v1.5.0 passes culprit=null if culprit not generated by client hash1 = hash_for_grouping(gen('message 1', None)) hash2 = hash_for_grouping(gen('message 2', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping(gen('message', None)) hash2 = hash_for_grouping(gen('message', None)) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping(gen('message 1', 'http://domain.com/path.php')) hash2 = hash_for_grouping(gen('message 2', 'http://domain.com/path.php')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping(gen('message', 'http://domain.com/path.php')) hash2 = hash_for_grouping(gen('message', 'http://domain.com/path.php')) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping(gen('message', 'http://domain.com/path1.php')) hash2 = hash_for_grouping(gen('message', 'http://domain.com/path2.php')) expect(hash1).not_to_equal(hash2)
def test_exception_with_stacktrace(): def gen(exception_message, exception_type, function_in_context, culprit): pre_context = [ "function %s() {" % function_in_context, "throw new Exception(CONST_VAL);", "}" ] post_context = [ "} catch (Exception $e) {", "$client->captureException($e);", "}" ] return { "exception": { "values": [{ "stacktrace": { "frames": [{ "function": None, "pre_context": pre_context, "post_context": post_context, "filename": "test.php", "lineno": 1, "context_line": "a();" }] }, "type": exception_type, "value": exception_message }] }, "culprit": culprit } # sentry-php client v1.5.0 passes culprit=null if culprit not generated by client hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionA', None)) expect(hash1).to_equal(hash2) # is stacktrace is present and has non empty frames sentry uses it and ignores exception message hash1 = hash_for_grouping( gen('exception message 1', 'Exception', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message 2', 'Exception', 'functionA', None)) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionB', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'Exception1', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message', 'Exception2', 'functionA', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message 1', 'Exception', 'functionA', 'culprit 1')) hash2 = hash_for_grouping( gen('exception message 2', 'Exception', 'functionA', 'culprit 2')) expect(hash1).to_equal(hash2)
def test_exception_with_sentry_interfaces_on_nodejs(): def gen(exception_message, exception_type, function_in_context): return { "sentry.interfaces.Exception": { "type": exception_type, "value": exception_message }, "sentry.interfaces.Stacktrace": { "frames": [{ "function": function_in_context, "in_app": False, "lineno": 456, "module": "" }] } } hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionA')) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionB')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'ExceptionA', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'ExceptionB ', 'functionA')) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping( gen('exception message 1', 'ExceptionA', 'functionA')) hash2 = hash_for_grouping( gen('exception message 2', 'ExceptionA ', 'functionA')) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'ExceptionA', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'ExceptionB ', 'functionA')) expect(hash1).to_equal(hash2)
def test_exception_with_sentry_interfaces_on_php(): def gen(exception_message, exception_type, function_in_stacktrace): return { "sentry.interfaces.Exception": { "values": [{ "type": exception_type, "module": "/some/path", "value": exception_message, "stacktrace": { "frames": [{ "function": function_in_stacktrace, "abs_path": "", "pre_context": [], "post_context": [], "module": "", "filename": "", "lineno": 1, "context_line": "" }] } }] }, "sentry.interfaces.Stacktrace": { "frames": [{ "function": function_in_stacktrace, "abs_path": "", "lineno": 456, "module": "" }] } } hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionA')) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionB')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'ExceptionA', 'functionA')) hash2 = hash_for_grouping( gen('exception message', 'ExceptionB', 'functionA')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message 1', 'Exception', 'functionA')) hash2 = hash_for_grouping( gen('exception message 2', 'Exception', 'functionA')) expect(hash1).to_equal(hash2)
def test_message_without_culprit(): def gen(message): return { "sentry.interfaces.Message": { "message": message, "params": [], "formatted": message }, "message": message } hash1 = hash_for_grouping(gen('message 1')) hash2 = hash_for_grouping(gen('message 2')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping(gen('message')) hash2 = hash_for_grouping(gen('message')) expect(hash1).to_equal(hash2)
def backend_request(self, project_id=None): auth = self.request.headers.get('X-Sentry-Auth') if not auth: self._404() return sentry_key = SENTRY_KEY.search(auth) if not sentry_key: self._404() return sentry_key = sentry_key.groups()[0] sentry_secret = SENTRY_SECRET.search(auth) if not sentry_secret: self._404() return sentry_secret = sentry_secret.groups()[0] if project_id is None: project_id = self.get_project_id(sentry_key, sentry_secret) else: project_id = int(project_id) if self.application.config.RESTRICT_API_ACCESS: if project_id is None or not self.are_valid_keys( project_id, sentry_key, sentry_secret): self._404() return base_url = self.application.config.SENTRY_BASE_URL.replace( 'http://', '').replace('https://', '') base_url = "%s://%s:%s@%s" % (self.request.protocol, sentry_key, sentry_secret, base_url) url = "%s%s?%s" % (base_url, self.request.path, self.request.query) try: payload = loads(decompress(self.request.body, MAX_WBITS | 32)) except ValueError: payload = loads(self.request.body) message_key = hash_for_grouping(payload) cache_key = "%s:%s" % (project_id, message_key) count = self.validate_cache(cache_key) if count > self.application.config.MAX_CACHE_USES: return self.set_header("X-CYCLOPS-CACHE-COUNT", str(count)) self.set_header("X-CYCLOPS-STATUS", "PROCESSED") self.application.processed_items += 1 self.process_request(project_id, url)
def test_exception_with_empty_stacktrace(): def gen_empty_stacktrace(exception_message, exception_type, culprit): return { "exception": { "values": [{ "type": exception_type, "value": exception_message }] }, "culprit": culprit } # sentry doesn't have this logic, it's cyclops-specific, cyclops uses exception message for grouping hash1 = hash_for_grouping( gen_empty_stacktrace('exception message', 'Exception1', None)) hash2 = hash_for_grouping( gen_empty_stacktrace('exception message', 'Exception2', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen_empty_stacktrace('exception message 1', 'Exception', None)) hash2 = hash_for_grouping( gen_empty_stacktrace('exception message 2', 'Exception', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen_empty_stacktrace('exception message', 'Exception', 'culrpit 1')) hash2 = hash_for_grouping( gen_empty_stacktrace('exception message', 'Exception', 'culprit 2')) expect(hash1).to_equal(hash2)
def test_exception_with_sentry_interfaces_on_php_and_empty_frames(): def gen(exception_message, exception_type): return { "sentry.interfaces.Exception": { "values": [{ "type": exception_type, "module": "/some/path", "value": exception_message, "stacktrace": { "frames": [] } }] }, "sentry.interfaces.Stacktrace": { "frames": [] } } hash1 = hash_for_grouping(gen('exception message', 'Exception')) hash2 = hash_for_grouping(gen('exception message', 'Exception')) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping(gen('exception message', 'ExceptionA')) hash2 = hash_for_grouping(gen('exception message', 'ExceptionB')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping(gen('exception message 1', 'Exception')) hash2 = hash_for_grouping(gen('exception message 2', 'Exception')) expect(hash1).not_to_equal(hash2)
def test_message_with_stacktrace(): def gen(message, function_in_stacktrace): return { "stacktrace": { "frames": [{ "function": function_in_stacktrace, "filename": "file", "in_app": "true", "colno": 1, "lineno": 1 }] }, "message": message } hash1 = hash_for_grouping(gen('message', 'functionA')) hash2 = hash_for_grouping(gen('message', 'functionB')) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping(gen('message 1', 'functionA')) hash2 = hash_for_grouping(gen('message 2', 'functionA')) expect(hash1).to_equal(hash2)
def backend_request(self, project_id=None): auth = self.request.headers.get('X-Sentry-Auth') if not auth: self._404() return sentry_key = SENTRY_KEY.search(auth) if not sentry_key: self._404() return sentry_key = sentry_key.groups()[0] sentry_secret = SENTRY_SECRET.search(auth) if not sentry_secret: self._404() return sentry_secret = sentry_secret.groups()[0] if project_id is None: project_id = self.get_project_id(sentry_key, sentry_secret) else: project_id = int(project_id) if self.application.config.RESTRICT_API_ACCESS: if project_id is None or not self.are_valid_keys(project_id, sentry_key, sentry_secret): self._404() return base_url = self.application.config.SENTRY_BASE_URL.replace('http://', '').replace('https://', '') base_url = "%s://%s:%s@%s" % (self.request.protocol, sentry_key, sentry_secret, base_url) url = "%s%s?%s" % (base_url, self.request.path, self.request.query) try: payload = loads(self.request.body) except ValueError: payload = loads(decompress(b64decode(self.request.body))) message_key = hash_for_grouping(payload) cache_key = "%s:%s" % (project_id, message_key) count = self.validate_cache(cache_key) if count > self.application.config.MAX_CACHE_USES: return self.set_header("X-CYCLOPS-CACHE-COUNT", str(count)) self.set_header("X-CYCLOPS-STATUS", "PROCESSED") self.application.processed_items += 1 self.process_request(project_id, url)
def test_exception_with_stacktrace_old_node_format(): def gen(exception_message, exception_type, function_in_context, culprit): return { "exception": [{ "type": exception_type, "value": exception_message, "stacktrace": { "frames": [{ "function": function_in_context, "filename": "test.php", "lineno": 1, "module": "node" }] } }], "culprit": culprit } hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionA', None)) expect(hash1).to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'Exception', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message', 'Exception', 'functionB', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message', 'ExceptionA', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message', 'ExceptionB', 'functionA', None)) expect(hash1).not_to_equal(hash2) hash1 = hash_for_grouping( gen('exception message 1', 'Exception', 'functionA', None)) hash2 = hash_for_grouping( gen('exception message 2', 'Exception', 'functionA', None)) expect(hash1).to_equal(hash2)