Exemple #1
0
def test_config():
    sha = "4de21f8ea228a082d4f039c0c991ee41dfb6f9d8"
    try:
        Config.set(revision_sha=sha)
        assert scout_config.value("revision_sha") == sha
    finally:
        scout_config.reset_all()
def app_with_scout(redis_conn, scout_config=None):
    """
    Context manager that configures a Huey app with Scout installed.
    """
    # Enable Scout by default in tests.
    if scout_config is None:
        scout_config = {}
    scout_config.setdefault("monitor", True)
    scout_config["core_agent_launch"] = False

    # Reset global state
    scout_apm.rq.install_attempted = False
    scout_apm.rq.installed = None

    # Setup according to https://docs.scoutapm.com/#rq
    # Using job_class argument to Queue
    Config.set(**scout_config)
    queue = Queue(name="myqueue", connection=redis_conn)
    worker = scout_apm.rq.SimpleWorker([queue], connection=queue.connection)

    App = namedtuple("App", ["queue", "worker"])
    try:
        yield App(queue=queue, worker=worker)
    finally:
        Config.reset_all()
Exemple #3
0
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"SCOUT_MONITOR": True}

    # Disable running the agent.
    config["SCOUT_CORE_AGENT_LAUNCH"] = False

    # Setup according to http://help.apm.scoutapp.com/#django
    with override_settings(**config):
        # Prevent durable changes to MIDDLEWARE and MIDDLEWARE_CLASSES by
        # replacing them with a copy of their value.
        for name in ["MIDDLEWARE", "MIDDLEWARE_CLASSES"]:
            try:
                value = getattr(settings, name)
            except AttributeError:
                pass
            else:
                setattr(settings, name, value)
        # Scout settings must be overridden before inserting scout_apm.django
        # in INSTALLED_APPS because ScoutApmDjangoConfig.ready() accesses it.
        with modify_settings(INSTALLED_APPS={"prepend": "scout_apm.django"}):
            try:
                # Django initializes middleware when in creates the WSGI app.
                # Modifying MIDDLEWARE setting has no effect on the app.
                # Create a new WSGI app to account for the new middleware
                # that "scout_apm.django" injected.
                yield get_wsgi_application()
            finally:
                # Reset Scout configuration.
                Config.reset_all()
Exemple #4
0
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"SCOUT_MONITOR": True}

    # Disable running the agent.
    config["SCOUT_CORE_AGENT_LAUNCH"] = False

    # Setup according to http://help.apm.scoutapp.com/#flask
    scout = ScoutApm(app)
    for key, value in config.items():
        app.config[key] = value
    try:
        yield app
    finally:
        # Restore original configuration.
        assert app.before_first_request_funcs == [scout.before_first_request]
        assert app.before_request_funcs == {None: [scout.process_request]}
        assert app.after_request_funcs == {None: [scout.process_response]}
        assert app.dispatch_request == scout.dispatch_request
        del app.before_first_request_funcs[:]
        del app.before_request_funcs[None][:]
        del app.after_request_funcs[None][:]
        del app.dispatch_request
        # Reset Scout configuration.
        Config.reset_all()
Exemple #5
0
def app_with_scout(app=None, config=None):
    """
    Context manager that configures a Celery app with Scout installed.
    """
    if app is None:
        app = celery.Celery("tasks", broker="memory://")

    # Enable Scout by default in tests.
    if config is None:
        config = {"monitor": True}

    # Disable running the agent.
    config["core_agent_launch"] = False

    @app.task
    def hello():
        return "Hello World!"

    # Setup according to https://docs.scoutapm.com/#celery
    Config.set(**config)
    scout_apm.celery.install()

    try:
        yield app
    finally:
        scout_apm.celery.uninstall()
        # Reset Scout configuration.
        Config.reset_all()
Exemple #6
0
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"scout.monitor": True}

    # Disable running the agent.
    config["scout.core_agent_launch"] = False

    # Save a reference to the original configuration and make changes in a copy.
    app_config = app.config.copy()

    # Setup according to http://help.apm.scoutapp.com/#bottle
    app.config.update(config)
    scout = ScoutPlugin()
    app.install(scout)
    try:
        yield app
    finally:
        # Restore original configuration and clear all caches.
        app.config = app_config
        app.reset()
        # Reset Scout configuration.
        Config.reset_all()
