or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

activity-handling.mdbot-adapters.mdindex.mdmessage-factories.mdmiddleware.mdoauth-authentication.mdstate-management.mdstorage.mdtelemetry-logging.mdtesting-utilities.mdturn-context.md

telemetry-logging.mddocs/

0

# Telemetry & Logging

1

2

Telemetry and logging functionality for monitoring bot performance, usage analytics, and debugging. Includes telemetry clients, logging middleware, and transcript storage.

3

4

## Capabilities

5

6

### BotTelemetryClient

7

8

Abstract base class for telemetry clients that defines the interface for tracking bot events, exceptions, and custom metrics for monitoring and analytics.

9

10

```python { .api }

11

class BotTelemetryClient:

12

def track_event(self, name: str, properties: dict = None, measurements: dict = None):

13

"""

14

Track custom telemetry events.

15

16

Args:

17

name (str): Event name

18

properties (dict, optional): Event properties

19

measurements (dict, optional): Event measurements

20

"""

21

22

def track_exception(self, exception, properties: dict = None, measurements: dict = None):

23

"""

24

Track exceptions for monitoring.

25

26

Args:

27

exception (Exception): Exception to track

28

properties (dict, optional): Additional properties

29

measurements (dict, optional): Additional measurements

30

"""

31

32

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):

33

"""Track dependency calls."""

34

35

def track_trace(self, name: str, properties: dict = None, severity=None):

36

"""Track trace messages."""

37

38

def track_page_view(self, name: str, url: str = None, duration: int = None, properties: dict = None, measurements: dict = None):

39

"""Track page views."""

40

41

def flush(self):

42

"""Flush telemetry data."""

43

```

44

45

### NullTelemetryClient

46

47

No-operation telemetry client that provides a default implementation for scenarios where telemetry is not needed or configured.

48

49

```python { .api }

50

class NullTelemetryClient(BotTelemetryClient):

51

def track_event(self, name: str, properties: dict = None, measurements: dict = None):

52

"""No-op track event implementation."""

53

54

def track_exception(self, exception, properties: dict = None, measurements: dict = None):

55

"""No-op track exception implementation."""

56

57

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):

58

"""No-op track dependency implementation."""

59

60

def track_trace(self, name: str, properties: dict = None, severity=None):

61

"""No-op track trace implementation."""

62

63

def track_page_view(self, name: str, url: str = None, duration: int = None, properties: dict = None, measurements: dict = None):

64

"""No-op track page view implementation."""

65

66

def flush(self):

67

"""No-op flush implementation."""

68

```

69

70

### TranscriptLogger

71

72

Abstract base class for transcript logging that defines the interface for storing conversation transcripts for audit and debugging purposes.

73

74

```python { .api }

75

class TranscriptLogger:

76

async def log_activity(self, activity):

77

"""

78

Log activity to transcript store.

79

80

Args:

81

activity (Activity): Activity to log

82

"""

83

84

async def get_transcript_activities(self, channel_id: str, conversation_id: str, continuation_token: str = None, start_date = None):

85

"""

86

Get transcript activities from store.

87

88

Args:

89

channel_id (str): Channel ID

90

conversation_id (str): Conversation ID

91

continuation_token (str, optional): Continuation token for paging

92

start_date (optional): Start date filter

93

94

Returns:

95

PagedResult: Paged transcript activities

96

"""

97

98

async def list_transcripts(self, channel_id: str, continuation_token: str = None):

99

"""

100

List available transcripts.

101

102

Args:

103

channel_id (str): Channel ID

104

continuation_token (str, optional): Continuation token for paging

105

106

Returns:

107

PagedResult: Paged transcript summaries

108

"""

109

110

async def delete_transcript(self, channel_id: str, conversation_id: str):

111

"""

112

Delete transcript.

113

114

Args:

115

channel_id (str): Channel ID

116

conversation_id (str): Conversation ID

117

"""

118

```

119

120

### MemoryTranscriptStore

121

122

In-memory implementation of transcript logger for development and testing scenarios where persistent transcript storage is not required.

123

124

