You've reproduced a tricky bug on your local machine or a staging server. Your colleague is remote — different city, different timezone. The usual option is a screen-share call where you both stare at a terminal together.
There's a better way. Send them a URL and they can watch your log output live in their browser, no call required.
BunnyLogs streams log output to a URL. Anyone with the URL can watch — no login, no account, no browser extension. The stream is live: new log lines appear within milliseconds as they're emitted.
Go to bunnylogs.com, click "New log stream", and copy the UUID from the URL. Create a new stream for each debug session — this way the URL you share is specific to this investigation.
import logging
from bunnylogs import BunnyLogsHandler
# Replace existing handler temporarily, or add alongside it
debug_handler = BunnyLogsHandler("your-uuid-for-this-session")
logging.getLogger().addHandler(debug_handler)
Or, if you're using a debugger and want to add it at runtime:
# In a Python REPL or debugger prompt
import logging
from bunnylogs import BunnyLogsHandler
logging.getLogger().addHandler(BunnyLogsHandler("your-uuid"))
Paste bunnylogs.com/live/your-uuid into Slack, Teams, or email. They can open it immediately — no account required.
Walk through the steps that trigger the issue. Your colleague sees every log line appear in their browser in real time. They can scroll back to see earlier output. They can refresh to reconnect if they lose the WebSocket.
Not everyone can jump on a call. The BunnyLogs stream persists recent history — your colleague can open the URL an hour later and still see what happened during the debug session.
This is useful when:
Keep separate streams for development, staging, and production. Store the UUID in an environment variable:
import os
import logging
from bunnylogs import BunnyLogsHandler
uuid = os.environ.get("BUNNYLOGS_UUID")
if uuid:
logging.getLogger().addHandler(BunnyLogsHandler(uuid))
In your .env.development, .env.staging, and .env.production files, use different UUIDs. Now "share the staging logs" means sending one URL, and the production stream is never mixed with development noise.
When debugging, log not just events but state. Include request IDs, user IDs, and relevant values so the stream tells the full story:
def process_order(order_id: str, user_id: str):
logger.info(f"Processing order {order_id} for user {user_id}")
try:
result = charge_payment(order_id)
logger.info(f"Payment OK: {result.transaction_id}")
except PaymentError as e:
logger.error(f"Payment failed for order {order_id}: {e.code} — {e.message}")
raise
Your colleague sees the full context without needing access to your database or your machine.
April 22, 2025
March 11, 2025