Exemple #7
0
def app_with_scout(*, app=None, scout_config=None):
    """
    Context manager that configures and installs the Scout plugin for a basic
    Starlette application.
    """
    if scout_config is None:
        scout_config = {}

    scout_config["core_agent_launch"] = False
    scout_config.setdefault("monitor", True)

    if app is None:
        app = Starlette()

    @app.exception_handler(500)
    async def error(request, exc):
        # Always raise exceptions
        raise exc

    @app.route("/")
    async def home(request):
        return PlainTextResponse("Welcome home.")

    @app.route("/hello/")
    class HelloEndpoint(HTTPEndpoint):
        async def get(self, request):
            return PlainTextResponse("Hello World!")

    @app.route("/crash/")
    async def crash(request):
        raise ValueError("BØØM!")  # non-ASCII

    @app.route("/background-jobs/")
    async def background_jobs(request):
        def sync_noop():
            pass

        async def async_noop():
            pass

        tasks = BackgroundTasks()
        tasks.add_task(sync_noop)
        tasks.add_task(async_noop)

        return PlainTextResponse("Triggering background jobs",
                                 background=tasks)

    # As per http://docs.scoutapm.com/#starlette
    Config.set(**scout_config)
    app.add_middleware(ScoutMiddleware)

    try:
        yield app
    finally:
        Config.reset_all()
Exemple #8
0
def test_shutdown_message_disabled(capsys):
    report_app_metadata()  # queued but thread not running
    try:
        scout_config.set(shutdown_timeout_seconds=0.1, shutdown_message_enabled=False)

        shutdown()
    finally:
        Config.reset_all()

    captured = capsys.readouterr()
    assert not captured.err
Exemple #9
0
def test_shutdown(capsys):
    scout_config
    report_app_metadata()  # queued but thread not running
    try:
        scout_config.set(shutdown_timeout_seconds=0.1)

        shutdown()
    finally:
        Config.reset_all()

    captured = capsys.readouterr()
    assert "Scout draining" in captured.err
Exemple #10
0
def test_install_success(caplog):
    with mock.patch.object(CoreAgentManager, "launch"):
        try:
            installed = install(config={"monitor": True})
        finally:
            Config.reset_all()

    assert installed is True
    assert (
        "scout_apm.core",
        logging.DEBUG,
        "APM Launching on PID: %s" % os.getpid(),
    ) in caplog.record_tuples
Exemple #11
0
def test_install_fail_monitor_false(caplog):
    try:
        installed = install(config={"monitor": False})
    finally:
        Config.reset_all()

    assert installed is False
    assert (
        "scout_apm.core",
        logging.INFO,
        ("APM Not Launching on PID: %s - Configuration 'monitor' is not true" %
         os.getpid()),
    ) in caplog.record_tuples
Exemple #12
0
def app_with_scout(config=None, middleware=None, set_api=True):
    """
    Context manager that yields a fresh Falcon app with Scout configured.
    """
    # Enable Scout by default in tests.
    if config is None:
        config = {}

    config["core_agent_launch"] = False
    config.setdefault("monitor", True)

    if middleware is None:
        middleware = ["scout"]
    scout_index = middleware.index("scout")
    assert scout_index != -1
    scout_middleware = ScoutMiddleware(config=config)
    middleware[scout_index] = scout_middleware

    app = falcon.API(middleware=middleware)
    if set_api:
        scout_middleware.set_api(app)

    class HomeResource(object):
        def on_get(self, req, resp):
            resp.status = falcon.HTTP_200
            resp.content_type = falcon.MEDIA_TEXT
            resp.body = "Welcome home."

        def on_get_suffixed(self, req, resp):
            self.on_get(req, resp)
            resp.body = "Welcome home, suffixed."

    app.add_route("/", HomeResource())
    app.add_route("/suffixed", HomeResource(), suffix="suffixed")

    class CrashResource(object):
        def on_get(self, req, resp):
            raise ValueError("BØØM!")  # non-ASCII

    app.add_route("/crash", CrashResource())

    class ErrorResource(object):
        def on_get(self, req, resp):
            raise falcon.HTTPStatus("748 Confounded by ponies")

    app.add_route("/error", ErrorResource())

    try:
        yield app
    finally:
        Config.reset_all()
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    if config is None:
        config = {}

    config["SCOUT_CORE_AGENT_LAUNCH"] = False
    config.setdefault("SCOUT_MONITOR", True)
    # Disable Flask's error page to improve debugging
    config.setdefault("PROPAGATE_EXCEPTIONS", True)

    # Basic Flask app
    app = flask.Flask("test_app")

    @app.route("/")
    def home():
        return "Welcome home."

    @app.route("/hello/",
               methods=["GET", "OPTIONS"],
               provide_automatic_options=False)
    def hello():
        if flask.request.method == "OPTIONS":
            return "Hello Options!"
        return "Hello World!"

    @app.route("/set-session/")
    def set_session():
        flask.session["session_var"] = 1
        return "Set session"

    @app.route("/crash/")
    def crash():
        raise ValueError("BØØM!")  # non-ASCII

    @app.route("/return-error/")
    def return_error():
        return "Something went wrong", 503

    # Setup according to https://docs.scoutapm.com/#flask
    ScoutApm(app)
    app.config.update(config)
    app.secret_key = "123"

    try:
        yield app
    finally:
        Config.reset_all()