```python { .api }

125

class MemoryTranscriptStore(TranscriptLogger):

126

def __init__(self):

127

"""Initialize memory transcript store."""

128

129

async def log_activity(self, activity):

130

"""Log activity to memory store."""

131

132

async def get_transcript_activities(self, channel_id: str, conversation_id: str, continuation_token: str = None, start_date = None):

133

"""Get transcript activities from memory."""

134

135

async def list_transcripts(self, channel_id: str, continuation_token: str = None):

136

"""List transcripts from memory."""

137

138

async def delete_transcript(self, channel_id: str, conversation_id: str):

139

"""Delete transcript from memory."""

140

```

141

142

### Severity Enum

143

144

Enumeration of telemetry severity levels for categorizing telemetry events and traces.

145

146

```python { .api }

147

class Severity:

148

VERBOSE = 0

149

INFORMATION = 1

150

WARNING = 2

151

ERROR = 3

152

CRITICAL = 4

153

```

154

155

### Telemetry Constants

156

157

Constants used throughout the telemetry system for standard property names and event types.

158

159

```python { .api }

160

class TelemetryConstants:

161

ACTIVITY_ID_PROPERTY = "activityId"

162

ACTIVITY_TYPE_PROPERTY = "activityType"

163

CHANNEL_ID_PROPERTY = "channelId"

164

CONVERSATION_ID_PROPERTY = "conversationId"

165

CONVERSATION_NAME_PROPERTY = "conversationName"

166

DIALOG_ID_PROPERTY = "dialogId"

167

FROM_ID_PROPERTY = "fromId"

168

FROM_NAME_PROPERTY = "fromName"

169

LOCALE_PROPERTY = "locale"

170

RECIPIENT_ID_PROPERTY = "recipientId"

171

RECIPIENT_NAME_PROPERTY = "recipientName"

172

REPLY_ACTIVITY_ID_PROPERTY = "replyActivityId"

173

TEXT_PROPERTY = "text"

174

SPEAK_PROPERTY = "speak"

175

USER_ID_PROPERTY = "userId"

176

```

177

178

## Usage Examples

179

180

### Basic Telemetry Setup

181

182

```python

183

from botbuilder.core import ActivityHandler, TurnContext, BotTelemetryClient

184

185

class TelemetryBot(ActivityHandler):

186

def __init__(self, telemetry_client: BotTelemetryClient):

187

self.telemetry_client = telemetry_client

188

189

async def on_message_activity(self, turn_context: TurnContext):

190

# Track message received event

191

self.telemetry_client.track_event(

192

"MessageReceived",

193

properties={

194

"conversationId": turn_context.activity.conversation.id,

195

"userId": turn_context.activity.from_property.id,

196

"text": turn_context.activity.text[:100] # Truncate for privacy

197

}

198

)

199

200

try:

201

# Process message

202

response = await self.process_message(turn_context.activity.text)

203

await turn_context.send_activity(MessageFactory.text(response))

204

205

# Track successful response

206

self.telemetry_client.track_event(

207

"MessageProcessed",

208

properties={

209

"conversationId": turn_context.activity.conversation.id,

210

"success": "true"

211

}

212

)

213

214

except Exception as e:

215

# Track exceptions

216

self.telemetry_client.track_exception(

217

e,

218

properties={

219

"conversationId": turn_context.activity.conversation.id,

220

"userId": turn_context.activity.from_property.id

221

}

222

)

223

await turn_context.send_activity(MessageFactory.text("Sorry, an error occurred"))

224

225

async def process_message(self, text: str):

226

# Simulate some processing

227

import time

228

start_time = time.time()

229

230

# Track dependency call (e.g., to external API)

231

try:

232

result = await self.call_external_api(text)

233

duration = int((time.time() - start_time) * 1000)

234

235

self.telemetry_client.track_dependency(

236

name="ExternalAPI",

237

data=f"ProcessText: {text[:50]}",

238

type_name="HTTP",

239

target="api.example.com",

240

duration=duration,

241

success=True,

242

result_code="200"

243

)

244

245

return result

246

247

except Exception as e:

248

duration = int((time.time() - start_time) * 1000)

249

250

self.telemetry_client.track_dependency(

251

name="ExternalAPI",

252

data=f"ProcessText: {text[:50]}",

253

type_name="HTTP",

254

target="api.example.com",

255

duration=duration,

256

success=False,

257

result_code="500"

258

)

259

raise

260

```

