11import asyncio
22import functools
3+ import logging
34import sys
45import typing
56from types import TracebackType
1718 from aiocontextvars import ContextVar
1819
1920
21+ logger = logging .getLogger ("databases" )
22+
23+
2024class Database :
2125 SUPPORTED_BACKENDS = {
2226 "postgresql" : "databases.backends.postgres:PostgresBackend" ,
@@ -63,6 +67,7 @@ async def connect(self) -> None:
6367 assert not self .is_connected , "Already connected."
6468
6569 await self ._backend .connect ()
70+ logger .info ("Connected to database %s" % repr (self .url .obscure_password ))
6671 self .is_connected = True
6772
6873 if self ._force_rollback :
@@ -80,6 +85,7 @@ async def disconnect(self) -> None:
8085 await self ._global_transaction .__aexit__ ()
8186
8287 await self ._backend .disconnect ()
88+ logger .info ("Disconnected from database %s" % repr (self .url .obscure_password ))
8389 self .is_connected = False
8490
8591 async def __aenter__ (self ) -> "Database" :
@@ -412,14 +418,17 @@ def replace(self, **kwargs: typing.Any) -> "DatabaseURL":
412418 components = self .components ._replace (** kwargs )
413419 return self .__class__ (components .geturl ())
414420
421+ @property
422+ def obscure_password (self ) -> str :
423+ if self .password :
424+ return self .replace (password = "********" )._url
425+ return self ._url
426+
415427 def __str__ (self ) -> str :
416428 return self ._url
417429
418430 def __repr__ (self ) -> str :
419- url = str (self )
420- if self .password :
421- url = str (self .replace (password = "********" ))
422- return f"{ self .__class__ .__name__ } ({ repr (url )} )"
431+ return f"{ self .__class__ .__name__ } ({ repr (self .obscure_password )} )"
423432
424433 def __eq__ (self , other : typing .Any ) -> bool :
425434 return str (self ) == str (other )
0 commit comments