def create_app(): get_api_settings.cache_clear() settings = get_api_settings() settings.docs_url = "/api/docs" settings.redoc_url = "/api/redoc" settings.title = "Exponea Task Api" app = FastAPI(openapi_tags=tags_metadata, **settings.fastapi_kwargs) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["GET"], allow_headers=["*"], ) api = Api(app, prefix="/api") api.add_resource(AllResponsesResource(), "/all", tags=["Exponea Test Server"]) api.add_resource(FirstResponseResource(), "/first", tags=["Exponea Test Server"]) api.add_resource( ThresholdResponsesResource(), "/within-timeout", tags=["Exponea Test Server"], ) api.add_resource(SmartResponseResource(), "/smart", tags=["Exponea Test Server"]) simplify_operation_ids(app) add_timing_middleware(app, record=log.info, prefix="/api") Instrumentator().instrument(app).expose(app) return app
def test_rounding(): app = create_app() Instrumentator(should_round_latency_decimals=True).add( metrics.latency(buckets=( 1, 2, 3, ))).instrument(app).expose(app) client = TestClient(app) get_response(client, "/") get_response(client, "/") get_response(client, "/") _ = get_response(client, "/metrics") result = REGISTRY.get_sample_value( "http_request_duration_seconds_sum", { "handler": "/", "method": "GET", "status": "2xx" }, ) entropy = calc_entropy(str(result).split(".")[1][4:]) assert entropy < 10
def test_default(): app = create_app() Instrumentator().add(metrics.default()).instrument(app).expose(app) client = TestClient(app) client.get("/", data="fefeef") client.get("/") _ = get_response(client, "/metrics") assert (REGISTRY.get_sample_value( "http_requests_total", { "handler": "/", "method": "GET", "status": "2xx" }, ) > 0) assert (REGISTRY.get_sample_value( "http_request_size_bytes_sum", {"handler": "/"}, ) > 0) assert (REGISTRY.get_sample_value( "http_response_size_bytes_sum", {"handler": "/"}, ) > 0) assert (REGISTRY.get_sample_value( "http_request_duration_highr_seconds_sum", {}, ) > 0) assert (REGISTRY.get_sample_value( "http_request_duration_seconds_sum", {"handler": "/"}, ) > 0)
def create_app(): create_logger("erudite") # Logger creation from fastapi import FastAPI if settings.dev: app = FastAPI() else: app = FastAPI(root_path="/api/erudite") from core.middleware import authorization app.add_middleware(BaseHTTPMiddleware, dispatch=authorization) Instrumentator().instrument(app).expose(app) from core.routes.rooms import router as room_router from core.routes.equipment import router as equipment_router from core.routes.disciplines import router as discipline_router from core.routes.lessons import router as lesson_router from core.routes.records import router as record_router app.include_router(room_router, tags=["rooms"]) app.include_router(equipment_router, tags=["equipment"]) app.include_router(discipline_router, tags=["disciplines"]) app.include_router(lesson_router, tags=["lessons"]) app.include_router(record_router, tags=["records"]) return app
def test_excluded_handlers_none(): app = create_app() exporter = (Instrumentator(excluded_handlers=None).add( metrics.latency()).instrument(app)) expose_metrics(app) assert len(exporter.excluded_handlers) == 0 assert isinstance(exporter.excluded_handlers, list) assert exporter.excluded_handlers is not None
def test_multiprocess_env_folder(monkeypatch, tmp_path): monkeypatch.setenv("prometheus_multiproc_dir", "DOES/NOT/EXIST") app = create_app() with pytest.raises(Exception): Instrumentator(buckets=( 1, 2, 3, )).add(metrics.latency()).instrument(app).expose(app)
def test_expose_defaults(): app = create_app() Instrumentator().instrument(app).expose(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert response.status_code == 200 assert b"http_request" in response.content
def test_should_respect_env_var_existence_exists(): app = create_app() Instrumentator(should_respect_env_var=True, env_var_name="eoioerwjioGFIUONEIO").add( metrics.latency()).instrument(app).expose(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert response.status_code == 404
def test_gzip_not_accepted(): app = create_app() Instrumentator().instrument(app).expose(app, should_gzip=False) client = TestClient(app) get_response(client, "/") get_response(client, "/") response = get_response(client, "/metrics") assert response.headers.get("Content-Encoding") is None assert int(response.headers["Content-Length"]) >= 2000
def test_gzip_accepted(): app = create_app() Instrumentator().instrument(app).expose(app, should_gzip=True) client = TestClient(app) get_response(client, "/") get_response(client, "/") response = get_response(client, "/metrics") assert response.headers["Content-Encoding"] == "gzip" assert int(response.headers["Content-Length"]) <= 2000
def test_expose_default_content_type(): reset_prometheus() app = create_app() Instrumentator().instrument(app).expose(app) client = TestClient(app) response = client.get("/metrics") print(response.headers.items()) assert ( "text/plain; version=0.0.4; charset=utf-8; charset=utf-8" not in response.headers.values() )
def test_request_size_no_cl(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.request_size()).instrument(app).expose(app) client = TestClient(app) client.get("/") response = get_response(client, "/metrics") assert b"http_request_size_bytes" in response.content assert b"http_request_size_bytes_count{" in response.content
def test_default_should_only_respect_2xx_for_highr(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.default(should_only_respect_2xx_for_highr=True)).instrument( app).expose(app) client = TestClient(app) client.get("/efefewffe", data="fefeef") client.get("/ffe04904nfiuo-ni") response = get_response(client, "/metrics") assert b"http_request_duration_highr_seconds_count 0.0" in response.content
def test_combined_size_no_labels(): app = create_app() Instrumentator().add( metrics.combined_size( should_include_handler=False, should_include_method=False, should_include_status=False, )).instrument(app) client = TestClient(app) client.get("/") assert REGISTRY.get_sample_value("http_combined_size_bytes_sum", {}) == 14
def test_metrics_endpoint_availability(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.latency()).instrument(app) expose_metrics(app) client = TestClient(app) get_response(client, "/") get_response(client, "/") response = get_response(client, "/metrics") assert_is_not_multiprocess(response) assert_request_count(2)
def test_default_without_add(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.latency()).instrument(app) expose_metrics(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert_is_not_multiprocess(response) assert_request_count(1) assert b"http_request_duration_seconds" in response.content
def test_default_with_runtime_error(): app = create_app() Instrumentator().instrument(app).expose(app) client = TestClient(app) try: get_response(client, "/runtime_error") except RuntimeError: pass response = get_response(client, "/metrics") assert (b'http_request_size_bytes_count{handler="/runtime_error"} 1.0' in response.content)
def test_custom_metric_name(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.latency(metric_name="fastapi_latency")).instrument(app) expose_metrics(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert_is_not_multiprocess(response) assert_request_count(1, name="fastapi_latency_count") assert b"fastapi_latency" in response.content assert b"http_request_duration_seconds" not in response.content
def test_expose_custom_path(): app = create_app() Instrumentator().instrument(app).expose(app, endpoint="/custom_metrics") client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert response.status_code == 404 assert b"http_request" not in response.content response = get_response(client, "/custom_metrics") assert response.status_code == 200 assert b"http_request" in response.content
def test_ungrouped_status_codes(): app = create_app() Instrumentator(should_group_status_codes=False).add( metrics.latency()).instrument(app) expose_metrics(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert_is_not_multiprocess(response) assert_request_count(1, status="200") assert b'status="2xx"' not in response.content assert b'status="200"' in response.content
def test_multiprocess_reg_is_not(monkeypatch, tmp_path): monkeypatch.setenv("prometheus_multiproc_dir", str(tmp_path)) app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.latency()).instrument(app).expose(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert response.status_code == 200 assert b"" == response.content
def test_combined_size_with_runtime_error(): app = create_app() Instrumentator().add(metrics.combined_size()).instrument(app).expose(app) client = TestClient(app) try: get_response(client, "/runtime_error") except RuntimeError: pass response = get_response(client, "/metrics") assert ( b'http_combined_size_bytes_count{handler="/runtime_error",method="GET",status="5xx"} 1.0' in response.content)
def test_bucket_without_inf(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.latency(buckets=( 1, 2, 3, ))).instrument(app).expose(app) client = TestClient(app) get_response(client, "/") response = get_response(client, "/metrics") assert_is_not_multiprocess(response) assert b"http_request_duration_seconds" in response.content
def test_request_size_all_labels(): app = create_app() Instrumentator().add(metrics.request_size()).instrument(app) client = TestClient(app) client.get("/", data="some data") assert (REGISTRY.get_sample_value( "http_request_size_bytes_sum", { "handler": "/", "method": "GET", "status": "2xx" }, ) == 9)
def test_response_size_no_labels(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.response_size( should_include_handler=False, should_include_method=False, should_include_status=False, )).instrument(app).expose(app) client = TestClient(app) client.get("/") _ = get_response(client, "/metrics") assert REGISTRY.get_sample_value("http_response_size_bytes_sum", {}) == 14
def test_excluding_handlers_regex(): app = create_app() Instrumentator(excluded_handlers=["^/$"]).add( metrics.latency()).instrument(app) expose_metrics(app) client = TestClient(app) get_response(client, "/ignore") get_response(client, "/ignore") get_response(client, "/") response = get_response(client, "/metrics") assert b'handler="/"' not in response.content assert b'handler="none"' not in response.content assert b'handler="/ignore"' in response.content
def test_grouping_untemplated(): app = create_app() Instrumentator(excluded_handlers=["/metrics"]).add( metrics.latency()).instrument(app) expose_metrics(app) client = TestClient(app) get_response(client, "/") get_response(client, "/items/678?q=43243") get_response(client, "/does_not_exist") response = get_response(client, "/metrics") assert_is_not_multiprocess(response) assert_request_count(1) assert b'handler="/does_not_exist"' not in response.content assert b'handler="none"' in response.content
def test_namespace_subsystem(): app = create_app() Instrumentator().add( metrics.request_size( should_include_handler=False, should_include_method=False, should_include_status=False, metric_namespace="namespace", metric_subsystem="subsystem", )).instrument(app).expose(app) client = TestClient(app) response = get_response(client, "/metrics") assert b" http_request_size_bytes" not in response.content assert b" namespace_subsystem_http_request_size_bytes" in response.content
def test_requests_all_labels(): app = create_app() Instrumentator().add(metrics.requests()).instrument(app).expose(app) client = TestClient(app) client.get("/") _ = get_response(client, "/metrics") assert (REGISTRY.get_sample_value( "http_requests_total", { "handler": "/", "method": "GET", "status": "2xx" }, ) == 1)
def test_latency_all_labels(): app = create_app() Instrumentator().add(metrics.latency()).instrument(app).expose(app) client = TestClient(app) client.get("/") _ = get_response(client, "/metrics") assert (REGISTRY.get_sample_value( "http_request_duration_seconds_sum", { "handler": "/", "method": "GET", "status": "2xx" }, ) > 0)