|
| 1 | +--- |
| 2 | +title: "Sentry SDK Integration" |
| 3 | +description: "Integrate Sentry for error tracking and performance monitoring" |
| 4 | +--- |
| 5 | + |
| 6 | +## What is Sentry? |
| 7 | + |
| 8 | +[Sentry](https://sentry.io/) is an open-source error tracking tool that helps developers monitor and fix crashes in real-time. It provides insights into the health of your applications by capturing and reporting errors, exceptions, and performance issues. |
| 9 | + |
| 10 | +## Why integrate Sentry? |
| 11 | + |
| 12 | +Integrating Sentry into your application allows you to: |
| 13 | + |
| 14 | +- Automatically capture and report errors and exceptions. |
| 15 | +- Monitor the performance of your application. |
| 16 | +- Gain insights into the user experience and identify bottlenecks. |
| 17 | +- Improve the overall reliability and stability of your application. |
| 18 | + |
| 19 | +## Configuring Sentry |
| 20 | + |
| 21 | +To integrate Sentry into your application, you need to initialize the Sentry SDK at the earliest instantiation point in your code. This ensures that Sentry starts capturing errors and performance data as soon as possible. |
| 22 | + |
| 23 | +Here's how you can configure the Sentry SDK: |
| 24 | + |
| 25 | +```python |
| 26 | +import os |
| 27 | +import sentry_sdk |
| 28 | +from sentry_sdk.integrations.asyncio import AsyncioIntegration |
| 29 | +from sentry_sdk.integrations.logging import LoguruIntegration |
| 30 | + |
| 31 | +sentry_sdk.init( |
| 32 | + dsn=os.getenv("SENTRY_DSN"), |
| 33 | + environment=os.getenv("ENVIRONMENT"), |
| 34 | + # Sample rate for transactions (performance). |
| 35 | + traces_sample_rate=1.0, |
| 36 | + # Sample rate for exceptions / crashes. |
| 37 | + sample_rate=1.0, |
| 38 | + max_request_body_size="always", |
| 39 | + integrations=[ |
| 40 | + AsyncioIntegration(), |
| 41 | + LoguruIntegration(), |
| 42 | + ], |
| 43 | +) |
| 44 | +``` |
| 45 | + |
| 46 | +Head to [sentry.io](sentry.io) to get your DSN! See https://docs.sentry.io/platforms/python/configuration/options/ for more info about the above options. |
| 47 | + |
| 48 | +## Instrumenting your application |
| 49 | + |
| 50 | +Vocode exposes a set of custom spans that get automatically sent to Sentry during Vocode conversations. To use these spans, you'll need to manually attach a transaction to the current scope. |
| 51 | + |
| 52 | +### Example 1: Streaming Conversation |
| 53 | + |
| 54 | +Update `quickstarts/streaming_conversation.py`, replace the `main` function with the following code: |
| 55 | + |
| 56 | +```python |
| 57 | +import sentry_sdk |
| 58 | +from sentry_sdk.integrations.asyncio import AsyncioIntegration |
| 59 | +from sentry_sdk.integrations.loguru import LoguruIntegration |
| 60 | +from vocode import sentry_transaction |
| 61 | + |
| 62 | +sentry_sdk.init( |
| 63 | + ..., |
| 64 | + integrations=[ |
| 65 | + AsyncioIntegration(), |
| 66 | + LoguruIntegration(), |
| 67 | + ], |
| 68 | +) |
| 69 | + |
| 70 | +async def main(): |
| 71 | + ... |
| 72 | + await conversation.start() |
| 73 | + ... |
| 74 | + |
| 75 | + |
| 76 | +if __name__ == "__main__": |
| 77 | + with sentry_sdk.start_transaction( |
| 78 | + op="streaming_conversation", description="streaming_conversation" |
| 79 | + ) as sentry_txn: |
| 80 | + sentry_transaction.set(sentry_txn) |
| 81 | + asyncio.run(main()) |
| 82 | +``` |
| 83 | + |
| 84 | +Head to the Performance pane in Sentry and click into the trace, you should see something that looks like this: |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | +### Example 2: Telephony Server |
| 89 | + |
| 90 | +Simply instantiate the Sentry SDK at the top of the file, e.g. in `app/telephony_app/main.py` |
| 91 | + |
| 92 | +```python |
| 93 | +sentry_sdk.init( |
| 94 | + ... |
| 95 | +) |
| 96 | + |
| 97 | +app = FastAPI(docs_url=None) |
| 98 | +``` |
| 99 | + |
| 100 | +## Custom Spans Overview |
| 101 | + |
| 102 | +### Latency of Conversation |
| 103 | + |
| 104 | +**Latency of Conversation** _(`LATENCY_OF_CONVERSATION`)_ measures the overall latency of a conversation, from when the user finishes their utterance to when the agent begins its response. It is broken up into the following sub-spans: |
| 105 | + |
| 106 | +- **[Deepgram Only] Endpointing Latency** _(`ENDPOINTING_LATENCY`)_: Captures the extra latency involved from retrieving finalized transcripts from Deepgram before deciding to invoke the agent. |
| 107 | +- **Language model Time to First Token** _(`LANGUAGE_MODEL_TIME_TO_FIRST_TOKEN`)_: Tracks the time taken by the language model to generate the first token (word or character) in its response. |
| 108 | +- **Synthesis Time to First Token** _(`SYNTHESIS_TIME_TO_FIRST_TOKEN`)_: Measures the time taken by the synthesizer to generate the first token in the synthesized speech. This is useful for evaluating the initial response time of the synthesizer. |
| 109 | + |
| 110 | +### Deepgram |
| 111 | + |
| 112 | +We capture the following spans in our Deepgram integration: |
| 113 | + |
| 114 | +- **Connected to First Send** _(`CONNECTED_TO_FIRST_SEND`)_: Measures the time from when the Deepgram websocket connection is established to when the first data is sent |
| 115 | +- **[Deepgram Only] First Send to First Receive** _(`FIRST_SEND_TO_FIRST_RECEIVE`)_: Measures the time from when the first data is sent to Deepgram to when the first response is received |
| 116 | +- **[Deepgram Only] Start to Connection** _(`START_TO_CONNECTION`)_: Tracks the time it takes to establish the websocket connection with Deepgram |
| 117 | + |
| 118 | +### LLM |
| 119 | + |
| 120 | +For our OpenAI and Anthropic integrations, we capture: |
| 121 | + |
| 122 | +- **Time to First Token** _(`TIME_TO_FIRST_TOKEN`)_: Measures the time taken by the language model to generate the first token (word or character) in its response. |
| 123 | +- **LLM First Sentence Total** _(`LLM_FIRST_SENTENCE_TOTAL`)_: Measures the total time taken by the language model to generate the first complete sentence. |
| 124 | + |
| 125 | +### Synthesizer |
| 126 | + |
| 127 | +For most of our synthesizer integrations, we capture: |
| 128 | + |
| 129 | +- **Synthesis Generate First Chunk** _(`SYNTHESIS_GENERATE_FIRST_CHUNK`)_: Measures the time taken to generate the first chunk of synthesized speech. |
| 130 | +- **Synthesizer Synthesis Total** _(`SYNTHESIZER_SYNTHESIS_TOTAL`)_: Tracks the total time taken for the entire speech synthesis process. This span helps in understanding the overall performance of the synthesizer. |
| 131 | + |
| 132 | +These spans will have the actual synthesizer's name prepended to them. For example, if the synthesizer is `ElevenLabsSynthesizer`, the span `SYNTHESIZER_SYNTHESIS_TOTAL` will be recorded as `ElevenLabsSynthesizer.synthesis_total`: |
| 133 | + |
| 134 | +- **Synthesis Total** _(`SYNTHESIZER_SYNTHESIS_TOTAL`)_ |
| 135 | +- **Time to First Token** _(`SYNTHESIZER_TIME_TO_FIRST_TOKEN`)_ |
0 commit comments