def app_with_scout(scout_config=None):
    """
    Context manager that configures and installs the Scout plugin.
    """
    # Enable Scout by default in tests.
    if scout_config is None:
        scout_config = {}

    scout_config.setdefault("monitor", True)
    scout_config.setdefault("errors_enabled", True)
    Config.set(**scout_config)

    try:
        yield
    finally:
        # Reset Scout configuration.
        Config.reset_all()
def app_with_scout(config=None, catchall=False):
    """
    Context manager that configures and installs the Scout plugin for Bottle.
    """
    if config is None:
        config = {}

    # Enable Scout by default in tests.
    config.setdefault("scout.monitor", True)

    # Disable running the agent.
    config["scout.core_agent_launch"] = False

    app = Bottle(catchall=catchall)

    @app.route("/")
    def home():
        return "Welcome home."

    @app.route("/hello/")
    def hello():
        return "Hello World!"

    @app.route("/crash/")
    def crash():
        raise ValueError("BØØM!")  # non-ASCII

    @app.route("/return-error/")
    def return_error():
        response.status = 503
        return "Something went wrong"

    @app.route("/named/", name="named_route")
    def named():
        return "Response from a named route."

    # Setup according to https://docs.scoutapm.com/#bottle
    app.config.update(config)
    scout = ScoutPlugin()
    app.install(scout)

    try:
        yield app
    finally:
        # Reset Scout configuration.
        Config.reset_all()
Exemple #16
0
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {}

    config.setdefault("SCOUT_MONITOR", True)
    # Disable running the agent.
    config["SCOUT_CORE_AGENT_LAUNCH"] = False

    def home(request):
        return Response("Welcome home.")

    def hello(request):
        return Response("Hello World!")

    def crash(request):
        raise ValueError("BØØM!")  # non-ASCII

    def return_error(request):
        return Response("Something went wrong", status=503)

    with Configurator() as configurator:
        configurator.add_route("home", "/")
        configurator.add_view(home, route_name="home", request_method="GET")
        configurator.add_route("hello", "/hello/")
        configurator.add_view(hello, route_name="hello")
        configurator.add_route("crash", "/crash/")
        configurator.add_view(crash, route_name="crash")
        configurator.add_route("return_error", "/return-error/")
        configurator.add_view(return_error, route_name="return_error")

        # Setup according to https://docs.scoutapm.com/#pyramid
        configurator.add_settings(**config)
        configurator.include("scout_apm.pyramid")
        app = configurator.make_wsgi_app()

    try:
        yield app
    finally:
        # Reset Scout configuration.
        Config.reset_all()
def app_with_scout(nameko_config=None, scout_config=None):
    """
    Context manager that yields a fresh Nameko WSGI app with Scout configured.
    """
    if scout_config is None:
        scout_config = {}

    scout_config["core_agent_launch"] = False
    scout_config.setdefault("monitor", True)
    Config.set(**scout_config)

    class Service(object):
        name = "myservice"

        scout = ScoutReporter()

        @http("GET", "/")
        def home(self, request):
            return "Welcome home."

        @http("GET", "/crash/")
        def crash(self, request):
            raise ValueError("BØØM!")  # non-ASCII

    if nameko_config is None:
        nameko_config = {}
    # Container setup copied from Nameko's container_factory pytest fixture,
    # which we don't use - see pytest.ini
    container_cls = get_container_cls(nameko_config)
    container = container_cls(Service, nameko_config)
    try:
        container.start()

        # A bit of introspection to look inside the container and pull out the WSGI
        # app
        app = list(container.subextensions)[0].get_wsgi_app()

        # N.B. We're sidestepping the Nameko testing conventions
        # (https://docs.nameko.io/en/stable/testing.html) to make our tests more
        # uniform between frameworks

        yield app
    finally:
        container.kill()
        Config.reset_all()
