Microsoft Bot Framework Bot Builder core functionality for building conversational AI bots and chatbots in Python.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Telemetry and logging functionality for monitoring bot performance, usage analytics, and debugging. Includes telemetry clients, logging middleware, and transcript storage.
Abstract base class for telemetry clients that defines the interface for tracking bot events, exceptions, and custom metrics for monitoring and analytics.
class BotTelemetryClient:
def track_event(self, name: str, properties: dict = None, measurements: dict = None):
"""
Track custom telemetry events.
Args:
name (str): Event name
properties (dict, optional): Event properties
measurements (dict, optional): Event measurements
"""
def track_exception(self, exception, properties: dict = None, measurements: dict = None):
"""
Track exceptions for monitoring.
Args:
exception (Exception): Exception to track
properties (dict, optional): Additional properties
measurements (dict, optional): Additional measurements
"""
def track_dependency(self, name: str, data: str, type_name: str, target: str, duration: int, success: bool, result_code: str = None, properties: dict = None, measurements: dict = None):
"""Track dependency calls."""
def track_trace(self, name: str, properties: dict = None, severity=None):
"""Track trace messages."""
def track_page_view(self, name: str, url: str = None, duration: int = None, properties: dict = None, measurements: dict = None):
"""Track page views."""
def flush(self):
"""Flush telemetry data."""No-operation telemetry client that provides a default implementation for scenarios where telemetry is not needed or configured.
class NullTelemetryClient(BotTelemetryClient):
def track_event(self, name: str, properties: dict = None, measurements: dict = None):
"""No-op track event implementation."""
def track_exception(self, exception, properties: dict = None, measurements: dict = None):
"""No-op track exception implementation."""
def track_dependency(self, name: str, data: str, type_name: str, target: str, duration: int, success: bool, result_code: str = None, properties: dict = None, measurements: dict = None):
"""No-op track dependency implementation."""
def track_trace(self, name: str, properties: dict = None, severity=None):
"""No-op track trace implementation."""
def track_page_view(self, name: str, url: str = None, duration: int = None, properties: dict = None, measurements: dict = None):
"""No-op track page view implementation."""
def flush(self):
"""No-op flush implementation."""Abstract base class for transcript logging that defines the interface for storing conversation transcripts for audit and debugging purposes.
class TranscriptLogger:
async def log_activity(self, activity):
"""
Log activity to transcript store.
Args:
activity (Activity): Activity to log
"""
async def get_transcript_activities(self, channel_id: str, conversation_id: str, continuation_token: str = None, start_date = None):
"""
Get transcript activities from store.
Args:
channel_id (str): Channel ID
conversation_id (str): Conversation ID
continuation_token (str, optional): Continuation token for paging
start_date (optional): Start date filter
Returns:
PagedResult: Paged transcript activities
"""
async def list_transcripts(self, channel_id: str, continuation_token: str = None):
"""
List available transcripts.
Args:
channel_id (str): Channel ID
continuation_token (str, optional): Continuation token for paging
Returns:
PagedResult: Paged transcript summaries
"""
async def delete_transcript(self, channel_id: str, conversation_id: str):
"""
Delete transcript.
Args:
channel_id (str): Channel ID
conversation_id (str): Conversation ID
"""In-memory implementation of transcript logger for development and testing scenarios where persistent transcript storage is not required.
class MemoryTranscriptStore(TranscriptLogger):
def __init__(self):
"""Initialize memory transcript store."""
async def log_activity(self, activity):
"""Log activity to memory store."""
async def get_transcript_activities(self, channel_id: str, conversation_id: str, continuation_token: str = None, start_date = None):
"""Get transcript activities from memory."""
async def list_transcripts(self, channel_id: str, continuation_token: str = None):
"""List transcripts from memory."""
async def delete_transcript(self, channel_id: str, conversation_id: str):
"""Delete transcript from memory."""Enumeration of telemetry severity levels for categorizing telemetry events and traces.
class Severity:
VERBOSE = 0
INFORMATION = 1
WARNING = 2
ERROR = 3
CRITICAL = 4Constants used throughout the telemetry system for standard property names and event types.
class TelemetryConstants:
ACTIVITY_ID_PROPERTY = "activityId"
ACTIVITY_TYPE_PROPERTY = "activityType"
CHANNEL_ID_PROPERTY = "channelId"
CONVERSATION_ID_PROPERTY = "conversationId"
CONVERSATION_NAME_PROPERTY = "conversationName"
DIALOG_ID_PROPERTY = "dialogId"
FROM_ID_PROPERTY = "fromId"
FROM_NAME_PROPERTY = "fromName"
LOCALE_PROPERTY = "locale"
RECIPIENT_ID_PROPERTY = "recipientId"
RECIPIENT_NAME_PROPERTY = "recipientName"
REPLY_ACTIVITY_ID_PROPERTY = "replyActivityId"
TEXT_PROPERTY = "text"
SPEAK_PROPERTY = "speak"
USER_ID_PROPERTY = "userId"from botbuilder.core import ActivityHandler, TurnContext, BotTelemetryClient
class TelemetryBot(ActivityHandler):
def __init__(self, telemetry_client: BotTelemetryClient):
self.telemetry_client = telemetry_client
async def on_message_activity(self, turn_context: TurnContext):
# Track message received event
self.telemetry_client.track_event(
"MessageReceived",
properties={
"conversationId": turn_context.activity.conversation.id,
"userId": turn_context.activity.from_property.id,
"text": turn_context.activity.text[:100] # Truncate for privacy
}
)
try:
# Process message
response = await self.process_message(turn_context.activity.text)
await turn_context.send_activity(MessageFactory.text(response))
# Track successful response
self.telemetry_client.track_event(
"MessageProcessed",
properties={
"conversationId": turn_context.activity.conversation.id,
"success": "true"
}
)
except Exception as e:
# Track exceptions
self.telemetry_client.track_exception(
e,
properties={
"conversationId": turn_context.activity.conversation.id,
"userId": turn_context.activity.from_property.id
}
)
await turn_context.send_activity(MessageFactory.text("Sorry, an error occurred"))
async def process_message(self, text: str):
# Simulate some processing
import time
start_time = time.time()
# Track dependency call (e.g., to external API)
try:
result = await self.call_external_api(text)
duration = int((time.time() - start_time) * 1000)
self.telemetry_client.track_dependency(
name="ExternalAPI",
data=f"ProcessText: {text[:50]}",
type_name="HTTP",
target="api.example.com",
duration=duration,
success=True,
result_code="200"
)
return result
except Exception as e:
duration = int((time.time() - start_time) * 1000)
self.telemetry_client.track_dependency(
name="ExternalAPI",
data=f"ProcessText: {text[:50]}",
type_name="HTTP",
target="api.example.com",
duration=duration,
success=False,
result_code="500"
)
raisefrom botbuilder.core import MemoryTranscriptStore, TranscriptLoggerMiddleware
class TranscriptBot(ActivityHandler):
def __init__(self):
# Create transcript store
self.transcript_store = MemoryTranscriptStore()
# Add transcript logging middleware to adapter
self.adapter.use(TranscriptLoggerMiddleware(self.transcript_store))
async def on_message_activity(self, turn_context: TurnContext):
# Regular bot processing - transcript logging happens automatically
await turn_context.send_activity(MessageFactory.text(f"You said: {turn_context.activity.text}"))
async def get_conversation_history(self, channel_id: str, conversation_id: str):
"""Get conversation transcript."""
transcript = await self.transcript_store.get_transcript_activities(
channel_id,
conversation_id
)
return transcript.itemsimport logging
class CustomTelemetryClient(BotTelemetryClient):
def __init__(self, logger=None):
self.logger = logger or logging.getLogger(__name__)
def track_event(self, name: str, properties: dict = None, measurements: dict = None):
"""Custom event tracking implementation."""
log_data = {
"event": name,
"properties": properties or {},
"measurements": measurements or {}
}
self.logger.info(f"Event: {log_data}")
# Send to your analytics service
# await self.send_to_analytics_service(log_data)
def track_exception(self, exception, properties: dict = None, measurements: dict = None):
"""Custom exception tracking."""
log_data = {
"exception": str(exception),
"type": type(exception).__name__,
"properties": properties or {}
}
self.logger.error(f"Exception: {log_data}")
# Send to your error tracking service
# await self.send_to_error_service(log_data)
def track_trace(self, name: str, properties: dict = None, severity=None):
"""Custom trace tracking."""
level = logging.INFO
if severity == Severity.WARNING:
level = logging.WARNING
elif severity == Severity.ERROR:
level = logging.ERROR
elif severity == Severity.CRITICAL:
level = logging.CRITICAL
self.logger.log(level, f"Trace: {name}", extra=properties or {})
def flush(self):
"""Flush telemetry data."""
# Implement flushing logic for your telemetry backend
passimport time
from botbuilder.core import Middleware
class PerformanceTelemetryMiddleware(Middleware):
def __init__(self, telemetry_client: BotTelemetryClient):
self.telemetry_client = telemetry_client
async def on_turn(self, turn_context: TurnContext, next_middleware):
start_time = time.time()
try:
await next_middleware()
# Track successful turn
duration = (time.time() - start_time) * 1000
self.telemetry_client.track_event(
"TurnCompleted",
properties={
"conversationId": turn_context.activity.conversation.id,
"activityType": turn_context.activity.type
},
measurements={
"durationMs": duration
}
)
except Exception as e:
# Track failed turn
duration = (time.time() - start_time) * 1000
self.telemetry_client.track_event(
"TurnFailed",
properties={
"conversationId": turn_context.activity.conversation.id,
"error": str(e)
},
measurements={
"durationMs": duration
}
)
raiseclass PagedResult:
"""Paged result for transcript queries."""
def __init__(self):
self.items: list = []
self.continuation_token: str = None
class TranscriptInfo:
"""Information about a transcript."""
def __init__(self):
self.channel_id: str = None
self.id: str = None
self.created: str = NoneInstall with Tessl CLI
npx tessl i tessl/pypi-botbuilder-core