def test_custom_label_names():
    app = create_app()
    instrumentator = Instrumentator(label_names=(
        "a",
        "b",
        "c",
    ))
    instrumentator.instrument(app).expose(app)
    client = app.test_client()

    client.get("/")

    response = get_response(client, "/metrics")

    for label in (
            "a",
            "b",
            "c",
    ):
        assert f'{label}="'.encode() in response.data

    for label in (
            "method",
            "handler",
            "status",
    ):
        assert f'{label}="'.encode() not in response.data
def test_do_not_track_decorator():
    app = create_app()
    instrumentator = Instrumentator(excluded_handlers=[])
    instrumentator.instrument(app).expose(app)
    client = app.test_client()

    client.get("/ignored")
    client.get("/ignored")
    client.get("/")

    response = get_response(client, "/metrics")
    assert b'handler="/ignored"' not in response.data
    assert b'handler="/"' in response.data
def test_exclude_paths():
    app = create_app()
    instrumentator = Instrumentator(excluded_handlers=["/to/exclude"])
    instrumentator.instrument(app).expose(app)
    client = app.test_client()

    client.get("/")
    client.get("/to/exclude")
    client.get("/to/exclude")

    response = get_response(client, "/metrics")
    assert b'handler="/"' in response.data
    assert b'handler="/to/exclude"' not in response.data
def test_default_label_names():
    app = create_app()
    instrumentator = Instrumentator()
    instrumentator.instrument(app).expose(app)
    client = app.test_client()

    client.get("/")

    response = get_response(client, "/metrics")

    for label in instrumentator.label_names:
        assert f'{label}="'.encode() in response.data

    for label in ("endpoint", "path", "status_code"):
        assert f'{label}="'.encode() not in response.data
def test_multiprocess_with_var_not_set(monkeypatch, tmp_path):
    monkeypatch.setenv("prometheus_multiproc_dir", "DOES/NOT/EXIST")

    app = create_app()
    with pytest.raises(Exception):
        Instrumentator(buckets=(
            1,
            2,
            3,
        )).instrument(app).expose(app)
def test_custom_metric_name():
    app = create_app()
    Instrumentator(metric_name="xzy").instrument(app).expose(app)
    client = app.test_client()

    client.get("/")

    response = get_response(client, "/metrics")
    assert b"http_request_duration_seconds_bucket" not in response.data
    assert b"xzy_bucket" in response.data
def test_metrics_endpoint_availability():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    get_response(client, "/")

    response = get_response(client, "/metrics")
    assert_is_not_multiprocess(response)
    assert_request_count(1)
    assert METRIC.encode() in response.data
def test_multiprocess_with_var_set():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    get_response(client, "/")

    response = get_response(client, "/metrics")
    assert response.status_code == 200
    assert b"Multiprocess" in response.data
    assert b"# HELP process_cpu_seconds_total" not in response.data
    assert b"http_request_duration_seconds" in response.data
def test_parameter_existence():
    app = create_app()
    instrumentator = Instrumentator().instrument(app)

    assert hasattr(instrumentator, "should_group_status_codes")
    assert instrumentator.should_group_status_codes is True

    assert hasattr(instrumentator, "should_ignore_untemplated")
    assert instrumentator.should_ignore_untemplated is False

    assert hasattr(instrumentator, "should_group_untemplated")
    assert instrumentator.should_group_untemplated is True
def test_include_untemplated_group():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    get_response(client, "/")  # Exists
    get_response(client, "/this_does_not_exist")

    response = get_response(client, "/metrics")
    assert b'handler="/this_does_not_exist"' not in response.data
    assert b'handler="none"' in response.data
    assert b'status="4xx"' in response.data
def test_unhandled_server_error():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    client.get("/")

    response = get_response(client, "/server_error")
    assert response.status_code == 500

    response = get_response(client, "/metrics")
    assert b'handler="/server_error"' in response.data
    assert b'status="5xx"' in response.data
def test_bucket_without_inf():
    app = create_app()
    Instrumentator(buckets=(
        1,
        2,
        3,
    )).instrument(app).expose(app)
    client = app.test_client()

    client.get("/")

    response = get_response(client, "/metrics")
    assert b"http_request_duration_seconds_bucket" in response.data
def test_label_names():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    get_response(client, "/")

    response = get_response(client, "/metrics")
    assert_is_not_multiprocess(response)
    assert_request_count(1)
    assert b'method="' in response.data
    assert b'handler="' in response.data
    assert b'status="' in response.data
def test_ungrouped_status_codes():
    app = create_app()
    Instrumentator(should_group_status_codes=False).instrument(app).expose(app)
    client = app.test_client()

    client.post("/")  # -> 405
    client.post("/")  # -> 405
    client.get("/")  # -> 200

    response = get_response(client, "/metrics")
    assert b'status="2xx"' not in response.data
    assert b'status="200"' in response.data
    assert b'status="4xx"' not in response.data
    assert b'status="405"' in response.data
def test_ignore_untemplated():
    app = create_app()
    Instrumentator(should_ignore_untemplated=True).instrument(app).expose(app)
    client = app.test_client()

    get_response(client, "/")  # Exists
    get_response(client, "/fefwefwe4533")  # Does not exist
    get_response(client, "/booogo")  # Does not exist

    response = get_response(client, "/metrics")
    assert b'status="4xx"' not in response.data
    assert b'status="404"' not in response.data
    assert b'status="2xx"' in response.data
    assert b'handler="/fefwefwe4533"' not in response.data
    assert b'handler="none"' not in response.data
def test_grouped_status_codes():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    client.post("/")  # -> 405 -> 4xx
    client.post("/")  # -> 405 -> 4xx
    client.get("/")  # -> 200 -> 2xx
    client.get("/")  # -> 200 -> 2xx
    client.get("/")  # -> 200 -> 2xx

    response = get_response(client, "/metrics")
    assert_is_not_multiprocess(response)
    assert_request_count(3)
    assert b'status="2xx"' in response.data
    assert b'status="4xx"' in response.data
    assert b'status="405"' not in response.data
def test_default_no_rounding():
    app = create_app()
    Instrumentator().instrument(app).expose(app)
    client = app.test_client()

    client.get("/")
    client.get("/")
    client.get("/")

    _ = 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 > 15