Exemple #18
0
def load_scout_apm(app, db, celery=False):
    logger = _get_logger(app, celery)
    try:
        if celery:
            import scout_apm.celery
            from scout_apm.api import Config
            Config.set(key=app.config['SCOUT_KEY'],
                       monitor=app.config['SCOUT_MONITOR'],
                       name=app.config['SCOUT_NAME'])
            scout_apm.celery.install()
        else:
            from scout_apm.flask import ScoutApm
            from scout_apm.flask.sqlalchemy import instrument_sqlalchemy
            ScoutApm(app)
            instrument_sqlalchemy(db)
    except ImportError:
        logger.warning('Scout APM modules not found')
    else:
        logger.info('Scout APM initialized')
Exemple #19
0
def app_with_scout(scout_config=None):
    """
    Context manager that configures and installs the Scout plugin for CherryPy.
    """
    if scout_config is None:
        scout_config = {}

    scout_config["core_agent_launch"] = False
    scout_config.setdefault("monitor", True)
    Config.set(**scout_config)

    class Views(object):
        @cherrypy.expose
        def index(self, **params):  # Take all params so CherryPy doesn't 404
            return "Welcome home."

        @cherrypy.expose
        def hello(self):
            return "Hello World!"

        @cherrypy.expose
        def crash(self):
            raise ValueError("BØØM!")  # non-ASCII

        @cherrypy.expose
        def return_error(self):
            cherrypy.response.status = 503
            return "Something went wrong"

        # Serve this source file statically
        static_file = cherrypy.tools.staticfile.handler(__file__)

    app = cherrypy.Application(Views(), "/", config=None)

    # Setup according to https://docs.scoutapm.com/#cherrypy
    plugin = ScoutPlugin(cherrypy.engine)
    plugin.subscribe()

    try:
        yield app
    finally:
        plugin.unsubscribe()
        Config.reset_all()
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"SCOUT_MONITOR": True}

    # Disable running the agent.
    config["SCOUT_CORE_AGENT_LAUNCH"] = False

    # Basic Flask app
    app = flask.Flask("test_app")
    # Enable the following for debugging exceptions:
    # app.config["PROPAGATE_EXCEPTIONS"] = True

    @app.route("/")
    def home():
        return "Welcome home."

    @app.route("/hello/",
               methods=["GET", "OPTIONS"],
               provide_automatic_options=False)
    def hello():
        if flask.request.method == "OPTIONS":
            return "Hello Options!"
        return "Hello World!"

    @app.route("/crash/")
    def crash():
        raise ValueError("BØØM!")  # non-ASCII

    # Setup according to https://docs.scoutapm.com/#flask
    ScoutApm(app)
    app.config.update(config)

    try:
        yield app
    finally:
        Config.reset_all()
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"monitor": True}

    # Disable running the agent.
    config["core_agent_launch"] = False

    # Setup according to https://docs.scoutapm.com/#celery
    Config.set(**config)
    scout_apm.celery.install()
    try:
        yield app
    finally:
        scout_apm.celery.uninstall()
        # Reset Scout configuration.
        Config.reset_all()
