def test_subprocess_invalid_args(sentry_init): sentry_init(integrations=[StdlibIntegration()]) with pytest.raises(TypeError) as excinfo: subprocess.Popen(1) assert "'int' object is not iterable" in str(excinfo.value)
def test_crumb_capture_hint(sentry_init, capture_events): def before_breadcrumb(crumb, hint): if "httplib_response" in hint: con = hint["httplib_response"].getheader("Connection") assert con.lower() == "close" crumb["data"]["extra"] = "foo" return crumb sentry_init(integrations=[StdlibIntegration()], before_breadcrumb=before_breadcrumb) events = capture_events() url = "https://httpbin.org/status/200" response = urlopen(url) assert response.getcode() == 200 capture_message("Testing!") event, = events crumb, = event["breadcrumbs"] assert crumb["type"] == "http" assert crumb["category"] == "httplib" assert crumb["data"] == { "url": url, "method": "GET", "status_code": 200, "reason": "OK", "extra": "foo", } if platform.python_implementation() != "PyPy": assert sys.getrefcount(response) == 2
def test_subprocess_invalid_args(sentry_init): sentry_init(integrations=[StdlibIntegration()]) with pytest.raises(TypeError) as excinfo: subprocess.Popen() if PY2: assert "__init__() takes at least 2 arguments (1 given)" in str(excinfo.value) else: assert "missing 1 required positional argument: 'args" in str(excinfo.value)
def test_crumb_capture(sentry_init, capture_events): sentry_init(integrations=[StdlibIntegration()]) events = capture_events() response = requests.get("https://httpbin.org/status/418") capture_message("Testing!") (event, ) = events (crumb, ) = event["breadcrumbs"]["values"] assert crumb["type"] == "http" assert crumb["category"] == "httplib" assert crumb["data"] == { "url": "https://httpbin.org/status/418", "method": "GET", "status_code": response.status_code, "reason": response.reason, }
def test_crumb_capture(sentry_init, capture_events): sentry_init(integrations=[StdlibIntegration()]) events = capture_events() url = "https://httpbin.org/status/200" response = urlopen(url) assert response.getcode() == 200 capture_message("Testing!") event, = events crumb, = event["breadcrumbs"] assert crumb["type"] == "http" assert crumb["category"] == "httplib" assert crumb["data"] == { "url": url, "method": "GET", "status_code": 200, "reason": "OK", }
def test_crumb_capture(sentry_init, capture_events): sentry_init(integrations=[StdlibIntegration()]) events = capture_events() response = requests.get("https://httpbin.org/status/418") assert response.status_code == 418 capture_message("Testing!") event, = events crumb, = event["breadcrumbs"] assert crumb["type"] == "http" assert crumb["category"] == "httplib" assert crumb["data"] == { "url": "https://httpbin.org/status/418", "method": "GET", "status_code": 418, "reason": "I'M A TEAPOT", "httplib_response": crumb["data"]["httplib_response"], }
def configure_extensions(): log.debug("Configuring extensions...") if SENTRY_DSN: sentry_sdk.init( dsn=str(SENTRY_DSN), integrations=[ sentry_logging, AioHttpIntegration(), SqlalchemyIntegration(), StdlibIntegration(), ExcepthookIntegration(), DedupeIntegration(), AtexitIntegration(), ModulesIntegration(), ], environment=ENV, ) with sentry_sdk.configure_scope() as scope: log.debug(f"Using the following tags... ENV_TAGS: {ENV_TAGS}") for k, v in ENV_TAGS.items(): scope.set_tag(k, v)
def _sentry_client( disabled: bool = False, ) -> sentry_sdk.Client: """ Initialize sentry. You can override the default values with the following env vars: 1. CORTEX_TELEMETRY_SENTRY_DSN 2. CORTEX_TELEMETRY_SENTRY_ENVIRONMENT 3. CORTEX_TELEMETRY_DISABLE """ dsn = CORTEX_TELEMETRY_SENTRY_DSN environment = CORTEX_TELEMETRY_SENTRY_ENVIRONMENT if disabled or os.getenv("CORTEX_TELEMETRY_DISABLE", "").lower() == "true": return if os.getenv("CORTEX_TELEMETRY_SENTRY_DSN", "") != "": dsn = os.environ["CORTEX_TELEMETRY_SENTRY_DSN"] if os.getenv("CORTEX_TELEMETRY_SENTRY_ENVIRONMENT", "") != "": environment = os.environ["CORTEX_TELEMETRY_SENTRY_ENVIRONMENT"] client = sentry_sdk.Client( dsn=dsn, environment=environment, release=CORTEX_VERSION, ignore_errors=[CortexBinaryException], # exclude CortexBinaryException exceptions in_app_include=["cortex"], # for better grouping of events in sentry attach_stacktrace=True, default_integrations=False, # disable all default integrations auto_enabling_integrations=False, integrations=[ DedupeIntegration(), # prevent duplication of events StdlibIntegration(), # adds breadcrumbs (aka more info) ModulesIntegration(), # adds info about installed modules ], # debug=True, ) return client
def test_subprocess_basic(sentry_init, capture_events, monkeypatch): monkeypatch.setenv("FOO", "bar") old_environ = dict(os.environ) sentry_init(integrations=[StdlibIntegration()], traces_sample_rate=1.0) with Hub.current.span(transaction="foo", op="foo") as span: output = subprocess.check_output( [ sys.executable, "-c", "import os; " "import sentry_sdk; " "from sentry_sdk.integrations.stdlib import get_subprocess_traceparent_headers; " "sentry_sdk.init(); " "assert os.environ['FOO'] == 'bar'; " "print(dict(get_subprocess_traceparent_headers()))", ] ) assert os.environ == old_environ assert span.trace_id in str(output) events = capture_events() capture_message("hi") event, = events crumb, = event["breadcrumbs"] assert crumb == { "category": "subprocess", "data": {}, "timestamp": crumb["timestamp"], "type": "subprocess", }
def test_subprocess_basic( sentry_init, capture_events, monkeypatch, positional_args, iterator, env_mapping, with_cwd, ): monkeypatch.setenv("FOO", "bar") old_environ = dict(os.environ) sentry_init(integrations=[StdlibIntegration()], traces_sample_rate=1.0) events = capture_events() with Hub.current.start_span(transaction="foo", op="foo") as span: args = [ sys.executable, "-c", "import os; " "import sentry_sdk; " "from sentry_sdk.integrations.stdlib import get_subprocess_traceparent_headers; " "sentry_sdk.init(); " "assert os.environ['FOO'] == 'bar'; " "print(dict(get_subprocess_traceparent_headers()))", ] if iterator: args = iter(args) if positional_args: a = ( args, 0, # bufsize None, # executable None, # stdin subprocess.PIPE, # stdout None, # stderr None, # preexec_fn False, # close_fds False, # shell os.getcwd() if with_cwd else None, # cwd ) if env_mapping is not None: a += (env_mapping, ) popen = subprocess.Popen(*a) else: kw = {"args": args, "stdout": subprocess.PIPE} if with_cwd: kw["cwd"] = os.getcwd() if env_mapping is not None: kw["env"] = env_mapping popen = subprocess.Popen(**kw) output, unused_err = popen.communicate() retcode = popen.poll() assert not retcode assert os.environ == old_environ assert span.trace_id in str(output) capture_message("hi") transaction_event, message_event, = events assert message_event["message"] == "hi" data = {"subprocess.cwd": os.getcwd()} if with_cwd else {} crumb, = message_event["breadcrumbs"] assert crumb == { "category": "subprocess", "data": data, "timestamp": crumb["timestamp"], "type": "subprocess", } assert transaction_event["type"] == "transaction" subprocess_span, = transaction_event["spans"] assert subprocess_span["data"] == data if iterator: assert "iterator" in subprocess_span["description"] assert subprocess_span["description"].startswith("<") else: assert sys.executable + " -c" in subprocess_span["description"]
from sentry_sdk.integrations.dedupe import DedupeIntegration from sentry_sdk.integrations.stdlib import StdlibIntegration from sentry_sdk.integrations.modules import ModulesIntegration from sentry_sdk.integrations.argv import ArgvIntegration from helpdesk.config import SENTRY_DSN logger = logging.getLogger(__name__) _client = Client( dsn=SENTRY_DSN, default_integrations=False, integrations=[ ExcepthookIntegration(), DedupeIntegration(), StdlibIntegration(), ModulesIntegration(), ArgvIntegration(), ], max_breadcrumbs=5, attach_stacktrace=True, ) _hub = Hub(_client) def report(msg=None, **kw): if not _hub: return try: extra = kw.pop('extra', {})
def main(): logging.info('main') app = QApplication(sys.argv) app.setQuitOnLastWindowClosed(False) appctxt = AppContext(app) sentry_sdk.init( "https://[email protected]/5210435", shutdown_timeout=5, default_integrations=False, # Either pyqt or pyinstaller do weird things with sentry, # need to explicitely specify these else sentry fails integrations=[ LoggingIntegration(), StdlibIntegration(), ExcepthookIntegration(), DedupeIntegration(), AtexitIntegration(), ModulesIntegration(), ArgvIntegration(), ThreadingIntegration(), ]) instance = SingleInstance() print('instance', instance) logger = get_logging(appctxt.build_settings['debug']) build_msg = "Production" if appctxt.is_frozen else "Development" logger.info( f"PWUploader, version: {appctxt.build_settings['version']}, {build_msg} build" ) logging.debug(f'config {CONFIG.as_dict()}') signal.signal(signal.SIGINT, signal.SIG_DFL) logo_path = appctxt.get_resource('logo.png') logging.debug(f'logo_path: {logo_path}') icon = QIcon(logo_path) tray = QSystemTrayIcon() tray.setIcon(icon) logging.debug('tray: %s', tray) tray.show() menu = QMenu() # left-click should just open the menu too def on_systray_activated(reason): if reason == 3: menu.popup(QCursor.pos()) tray.activated.connect(on_systray_activated) action0 = QAction(f"Version: v{appctxt.build_settings['version']}") menu.addAction(action0) action2 = QAction('settings') action2.triggered.connect(on_settings(appctxt)) menu.addAction(action2) action3 = QAction('resync files') def connect_missing_files(): upload_missing_files(appctxt, remote_config) action3.triggered.connect(connect_missing_files) menu.addAction(action3) action4 = QAction('open log dir') action4.triggered.connect(on_open_logdir) menu.addAction(action4) def toggle_always_running(state): if state: CONFIG.set('always_running', True) start_guardian_detached() else: CONFIG.set('always_running', False) kill_guardian() with open(CONFIG_FILE, 'w') as f: f.write(json.dumps(CONFIG.as_dict(), indent=2)) logging.info('config saved') action5 = QAction('always running', checkable=True) if CONFIG.get('always_running'): action5.setChecked(True) action5.triggered.connect(toggle_always_running) menu.addAction(action5) action1 = QAction("quit") action1.triggered.connect(on_quit) menu.addAction(action1) tray.setContextMenu(menu) # FIXME get this after app display if possible for i in range(10): api = PWAPI(appctxt, appctxt.build_settings['api_url'], CONFIG.get('api_token'), CONFIG.get('account_id')) remote_config = api.get_config() if 'detail' in remote_config: logging.error('Invalid remote config %s', remote_config) message = 'Unable to reach Pathology Watch API for authentication, are your API Token & Lab ID correct? Click ok to open settings.' response = QtWidgets.QMessageBox.question( None, 'API Error', message, QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Cancel) if response == QtWidgets.QMessageBox.Cancel: sys.exit(0) settings_dialog = SettingsDialog(appctxt, CONFIG, CONFIG_FILE) settings_dialog.ui.setWindowModality(QtCore.Qt.ApplicationModal) settings_dialog.ui.exec_() else: break time.sleep(1) if remote_config is not None: clean_remote_config = { k: v for k, v in remote_config.items() if 'secret' not in k } logging.debug(f'remote_config {clean_remote_config}') # TODO verify remote_config if it's not set, check api token or pw connectivity else: logging.error( 'Uploader settings invalid or server isn\'t configured, contact [email protected]' ) sys.exit(1) # FIXME need to validate remote_config, config logging.info('Starting upload watcher') watcher_thread = WatcherThread(CONFIG.get('watch_dir'), trigger_upload) watcher_thread.finished.connect(app.exit) watcher_thread.start() logging.info('Starting heartbeat thread') heartbeat_thread = HeartbeatThread(appctxt, remote_config, CONFIG, upload_missing_files) heartbeat_thread.finished.connect(app.exit) heartbeat_thread.start() worker_threads = [] for i in range(appctxt.build_settings['n_upload_worker_threads']): logging.info(f'Starting worker {i}') worker_thread = WorkerThread(appctxt, remote_config, CONFIG, UPLOAD_QUEUE) worker_thread.finished.connect(app.exit) worker_thread.start() worker_threads.append(worker_thread) #def excepthook(exc_type, exc_value, exc_tb): # import traceback # tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb)) # logging.error("error caught: %s", str(tb)) # capture_exception(exc_type) #sys.excepthook = excepthook exit_code = -1 delay = 2 for i in range(5): logging.info('Starting') exit_code = app.exec_() if exit_code == 0: break logging.info(f'Exit loop {exit_code}, sleeping {delay}') time.sleep(delay) delay = delay**2 logging.info(f'Exited: {exit_code}') sys.exit(exit_code)