A comprehensive example demonstrating automatic observability for SurrealDB operations using Pydantic Logfire. This example shows how to instrument your SurrealDB connections to get instant visibility into database operations.
Pydantic Logfire is an observability platform built by the creators of Pydantic. It provides:
- Automatic instrumentation for popular Python libraries including SurrealDB
- OpenTelemetry compatibility - works with any OTel-compatible platform
- Smart defaults - automatically scrubs sensitive data
- Beautiful dashboards - purpose-built for Python applications
- Zero configuration - works out of the box for local development
- Automatic span creation: Every database operation creates a trace span
- Smart parameter logging: Query parameters and data logged (with sensitive data scrubbed)
- All connection types: Works with HTTP, WebSocket, and embedded databases
- CRUD operations: Create, Read, Update, Delete all instrumented
- Authentication: Signin, signup, invalidate operations traced
- Query operations: Raw SurrealQL queries with automatic logging
- Error tracking: Exceptions and errors captured in spans
- Python 3.10+
- Docker (for running SurrealDB)
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies
uv sync
# Copy environment file
cp .env.example .env
# Start SurrealDB
docker compose up -d# Install dependencies
pip install -r requirements.txt
# Copy environment file
cp .env.example .env
# Start SurrealDB
docker compose up -d# Run the example
uv run python main.py# Run the example
python main.pyThe example performs various database operations, each creating a span in the trace:
π§ Configuring Logfire...
π‘ Instrumenting SurrealDB...
π Connecting to database...
β
Connected to SurrealDB
Logfire is now tracing all SurrealDB operations!
Each operation below creates a span with details about the database call.
π€ Signing in...
ποΈ Using namespace and database...
β Creating users...
π Selecting all users...
π Querying users with SurrealQL...
βοΈ Updating user...
ποΈ Deleting user...
π§Ή Cleaning up...
β¨ Done! Check your terminal or Logfire dashboard for traces.
Console output shows each operation with timing information:
surrealdb signin username = root β±οΈ 15.2ms
surrealdb use namespace = test, database = test β±οΈ 2.1ms
surrealdb create β±οΈ 8.3ms
surrealdb select β±οΈ 3.2ms
surrealdb query β±οΈ 4.7ms
surrealdb update β±οΈ 5.1ms
surrealdb delete β±οΈ 3.8ms
Each line represents a span with:
- Operation name: The database method called
- Parameters: Non-sensitive parameters (passwords/tokens scrubbed)
- Duration: How long the operation took
Logfire creates spans with names like:
surrealdb signin- Authentication operationssurrealdb use- Namespace/database selectionsurrealdb create- Record creationsurrealdb select- Record selectionsurrealdb query- Raw SurrealQL queriessurrealdb update- Record updatessurrealdb delete- Record deletion
Each span includes attributes such as:
namespace- The SurrealDB namespacedatabase- The database namerecord- The record ID or table name- Non-sensitive parameters passed to the operation
Logfire automatically scrubs:
- Passwords
- Tokens
- Authentication credentials
- Any parameter containing "password", "token", "secret", etc.
Edit .env to configure:
# SurrealDB Configuration
SURREALDB_URL=ws://localhost:8000/rpc
SURREALDB_NAMESPACE=test
SURREALDB_DATABASE=test
SURREALDB_USERNAME=root
SURREALDB_PASSWORD=root
# Logfire Configuration (Optional)
# LOGFIRE_TOKEN=your_token_here # For sending to Logfire cloudFor cloud-based tracing (optional):
- Create a Logfire account at logfire.pydantic.dev
- Get your token from the dashboard
- Set the environment variable:
LOGFIRE_TOKEN=your_token_here - Run the example - traces will appear in your dashboard
For local development, Logfire works without a token and displays traces in the console.
import logfire
from surrealdb import AsyncSurreal
# Instrument all SurrealDB connections globally
logfire.configure()
logfire.instrument_surrealdb()
# All instances are now instrumented
db1 = AsyncSurreal("ws://localhost:8000")
db2 = AsyncSurreal("http://localhost:8000")import logfire
from surrealdb import AsyncSurreal
logfire.configure()
# Create connection
db = AsyncSurreal("ws://localhost:8000")
# Instrument just this instance
logfire.instrument_surrealdb(db)import logfire
from surrealdb.connections import AsyncHttpSurrealConnection
logfire.configure()
# Instrument only HTTP connections
logfire.instrument_surrealdb(AsyncHttpSurrealConnection)import logfire
# Configure with custom settings
logfire.configure(
service_name="my-surrealdb-app",
service_version="1.0.0",
environment="production",
console=True, # Show traces in console
)
logfire.instrument_surrealdb()import logfire
from surrealdb import AsyncSurreal
logfire.configure()
logfire.instrument_surrealdb()
async with AsyncSurreal("ws://localhost:8000") as db:
# Custom span for business logic
with logfire.span("user-registration-flow"):
await db.signin({"username": "root", "password": "root"})
await db.use("test", "test")
# These database operations are nested within your custom span
user = await db.create("user", {"email": "user@example.com"})
await db.create("profile", {"user_id": user["id"]})You can selectively instrument operations:
import logfire
from surrealdb import AsyncSurreal
# Only instrument, then manually control what gets traced
logfire.configure(console={"min_log_level": "info"})
logfire.instrument_surrealdb()logfire/
βββ main.py # Demo application
βββ config.py # Configuration management
βββ database.py # Database and instrumentation setup
βββ requirements.txt # Python dependencies (pip)
βββ pyproject.toml # Modern dependencies (uv)
βββ .env.example # Environment template
βββ docker-compose.yml # SurrealDB setup
βββ README.md # This file
Problem: Operations execute but no trace output appears.
Solution:
- Ensure
logfire.configure()is called before operations - Check that
logfire.instrument_surrealdb()is called after configure - Try
logfire.configure(console=True)to force console output
Problem: Passwords or tokens visible in traces.
Solution: Logfire should automatically scrub these. If not:
- Report an issue to Pydantic Logfire
- Use custom scrubbing rules in
logfire.configure()
Problem: Worried about instrumentation overhead.
Solution:
- Logfire overhead is minimal (<1ms per operation typically)
- Can be disabled in production with environment variable
- Sampling can be configured to reduce overhead
Problem: Cannot send traces to Logfire dashboard.
Solution:
- Check
LOGFIRE_TOKENis set correctly - Verify network connectivity
- For local development, console output works without token
Logfire exports standard OpenTelemetry data:
import logfire
logfire.configure(
# Export to OTLP collector
otlp_endpoint="http://localhost:4317"
)import logfire
logfire.configure(
# Jaeger endpoint
otlp_endpoint="http://localhost:14268/api/traces"
)All OpenTelemetry-compatible platforms work with Logfire's output.
- Logfire Documentation
- SurrealDB Python SDK
- OpenTelemetry Python
- Logfire SurrealDB Integration Source
Observability helps you:
- Debug issues faster: See exactly what database operations occurred
- Find performance bottlenecks: Identify slow queries
- Track down errors: See the full context when operations fail
- Monitor production: Understand database usage patterns
- Optimize queries: See which operations are most expensive
- Run this example to see instrumentation in action
- Add to your project: Use the same pattern in your application
- Explore Logfire dashboard: Sign up for cloud tracing
- Customize instrumentation: Add custom spans for your business logic
- Set up alerts: Get notified of slow queries or errors