Exemple #22
0
def app_with_scout(config=None):
    """
    Context manager that configures a Dramatiq app with Scout middleware
    installed.
    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"monitor": True}

    # Disable running the agent.
    config["core_agent_launch"] = False

    broker = StubBroker()
    broker.emit_after("process_boot")
    dramatiq.set_broker(broker)

    @dramatiq.actor(max_retries=0)
    def hello():
        return "Hello World!"

    @dramatiq.actor(max_retries=0)
    def fail():
        raise ValueError("BØØM!")  # non-ASCII

    worker = dramatiq.Worker(broker, worker_timeout=0)

    # Setup according to https://docs.scoutapm.com/#dramatiq
    Config.set(**config)
    broker.add_middleware(ScoutMiddleware(),
                          before=broker.middleware[0].__class__)
    worker.start()

    App = namedtuple("App", ["broker", "worker", "hello", "fail"])
    try:
        yield App(broker=broker, worker=worker, hello=hello, fail=fail)
    finally:
        worker.stop()
        # Reset Scout configuration.
        Config.reset_all()
Exemple #23
0
def app_with_scout(config=None):
    """
    Context manager that configures and installs the Scout plugin for Bottle.

    """
    # Enable Scout by default in tests.
    if config is None:
        config = {"SCOUT_MONITOR": True}

    # Disable running the agent.
    config["SCOUT_CORE_AGENT_LAUNCH"] = False

    # Setup according to https://docs.scoutapm.com/#pyramid
    with app_configurator() as configurator:
        configurator.add_settings(**config)
        configurator.include("scout_apm.pyramid")
        app = configurator.make_wsgi_app()
    try:
        yield app
    finally:
        # Reset Scout configuration.
        Config.reset_all()
Exemple #24
0
def app_with_scout(scout_config=None):
    """
    Context manager that configures a Huey app with Scout installed.
    """
    # Enable Scout by default in tests.
    if scout_config is None:
        scout_config = {}
    scout_config.setdefault("monitor", True)
    scout_config["core_agent_launch"] = False

    huey = MemoryHuey(immediate=True)

    @huey.task()
    @huey.lock_task("hello")
    def hello():
        return "Hello World!"

    @huey.task()
    def retry_once():
        if not retry_once._did_retry:
            retry_once._did_retry = True
            raise RetryTask()
        return "Done."

    retry_once._did_retry = False

    @huey.task()
    def fail():
        raise ValueError("BØØM!")  # non-ASCII

    # Setup according to https://docs.scoutapm.com/#huey
    Config.set(**scout_config)
    attach_scout(huey)

    App = namedtuple("App", ["huey", "hello", "retry_once", "fail"])
    try:
        yield App(huey=huey, hello=hello, retry_once=retry_once, fail=fail)
    finally:
        Config.reset_all()
Exemple #25
0
def test_application_root():
    """
    A BASE_DIR setting is mapped to the application_root config parameter.

    Django doesn't have a BASE_DIR setting. However the default project
    template creates it in order to define other settings. As a consequence,
    most Django projets have it.

    """
    base_dir = os.path.dirname(__file__)
    with override_settings(BASE_DIR=base_dir):
        with app_with_scout():
            assert Config().value("application_root") == base_dir
Exemple #26
0
def app_with_scout(scout_config=None):
    """
    Context manager that yields the global Hug app with Scout configured.
    """
    global scout_integrated

    if scout_config is None:
        scout_config = {}

    scout_config["core_agent_launch"] = False
    scout_config.setdefault("monitor", True)
    Config.set(**scout_config)

    if not scout_integrated:
        integrate_scout(__name__, config={})
        scout_integrated = True

    try:
        # Hug attaches magic names to the current module when you use the @hug
        # decorators, we're interested in the WSGI app:
        yield __hug_wsgi__  # noqa: F821
    finally:
        Config.reset_all()
Exemple #27
0
    sentry_sdk.init(
        sentry_url,
        environment=_config["env"],
        integrations=[SqlalchemyIntegration(),
                      AioHttpIntegration()],
        release=f"{{ cookiecutter.package_name }}@{app_version}",
    )
    app.add_middleware(SentryAsgiMiddleware)

if scout_config := _config.get("scout"):  # pragma: no cover
    from scout_apm.api import Config
    from scout_apm.async_.starlette import ScoutMiddleware

    Config.set(
        key=scout_config["key"],
        name=f"{{ cookiecutter.package_name }} {_config['env'].capitalize()}",
        monitor=True,
        revision_sha=app_version,
    )
    app.add_middleware(ScoutMiddleware)

_secure_headers = SecureHeaders()
app.add_middleware(
    CORSMiddleware,
    allow_origins="*",
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
app.add_middleware(GZipMiddleware)

def test_on_setting_changed_monitor():
    with app_with_scout(SCOUT_MONITOR=True):
        assert Config().value("monitor") is True
    assert Config().value("monitor") is False
def test_on_setting_changed_application_root():
    with app_with_scout(BASE_DIR="/tmp/foobar"):
        assert Config().value("application_root") == "/tmp/foobar"
    assert Config().value("application_root") == ""
Exemple #30
0
    def index(self, **params):
        return "Welcome home."

    @cherrypy.expose
    def hello(self, name="World"):
        return f"Hello {name}!"

    @cherrypy.expose
    def crash(self):
        raise ValueError("BØØM!")

    @cherrypy.expose
    def return_error(self):
        cherrypy.response.status = 503
        return "Something went wrong"


app = cherrypy.Application(Views(), "/", config=None)

# https://docs.scoutapm.com/#cherrypy
Config.set(
    monitor=True,
    key=os.environ["SCOUT_KEY"],
    name="Test CherryPy App",
)
plugin = ScoutPlugin(cherrypy.engine)
plugin.subscribe()

if __name__ == '__main__':
    cherrypy.quickstart(Views())