diff --git a/CHANGELOG.md b/CHANGELOG.md index a2020ceb6..7196de607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ See also https://github.com/neo4j/neo4j-python-driver/wiki for a full changelog. ## NEXT RELEASE - No breaking or major changes. +- Implemented a hierarchical logger structure to improve log source + identification and traceability. + Introduced child loggers: + - `neo4j.io`: For socket and bolt protocol related logging. + - `neo4j.pool`: For logs pertaining to connection pooling and routing. + - `neo4j.auth_management`: For logging inside the provided AuthManager + implementations. ## Version 5.15 diff --git a/docs/source/api.rst b/docs/source/api.rst index 7a30f6004..6976951ad 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -2080,9 +2080,30 @@ following code: Logging ******* -The driver offers logging for debugging purposes. It is not recommended to -enable logging for anything other than debugging. For instance, if the driver is -not able to connect to the database server or if undesired behavior is observed. +The driver offers logging for debugging purposes. +It is not recommended to enable logging for anything other than debugging. +For instance, if the driver is not able to connect to the database server or if +undesired behavior is observed. + +This includes messages logged on ``WARNING`` level or higher. +They are logged to help understand what is going on *inside* the driver. +All relevant information is passed through return values, raised exceptions, +warnings, etc. +The logs are not the right place to look for actionable information. + +The driver supports hierarchical logging. +This means you can selectively configure all of the driver's logging or only +parts of it. +Currently available: + +* ``neo4j``: The root logger for the driver. + High-level code (e.g., Session, Transaction, Driver, etc.) logs here. + + * ``neo4j.io``: Logs network activity and bolt protocol messages, handshakes, + etc. + * ``neo4j.pool``: Logs connection pool activity (including routing). + * ``neo4j.auth_management``: Logger for provided :class:`.AuthManager` + implementations. There are different ways of enabling logging as listed below. diff --git a/src/neo4j/_async/auth_management.py b/src/neo4j/_async/auth_management.py index c97284ef2..54d66210b 100644 --- a/src/neo4j/_async/auth_management.py +++ b/src/neo4j/_async/auth_management.py @@ -32,7 +32,7 @@ from ..exceptions import Neo4jError -log = getLogger("neo4j") +log = getLogger("neo4j.auth_management") class AsyncStaticAuthManager(AsyncAuthManager): @@ -67,7 +67,11 @@ def __init__( self._lock = AsyncLock() async def _refresh_auth(self): - self._current_auth = await self._provider() + try: + self._current_auth = await self._provider() + except BaseException as e: + log.error("[ ] _: provider failed: %r", e) + raise if self._current_auth is None: raise TypeError( "Auth provider function passed to expiration_based " diff --git a/src/neo4j/_async/io/_bolt.py b/src/neo4j/_async/io/_bolt.py index 1815db9e5..04e922fda 100644 --- a/src/neo4j/_async/io/_bolt.py +++ b/src/neo4j/_async/io/_bolt.py @@ -57,7 +57,7 @@ # Set up logger -log = getLogger("neo4j") +log = getLogger("neo4j.io") class ServerStateManagerBase(abc.ABC): diff --git a/src/neo4j/_async/io/_bolt3.py b/src/neo4j/_async/io/_bolt3.py index 330ad4cce..d3c9837ad 100644 --- a/src/neo4j/_async/io/_bolt3.py +++ b/src/neo4j/_async/io/_bolt3.py @@ -49,7 +49,7 @@ ) -log = getLogger("neo4j") +log = getLogger("neo4j.io") class BoltStates(Enum): diff --git a/src/neo4j/_async/io/_bolt4.py b/src/neo4j/_async/io/_bolt4.py index 300c638a2..bda0b9641 100644 --- a/src/neo4j/_async/io/_bolt4.py +++ b/src/neo4j/_async/io/_bolt4.py @@ -51,7 +51,7 @@ ) -log = getLogger("neo4j") +log = getLogger("neo4j.io") class AsyncBolt4x0(AsyncBolt): diff --git a/src/neo4j/_async/io/_bolt5.py b/src/neo4j/_async/io/_bolt5.py index f84bd0d4c..455eeb230 100644 --- a/src/neo4j/_async/io/_bolt5.py +++ b/src/neo4j/_async/io/_bolt5.py @@ -54,7 +54,7 @@ ) -log = getLogger("neo4j") +log = getLogger("neo4j.io") class AsyncBolt5x0(AsyncBolt): diff --git a/src/neo4j/_async/io/_common.py b/src/neo4j/_async/io/_common.py index b90550dc8..3284abe2c 100644 --- a/src/neo4j/_async/io/_common.py +++ b/src/neo4j/_async/io/_common.py @@ -28,7 +28,7 @@ ) -log = logging.getLogger("neo4j") +log = logging.getLogger("neo4j.io") class AsyncInbox: diff --git a/src/neo4j/_async/io/_pool.py b/src/neo4j/_async/io/_pool.py index 65ae056ff..e4c6b7e2e 100644 --- a/src/neo4j/_async/io/_pool.py +++ b/src/neo4j/_async/io/_pool.py @@ -68,7 +68,7 @@ # Set up logger -log = getLogger("neo4j") +log = getLogger("neo4j.pool") @dataclass diff --git a/src/neo4j/_async/work/session.py b/src/neo4j/_async/work/session.py index b7b4452a4..c93bf7df4 100644 --- a/src/neo4j/_async/work/session.py +++ b/src/neo4j/_async/work/session.py @@ -61,7 +61,7 @@ _P = te.ParamSpec("_P") -log = getLogger("neo4j") +log = getLogger("neo4j.pool") class AsyncSession(AsyncWorkspace): diff --git a/src/neo4j/_async_compat/network/_bolt_socket.py b/src/neo4j/_async_compat/network/_bolt_socket.py index a0c19b1ec..74b1cba8b 100644 --- a/src/neo4j/_async_compat/network/_bolt_socket.py +++ b/src/neo4j/_async_compat/network/_bolt_socket.py @@ -62,7 +62,7 @@ from ..._sync.io import Bolt -log = logging.getLogger("neo4j") +log = logging.getLogger("neo4j.io") def _sanitize_deadline(deadline): diff --git a/src/neo4j/_async_compat/network/_util.py b/src/neo4j/_async_compat/network/_util.py index c292cd221..0248e4ba4 100644 --- a/src/neo4j/_async_compat/network/_util.py +++ b/src/neo4j/_async_compat/network/_util.py @@ -5,7 +5,7 @@ from ... import addressing -log = logging.getLogger("neo4j") +log = logging.getLogger("neo4j.io") def _resolved_addresses_from_info(info, host_name): @@ -142,7 +142,7 @@ def resolve_address(address, family=0, resolver=None): yield address return - addressing.log.debug("[#0000] _: in: %s", address) + log.debug("[#0000] _: in: %s", address) if resolver: for address in map(addressing.Address, resolver(address)): log.debug("[#0000] _: custom resolver out: %s", diff --git a/src/neo4j/_routing.py b/src/neo4j/_routing.py index 6cb83a880..5bc7f63b1 100644 --- a/src/neo4j/_routing.py +++ b/src/neo4j/_routing.py @@ -21,7 +21,7 @@ from .addressing import Address -log = getLogger("neo4j") +log = getLogger("neo4j.pool") class OrderedSet(MutableSet): diff --git a/src/neo4j/_sync/auth_management.py b/src/neo4j/_sync/auth_management.py index 4b9445139..408f2382f 100644 --- a/src/neo4j/_sync/auth_management.py +++ b/src/neo4j/_sync/auth_management.py @@ -32,7 +32,7 @@ from ..exceptions import Neo4jError -log = getLogger("neo4j") +log = getLogger("neo4j.auth_management") class StaticAuthManager(AuthManager): @@ -67,7 +67,11 @@ def __init__( self._lock = Lock() def _refresh_auth(self): - self._current_auth = self._provider() + try: + self._current_auth = self._provider() + except BaseException as e: + log.error("[ ] _: provider failed: %r", e) + raise if self._current_auth is None: raise TypeError( "Auth provider function passed to expiration_based " diff --git a/src/neo4j/_sync/io/_bolt.py b/src/neo4j/_sync/io/_bolt.py index 0250be0cb..389cc092a 100644 --- a/src/neo4j/_sync/io/_bolt.py +++ b/src/neo4j/_sync/io/_bolt.py @@ -57,7 +57,7 @@ # Set up logger -log = getLogger("neo4j") +log = getLogger("neo4j.io") class ServerStateManagerBase(abc.ABC): diff --git a/src/neo4j/_sync/io/_bolt3.py b/src/neo4j/_sync/io/_bolt3.py index f56af5322..5d9741179 100644 --- a/src/neo4j/_sync/io/_bolt3.py +++ b/src/neo4j/_sync/io/_bolt3.py @@ -49,7 +49,7 @@ ) -log = getLogger("neo4j") +log = getLogger("neo4j.io") class BoltStates(Enum): diff --git a/src/neo4j/_sync/io/_bolt4.py b/src/neo4j/_sync/io/_bolt4.py index 15c77f8ff..13969257b 100644 --- a/src/neo4j/_sync/io/_bolt4.py +++ b/src/neo4j/_sync/io/_bolt4.py @@ -51,7 +51,7 @@ ) -log = getLogger("neo4j") +log = getLogger("neo4j.io") class Bolt4x0(Bolt): diff --git a/src/neo4j/_sync/io/_bolt5.py b/src/neo4j/_sync/io/_bolt5.py index a9030eb92..7f691f9b2 100644 --- a/src/neo4j/_sync/io/_bolt5.py +++ b/src/neo4j/_sync/io/_bolt5.py @@ -54,7 +54,7 @@ ) -log = getLogger("neo4j") +log = getLogger("neo4j.io") class Bolt5x0(Bolt): diff --git a/src/neo4j/_sync/io/_common.py b/src/neo4j/_sync/io/_common.py index d5ae0aa35..b609bd0ab 100644 --- a/src/neo4j/_sync/io/_common.py +++ b/src/neo4j/_sync/io/_common.py @@ -28,7 +28,7 @@ ) -log = logging.getLogger("neo4j") +log = logging.getLogger("neo4j.io") class Inbox: diff --git a/src/neo4j/_sync/io/_pool.py b/src/neo4j/_sync/io/_pool.py index af3307b62..5655a5dad 100644 --- a/src/neo4j/_sync/io/_pool.py +++ b/src/neo4j/_sync/io/_pool.py @@ -65,7 +65,7 @@ # Set up logger -log = getLogger("neo4j") +log = getLogger("neo4j.pool") @dataclass diff --git a/src/neo4j/_sync/work/session.py b/src/neo4j/_sync/work/session.py index 1479b90b5..4153885f5 100644 --- a/src/neo4j/_sync/work/session.py +++ b/src/neo4j/_sync/work/session.py @@ -61,7 +61,7 @@ _P = te.ParamSpec("_P") -log = getLogger("neo4j") +log = getLogger("neo4j.pool") class Session(Workspace): diff --git a/src/neo4j/addressing.py b/src/neo4j/addressing.py index 76cc64944..66645aba8 100644 --- a/src/neo4j/addressing.py +++ b/src/neo4j/addressing.py @@ -16,7 +16,6 @@ from __future__ import annotations -import logging import typing as t from socket import ( AddressFamily, @@ -30,9 +29,6 @@ import typing_extensions as te -log = logging.getLogger("neo4j") - - _T = t.TypeVar("_T")