261

262

### Transcript Logging

263

264

```python

265

from botbuilder.core import MemoryTranscriptStore, TranscriptLoggerMiddleware

266

267

class TranscriptBot(ActivityHandler):

268

def __init__(self):

269

# Create transcript store

270

self.transcript_store = MemoryTranscriptStore()

271

272

# Add transcript logging middleware to adapter

273

self.adapter.use(TranscriptLoggerMiddleware(self.transcript_store))

274

275

async def on_message_activity(self, turn_context: TurnContext):

276

# Regular bot processing - transcript logging happens automatically

277

await turn_context.send_activity(MessageFactory.text(f"You said: {turn_context.activity.text}"))

278

279

async def get_conversation_history(self, channel_id: str, conversation_id: str):

280

"""Get conversation transcript."""

281

transcript = await self.transcript_store.get_transcript_activities(

282

channel_id,

283

conversation_id

284

)

285

return transcript.items

286

```

287

288

### Custom Telemetry Client

289

290

```python

291

import logging

292

293

class CustomTelemetryClient(BotTelemetryClient):

294

def __init__(self, logger=None):

295

self.logger = logger or logging.getLogger(__name__)

296

297

def track_event(self, name: str, properties: dict = None, measurements: dict = None):

298

"""Custom event tracking implementation."""

299

log_data = {

300

"event": name,

301

"properties": properties or {},

302

"measurements": measurements or {}

303

}

304

self.logger.info(f"Event: {log_data}")

305

306

# Send to your analytics service

307

# await self.send_to_analytics_service(log_data)

308

309

def track_exception(self, exception, properties: dict = None, measurements: dict = None):

310

"""Custom exception tracking."""

311

log_data = {

312

"exception": str(exception),

313

"type": type(exception).__name__,

314

"properties": properties or {}

315

}

316

self.logger.error(f"Exception: {log_data}")

317

318

# Send to your error tracking service

319

# await self.send_to_error_service(log_data)

320

321

def track_trace(self, name: str, properties: dict = None, severity=None):

322

"""Custom trace tracking."""

323

level = logging.INFO

324

if severity == Severity.WARNING:

325

level = logging.WARNING

326

elif severity == Severity.ERROR:

327

level = logging.ERROR

328

elif severity == Severity.CRITICAL:

329

level = logging.CRITICAL

330

331

self.logger.log(level, f"Trace: {name}", extra=properties or {})

332

333

def flush(self):

334

"""Flush telemetry data."""

335

# Implement flushing logic for your telemetry backend

336

pass

337

```

338

339

### Performance Metrics

340

341

```python

342

import time

343

from botbuilder.core import Middleware

344

345

class PerformanceTelemetryMiddleware(Middleware):

346

def __init__(self, telemetry_client: BotTelemetryClient):

347

self.telemetry_client = telemetry_client

348

349

async def on_turn(self, turn_context: TurnContext, next_middleware):

350

start_time = time.time()

351

352

try:

353

await next_middleware()

354

355

# Track successful turn

356

duration = (time.time() - start_time) * 1000

357

self.telemetry_client.track_event(

358

"TurnCompleted",

359

properties={

360

"conversationId": turn_context.activity.conversation.id,

361

"activityType": turn_context.activity.type

362

},

363

measurements={

364

"durationMs": duration

365

}

366

)

367

368

except Exception as e:

369

# Track failed turn

370

duration = (time.time() - start_time) * 1000

371

self.telemetry_client.track_event(

372

"TurnFailed",

373

properties={

374

"conversationId": turn_context.activity.conversation.id,

375

"error": str(e)

376

},

377

measurements={

378

"durationMs": duration

379

}

380

)

381

raise

382

```

383

384

## Types

385

386

```python { .api }

387

class PagedResult:

388

"""Paged result for transcript queries."""

389

def __init__(self):

390

self.items: list = []

391

self.continuation_token: str = None

392

393

class TranscriptInfo:

394

"""Information about a transcript."""

395

def __init__(self):

396

self.channel_id: str = None

397

self.id: str = None

398

self.created: str = None

399

```