raindrop-bedrock
Raindrop observability integration for AWS Bedrock (Python). Automatically captures converse() and invoke_model() calls by wrapping the boto3 bedrock-runtime client.
Installation
pip install raindrop-bedrock
For async support with aioboto3:
pip install raindrop-bedrock[async]
Quick Start
import boto3
from raindrop_bedrock import RaindropBedrock
rb = RaindropBedrock(api_key="your-write-key", user_id="user-123")
client = boto3.client("bedrock-runtime", region_name="us-east-1")
rb.wrap(client)
response = client.converse(
modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": [{"text": "Hello!"}]}],
)
rb.flush()
Projects
Route events to a specific project by passing its slug as project_id:
rb = RaindropBedrock(
api_key="your-write-key",
project_id="support-prod",
)
project_id sets the X-Raindrop-Project-Id header on every event. Omit it (or pass "default") to use your org's default Production project, which is the existing behavior. The same option is accepted by the create_raindrop_bedrock(...) factory. Invalid slugs are ignored with a warning and no header is sent.
Debug Mode
Enable verbose logging with the debug flag:
rb = RaindropBedrock(api_key="your-write-key", user_id="user-123", debug=True)
Async Usage
import aioboto3
from raindrop_bedrock import RaindropBedrock
rb = RaindropBedrock(api_key="rk_...", user_id="user-123")
session = aioboto3.Session()
async with session.client("bedrock-runtime", region_name="us-east-1") as client:
rb.async_wrap(client)
response = await client.converse(
modelId="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": [{"text": "Hello!"}]}],
)
rb.flush()
identify()
Associate a user with optional traits:
rb.identify(user_id="user-123", traits={"plan": "pro", "company": "Acme"})
track_signal()
Track feedback, edits, or custom signals:
rb.track_signal(
event_id="evt_abc123",
name="thumbs_up",
signal_type="feedback",
sentiment="POSITIVE",
comment="Great answer!",
)
flush() / shutdown()
Always call flush() before your process exits to ensure all telemetry is shipped:
rb.flush() # flush pending data
rb.shutdown() # flush + release resources
Legacy Factory Function
The create_raindrop_bedrock() factory function is still supported for backwards compatibility:
from raindrop_bedrock import create_raindrop_bedrock
raindrop = create_raindrop_bedrock(api_key="your-write-key", user_id="user-123")
client = boto3.client("bedrock-runtime", region_name="us-east-1")
raindrop.wrap(client)
What Gets Captured
| Method | Captured Data |
|---|---|
converse() |
Input messages, output text, model ID, token usage (inputTokens/outputTokens), stop reason (stopReason), cached tokens (cacheReadInputTokenCount, cacheWriteInputTokenCount), conversation ID |
invoke_model() |
Raw request/response bodies, model ID, token usage (Claude, Titan, and Llama formats), stop reason (Claude: stop_reason, Llama: stop_reason), cached tokens (Claude: cache_read_input_tokens) |
| Errors | Error type and message are captured in event properties, then the exception is re-raised |
Captured Properties
| Property Key | Source | Description |
|---|---|---|
ai.usage.prompt_tokens |
Both APIs | Input/prompt token count |
ai.usage.completion_tokens |
Both APIs | Output/completion token count |
ai.usage.cached_tokens |
Converse: cacheReadInputTokenCount; Claude InvokeModel: cache_read_input_tokens |
Tokens read from cache |
ai.usage.cache_write_tokens |
Converse: cacheWriteInputTokenCount |
Tokens written to cache |
bedrock.finish_reason |
Converse: stopReason; InvokeModel: varies by model |
Why the model stopped generating |
API Reference
RaindropBedrock(api_key=None, user_id=None, convo_id=None, project_id=None, tracing_enabled=True, bypass_otel_for_tools=True, disable_auto_instrument=True, debug=False)
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str | None |
None |
Raindrop API key. Warns if not provided. |
user_id |
str | None |
None |
Default user ID for events (falls back to "unknown") |
convo_id |
str | None |
None |
Group events into a conversation |
project_id |
str | None |
None |
Route events to a specific project (slug); omit for the default Production project |
tracing_enabled |
bool |
True |
Enable Raindrop tracing |
bypass_otel_for_tools |
bool |
True |
Bypass OpenTelemetry for tool-level instrumentation |
disable_auto_instrument |
bool |
True |
Library auto-instrumentation is opt-in (see below) |
debug |
bool |
False |
Enable verbose DEBUG-level logging |
Library auto-instrumentation is opt-in
As of 0.0.4, disable_auto_instrument defaults to True: the
integration no longer lets Traceloop monkey-patch every LLM client library
it recognizes in your process (botocore client creation, OpenAI, Anthropic, etc.). The
wrapper captures input/output, token usage, model name, and stop reason
directly from the wrapped boto3 client's responses, so no library patching is needed for full
dashboards.
If you specifically want LLM-call-level spans from library instrumentation
and have verified compatibility in your environment, opt back in with
disable_auto_instrument=False.
Methods
| Method | Description |
|---|---|
wrap(client) |
Instrument a sync boto3 bedrock-runtime client |
async_wrap(client) |
Instrument an async aioboto3 bedrock-runtime client |
identify(user_id, traits=None) |
Identify a user with optional traits |
track_signal(event_id, name, ...) |
Track a signal event |
flush() |
Flush pending events |
shutdown() |
Flush and shut down |
Testing
cd packages/bedrock-python
pip install -e ".[async]"
pip install pytest
python -m pytest tests/ -v
Known Limitations
- InvokeModel body replacement: After consuming the response body stream, it's replaced with a
BytesIOobject. Callers usingStreamingBody.read()will get the same bytes, but the originalStreamingBodyAPI is not preserved. - Async support requires the
[async]extra (aioboto3>=12.0.0).
Full Documentation
docs.raindrop.ai/integrations/bedrock
License
MIT
Release files for raindrop-bedrock 0.0.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| raindrop_bedrock-0.0.8.tar.gz | 29.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| raindrop_bedrock-0.0.8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.7 kB
Release files / raindrop_bedrock-0.0.8.tar.gz
| Download URL | raindrop_bedrock-0.0.8.tar.gz |
|---|---|
| Size | 29.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3ffef2f6553f8ba31e74009c432ebd9847f1858ede93fa4c397dec1a431ad343
|
|
BLAKE2b-256 checksum How to use checksums |
ac07d040b04aa5dc1386e4b399523d335c2721990fb06ad045b7c3a91da04ecc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / raindrop_bedrock-0.0.8-py3-none-any.whl
| Download URL | raindrop_bedrock-0.0.8-py3-none-any.whl |
|---|---|
| Size | 12.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d742603376367c24bb75b739f33a1f7e4971f7d3257eee5c885f266640179a16
|
|
BLAKE2b-256 checksum How to use checksums |
e425163ffb4dc250532497c89c9c63611b1b95354df7b516e56b29ef40ea052f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|