Skip to content

Commit 8da40a3

Browse files
Use connection string as default query session pool name
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e5091dd commit 8da40a3

5 files changed

Lines changed: 78 additions & 14 deletions

File tree

docs/opentelemetry.rst

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,14 @@ Operation metrics use stable labels only:
301301
Operation metrics are recorded for ``ExecuteQuery``, ``Commit``, ``Rollback``,
302302
``CreateSession``, and ``BeginTransaction``.
303303

304-
Query session metrics use ``ydb.query.session.pool.name``. The pool name is generated
305-
automatically, or can be set explicitly with ``QuerySessionPool(..., name="main-pool")``
306-
for both synchronous and asynchronous pools. ``ydb.query.session.count`` also includes
307-
``ydb.query.session.state`` with values ``"idle"`` or ``"used"``.
304+
Query session metrics use ``ydb.query.session.pool.name``. When ``name`` is not
305+
passed to ``QuerySessionPool``, the SDK uses the YDB connection string of the
306+
driver — ``<endpoint><database>`` (for example ``grpc://localhost:2136/local``) —
307+
so the pool is identifiable in dashboards out of the box. Set the label
308+
explicitly with ``QuerySessionPool(..., name="main-pool")`` for both synchronous
309+
and asynchronous pools when several pools share a connection string.
310+
``ydb.query.session.count`` also includes ``ydb.query.session.state`` with values
311+
``"idle"`` or ``"used"``.
308312

309313
Retry metrics are recorded without attributes.
310314

tests/opentelemetry/test_metrics.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,19 +424,49 @@ def test_sync_query_session_pool_stop_removes_observable_metrics(metrics_setup):
424424
assert _points(metrics_setup, QUERY_SESSION_MIN) == []
425425

426426

427-
def test_sync_query_session_pool_uses_endpoint_as_default_pool_name(metrics_setup):
427+
def test_query_session_pool_name_prefers_explicit_name():
428+
from ydb.opentelemetry.metrics import query_session_pool_name
429+
430+
assert query_session_pool_name("my-pool", endpoint="grpc://localhost:2136", database="/local") == "my-pool"
431+
432+
433+
def test_query_session_pool_name_uses_connection_string():
434+
from ydb.opentelemetry.metrics import query_session_pool_name
435+
436+
assert (
437+
query_session_pool_name(None, endpoint="grpc://localhost:2136", database="/local")
438+
== "grpc://localhost:2136/local"
439+
)
440+
441+
442+
def test_query_session_pool_name_normalizes_database_without_leading_slash():
443+
from ydb.opentelemetry.metrics import query_session_pool_name
444+
445+
assert (
446+
query_session_pool_name(None, endpoint="grpc://localhost:2136", database="local")
447+
== "grpc://localhost:2136/local"
448+
)
449+
450+
451+
def test_query_session_pool_name_falls_back_to_counter_when_nothing_known():
452+
from ydb.opentelemetry.metrics import query_session_pool_name
453+
454+
assert query_session_pool_name(None, endpoint=None, database=None).startswith("query-session-pool-")
455+
456+
457+
def test_sync_query_session_pool_uses_connection_string_as_default_pool_name(metrics_setup):
428458
from tests.opentelemetry.conftest import FakeDriverConfig
429459
from ydb.opentelemetry.metrics import QUERY_SESSION_MAX
430460
from ydb.query.pool import QuerySessionPool
431461

432462
class FakeDriver:
433-
_driver_config = FakeDriverConfig(endpoint="grpc://localhost:2136")
463+
_driver_config = FakeDriverConfig(endpoint="grpc://localhost:2136", database="/local")
434464

435465
QuerySessionPool(driver=FakeDriver(), size=42)
436466

437467
assert _single_point(metrics_setup, QUERY_SESSION_MAX).value == 42
438468
assert _single_point(metrics_setup, QUERY_SESSION_MAX).attributes == {
439-
"ydb.query.session.pool.name": "grpc://localhost:2136"
469+
"ydb.query.session.pool.name": "grpc://localhost:2136/local"
440470
}
441471

442472

@@ -467,19 +497,19 @@ async def test_async_query_session_pool_stop_removes_observable_metrics(metrics_
467497

468498

469499
@pytest.mark.asyncio
470-
async def test_async_query_session_pool_uses_endpoint_as_default_pool_name(metrics_setup):
500+
async def test_async_query_session_pool_uses_connection_string_as_default_pool_name(metrics_setup):
471501
from tests.opentelemetry.conftest import FakeDriverConfig
472502
from ydb.aio.query.pool import QuerySessionPool
473503
from ydb.opentelemetry.metrics import QUERY_SESSION_MAX
474504

475505
class FakeDriver:
476-
_driver_config = FakeDriverConfig(endpoint="grpc://localhost:2136")
506+
_driver_config = FakeDriverConfig(endpoint="grpc://localhost:2136", database="/local")
477507

478508
QuerySessionPool(driver=FakeDriver(), size=24)
479509

480510
assert _single_point(metrics_setup, QUERY_SESSION_MAX).value == 24
481511
assert _single_point(metrics_setup, QUERY_SESSION_MAX).attributes == {
482-
"ydb.query.session.pool.name": "grpc://localhost:2136"
512+
"ydb.query.session.pool.name": "grpc://localhost:2136/local"
483513
}
484514

485515

ydb/aio/query/pool.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ def __init__(
6565
self._loop = asyncio.get_running_loop() if loop is None else loop
6666
self._query_client_settings = query_client_settings
6767
driver_config = getattr(driver, "_driver_config", None)
68-
self._metrics_pool_name = query_session_pool_name(name, getattr(driver_config, "endpoint", None))
68+
self._metrics_pool_name = query_session_pool_name(
69+
name,
70+
endpoint=getattr(driver_config, "endpoint", None),
71+
database=getattr(driver_config, "database", None),
72+
)
6973
record_query_session_max(self._size, self._metrics_pool_name)
7074

7175
async def _create_new_session(self):

ydb/opentelemetry/metrics.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,30 @@ def next_query_session_pool_name() -> str:
154154
return "query-session-pool-%d" % next(_pool_name_counter)
155155

156156

157-
def query_session_pool_name(name: Optional[str], endpoint: Optional[str]) -> str:
158-
return name or endpoint or next_query_session_pool_name()
157+
def query_session_pool_name(
158+
name: Optional[str],
159+
endpoint: Optional[str] = None,
160+
database: Optional[str] = None,
161+
) -> str:
162+
"""Return a stable label for the ``ydb.query.session.pool.name`` metric attribute.
163+
164+
If the user passed an explicit ``name`` to ``QuerySessionPool``, it wins. Otherwise
165+
the SDK builds a YDB connection string in the canonical ``<endpoint><database>``
166+
form (e.g. ``grpc://localhost:2136/local``) so that the pool is identifiable in
167+
dashboards without leaking driver-internal counters. When neither piece of the
168+
connection string is available, a process-unique counter name is used as a last
169+
resort.
170+
"""
171+
if name:
172+
return name
173+
endpoint_part = endpoint or ""
174+
database_part = database or ""
175+
if database_part and not database_part.startswith("/"):
176+
database_part = "/" + database_part
177+
connection_string = endpoint_part + database_part
178+
if connection_string:
179+
return connection_string
180+
return next_query_session_pool_name()
159181

160182

161183
def _set_metrics_registry(metrics_registry: MetricRegistry) -> None:

ydb/query/pool.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ def __init__(
7575
self._lock = threading.RLock()
7676
self._query_client_settings = query_client_settings
7777
driver_config = getattr(driver, "_driver_config", None)
78-
self._metrics_pool_name = query_session_pool_name(name, getattr(driver_config, "endpoint", None))
78+
self._metrics_pool_name = query_session_pool_name(
79+
name,
80+
endpoint=getattr(driver_config, "endpoint", None),
81+
database=getattr(driver_config, "database", None),
82+
)
7983
record_query_session_max(self._size, self._metrics_pool_name)
8084

8185
def _create_new_session(self, timeout: Optional[float]):

0 commit comments

Comments
 (0)