Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ src/deepgram/client.py
# key / access token) in DEBUG handshake logs. No Fern-generated counterpart.
src/deepgram/_secure_logging.py

# Hand-written opt-out telemetry module (SDK Observability). Builds an isolated
# Sentry client (never the global sentry_sdk.init()) wired into client.py via
# the telemetry_opt_out / telemetry_handler constructor params. No Fern-generated
# counterpart. Inert until a real DSN is embedded/supplied.
src/deepgram/telemetry

# WebSocket socket clients:
# - except Exception broad catch (supports custom transports, generator narrows to WebSocketException)
# - _sanitize_numeric_types in agent socket client (float→int for API)
Expand Down Expand Up @@ -173,6 +179,7 @@ tests/custom/test_listen_v2_connect_wire.py
tests/custom/test_listen_v2_regen_constraints.py
tests/custom/test_query_encoder.py
tests/custom/test_secure_logging.py
tests/custom/test_telemetry.py
tests/custom/test_socket_client_shims.py
tests/custom/test_speak_v2_connect_wire.py
tests/custom/test_speak_v2_socket.py
Expand Down
73 changes: 70 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ python = "^3.10"
aiohttp = { version = ">=3.14.1,<4", optional = true, python = ">=3.10"}
httpx = ">=0.21.2"
httpx-aiohttp = { version = "^0.1.8", optional = true, python = ">=3.10"}
sentry-sdk = { version = ">=2.0.0", optional = true }
pydantic = ">= 1.9.2"
pydantic-core = ">=2.18.2,<3.0.0"
typing_extensions = ">= 4.0.0"
Expand Down Expand Up @@ -99,3 +100,4 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry.extras]
aiohttp=["aiohttp", "httpx-aiohttp"]
telemetry=["sentry-sdk"]
58 changes: 50 additions & 8 deletions src/deepgram/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@

from ._secure_logging import install_websocket_log_redaction
from .base_client import AsyncBaseClient, BaseClient
from .telemetry import init_telemetry, install_response_capture
from .transport import install_transport
from .version import __version__

from deepgram.core.client_wrapper import BaseClientWrapper

Expand Down Expand Up @@ -75,8 +77,14 @@ class DeepgramClient(BaseClient):
- `redact_credentials_in_logs`: Mask the `Authorization` header (API key / access token)
in the `websockets` library's DEBUG handshake logs. Defaults to `True`; set
to `False` to opt out and manage credential redaction yourself.
- `telemetry_opt_out`: Telemetry opt-out flag (maintained for backwards compatibility, no-op).
- `telemetry_handler`: Telemetry handler (maintained for backwards compatibility, no-op).
- `telemetry_opt_out`: Opt out of isolated, error-only SDK telemetry. Defaults to
``True`` (telemetry off). When ``False`` and a telemetry DSN is
configured, the SDK reports its *own* errors (never host-app errors,
never audio/keys/transcripts/PII) to an isolated Sentry client. Also
forced off by the ``DEEPGRAM_TELEMETRY_DISABLED`` env kill-switch.
- `telemetry_handler`: Receive the SDK's own errors in-process instead of phoning home.
A callable ``(exc, tags)`` invoked for SDK-originated exceptions; when
set it fully replaces Sentry and no data leaves the process.
"""

def __init__(self, *args, **kwargs) -> None:
Expand Down Expand Up @@ -130,8 +138,22 @@ def __init__(self, *args, **kwargs) -> None:
reconnect = False
self.reconnect = reconnect

# Store telemetry handler for backwards compatibility (no-op, telemetry not implemented)
self._telemetry_handler = None
# Wire opt-out telemetry. `telemetry_opt_out` and `telemetry_handler`
# are resolved above; a custom handler takes precedence over Sentry,
# and with no opt-out + a resolvable DSN this arms isolated phone-home.
# When active, attach a response hook (HTTP 5xx reporting, tagged with
# session id + request id) to the httpx client the wrapper already
# built — no generated files are touched.
self._telemetry_handler = telemetry_handler
self._telemetry = init_telemetry(
opt_out=telemetry_opt_out,
handler=telemetry_handler,
version=__version__,
)
if self._telemetry is not None:
install_response_capture(
self._telemetry, self._client_wrapper, final_session_id
)


class AsyncDeepgramClient(AsyncBaseClient):
Expand All @@ -154,8 +176,14 @@ class AsyncDeepgramClient(AsyncBaseClient):
- `redact_credentials_in_logs`: Mask the `Authorization` header (API key / access token)
in the `websockets` library's DEBUG handshake logs. Defaults to `True`; set
to `False` to opt out and manage credential redaction yourself.
- `telemetry_opt_out`: Telemetry opt-out flag (maintained for backwards compatibility, no-op).
- `telemetry_handler`: Telemetry handler (maintained for backwards compatibility, no-op).
- `telemetry_opt_out`: Opt out of isolated, error-only SDK telemetry. Defaults to
``True`` (telemetry off). When ``False`` and a telemetry DSN is
configured, the SDK reports its *own* errors (never host-app errors,
never audio/keys/transcripts/PII) to an isolated Sentry client. Also
forced off by the ``DEEPGRAM_TELEMETRY_DISABLED`` env kill-switch.
- `telemetry_handler`: Receive the SDK's own errors in-process instead of phoning home.
A callable ``(exc, tags)`` invoked for SDK-originated exceptions; when
set it fully replaces Sentry and no data leaves the process.
"""

def __init__(self, *args, **kwargs) -> None:
Expand Down Expand Up @@ -209,5 +237,19 @@ def __init__(self, *args, **kwargs) -> None:
reconnect = False
self.reconnect = reconnect

# Store telemetry handler for backwards compatibility (no-op, telemetry not implemented)
self._telemetry_handler = None
# Wire opt-out telemetry. `telemetry_opt_out` and `telemetry_handler`
# are resolved above; a custom handler takes precedence over Sentry,
# and with no opt-out + a resolvable DSN this arms isolated phone-home.
# When active, attach a response hook (HTTP 5xx reporting, tagged with
# session id + request id) to the httpx client the wrapper already
# built — no generated files are touched.
self._telemetry_handler = telemetry_handler
self._telemetry = init_telemetry(
opt_out=telemetry_opt_out,
handler=telemetry_handler,
version=__version__,
)
if self._telemetry is not None:
install_response_capture(
self._telemetry, self._client_wrapper, final_session_id
)
22 changes: 22 additions & 0 deletions src/deepgram/telemetry/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Opt-out, isolated Sentry telemetry for the Deepgram Python SDK.

Hand-written module (not Fern-generated). Wired into ``DeepgramClient`` /
``AsyncDeepgramClient`` via the ``telemetry_opt_out`` and ``telemetry_handler``
constructor parameters.
"""

from .client import (
TelemetryHandler,
TelemetrySink,
init_telemetry,
is_enabled,
)
from .http_hooks import install_response_capture

__all__ = [
"TelemetryHandler",
"TelemetrySink",
"init_telemetry",
"install_response_capture",
"is_enabled",
]
Loading
Loading