示例#1
0
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)
示例#2
0
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,
    }
示例#5
0
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",
    }
示例#6
0
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"],
    }
示例#7
0
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)
示例#8
0
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"]
示例#11
0
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', {})
示例#12
0
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)