|
1 | 1 | import sys |
2 | 2 | import threading |
3 | 3 | import weakref |
| 4 | +import inspect |
4 | 5 | from importlib import import_module |
5 | 6 |
|
6 | 7 | import sentry_sdk |
@@ -763,24 +764,52 @@ def _set_db_data(span, cursor_or_db): |
763 | 764 | span.set_data(SPANDATA.SERVER_SOCKET_ADDRESS, cached_config["unix_socket"]) |
764 | 765 | return |
765 | 766 |
|
766 | | - # Fallback to using get_connection_params() |
| 767 | + # Fallback to using the database connection to get the data. |
| 768 | + # This is the edge case where db configuration is not in Django's `DATABASES` setting. |
767 | 769 | try: |
768 | | - connection_params = db.get_connection_params() |
| 770 | + # Some custom backends override `__getattr__`, making it look like `cursor_or_db` |
| 771 | + # actually has a `connection` and the `connection` has a `get_dsn_parameters` |
| 772 | + # attribute, only to throw an error once you actually want to call it. |
| 773 | + # Hence the `inspect` check whether `get_dsn_parameters` is an actual callable |
| 774 | + # function. |
| 775 | + is_psycopg2 = ( |
| 776 | + hasattr(cursor_or_db, "connection") |
| 777 | + and hasattr(cursor_or_db.connection, "get_dsn_parameters") |
| 778 | + and inspect.isroutine(cursor_or_db.connection.get_dsn_parameters) |
| 779 | + ) |
| 780 | + if is_psycopg2: |
| 781 | + connection_params = cursor_or_db.connection.get_dsn_parameters() |
| 782 | + else: |
| 783 | + try: |
| 784 | + # psycopg3, only extract needed params as get_parameters |
| 785 | + # can be slow because of the additional logic to filter out default |
| 786 | + # values |
| 787 | + connection_params = { |
| 788 | + "dbname": cursor_or_db.connection.info.dbname, |
| 789 | + "port": cursor_or_db.connection.info.port, |
| 790 | + } |
| 791 | + # PGhost returns host or base dir of UNIX socket as an absolute path |
| 792 | + # starting with /, use it only when it contains host |
| 793 | + host = cursor_or_db.connection.info.host |
| 794 | + if host and not host.startswith("/"): |
| 795 | + connection_params["host"] = host |
| 796 | + except Exception: |
| 797 | + connection_params = db.get_connection_params() |
769 | 798 |
|
770 | 799 | db_name = connection_params.get("dbname") or connection_params.get("database") |
771 | | - if db_name: |
| 800 | + if db_name is not None: |
772 | 801 | span.set_data(SPANDATA.DB_NAME, db_name) |
773 | 802 |
|
774 | 803 | host = connection_params.get("host") |
775 | | - if host: |
| 804 | + if host is not None: |
776 | 805 | span.set_data(SPANDATA.SERVER_ADDRESS, host) |
777 | 806 |
|
778 | 807 | port = connection_params.get("port") |
779 | | - if port: |
| 808 | + if port is not None: |
780 | 809 | span.set_data(SPANDATA.SERVER_PORT, str(port)) |
781 | 810 |
|
782 | 811 | unix_socket = connection_params.get("unix_socket") |
783 | | - if unix_socket: |
| 812 | + if unix_socket is not None: |
784 | 813 | span.set_data(SPANDATA.SERVER_SOCKET_ADDRESS, unix_socket) |
785 | 814 |
|
786 | 815 | except (KeyError, ImproperlyConfigured, AttributeError) as e: |
|
0 commit comments