or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

administration.mdassistants-threads.mdbatch-processing.mdbeta-realtime.mdchat-completions.mdconfiguration-management.mdcontainer-content.mdcore-client.mdembeddings.mdevaluation-testing.mdfeedback-collections.mdfile-management.mdfine-tuning.mdframework-integrations.mdindex.mdkey-management.mdmodels.mdmultimodal-apis.mdobservability-analytics.mdprompt-management.mdprovider-integration.mdtext-completions.mduploads.mdvector-stores.md

observability-analytics.mddocs/

0

# Observability & Analytics

1

2

Comprehensive logging, request tracing, analytics, and monitoring capabilities with custom metadata and performance metrics.

3

4

## Capabilities

5

6

### Request Logging

7

8

Track and analyze all API requests with detailed logging capabilities including request/response data, performance metrics, and custom metadata.

9

10

```python { .api }

11

class Logs:

12

"""Request logging and retrieval"""

13

14

def list(

15

self,

16

*,

17

limit: Optional[int] = None,

18

after: Optional[str] = None,

19

before: Optional[str] = None,

20

order: Optional[str] = None,

21

filters: Optional[dict] = None,

22

**kwargs

23

) -> dict:

24

"""

25

List request logs with filtering and pagination.

26

27

Parameters:

28

- limit: Maximum number of logs to retrieve

29

- after: Cursor for pagination (logs after this ID)

30

- before: Cursor for pagination (logs before this ID)

31

- order: Sort order ('asc' or 'desc')

32

- filters: Filter criteria (date range, model, provider, etc.)

33

34

Returns:

35

Dictionary containing log entries and pagination info

36

"""

37

38

def retrieve(

39

self,

40

log_id: str,

41

**kwargs

42

) -> dict:

43

"""

44

Retrieve a specific log entry by ID.

45

46

Parameters:

47

- log_id: Unique identifier for the log entry

48

49

Returns:

50

Detailed log entry with request/response data

51

"""

52

53

class AsyncLogs:

54

"""Async request logging and retrieval"""

55

56

async def list(self, **kwargs) -> dict: ...

57

async def retrieve(self, log_id: str, **kwargs) -> dict: ...

58

```

59

60

### Response Analysis

61

62

Analyze API responses with detailed breakdowns of input/output tokens, performance metrics, and content analysis.

63

64

```python { .api }

65

class Responses:

66

"""Response analysis and metrics"""

67

68

def list(

69

self,

70

*,

71

limit: Optional[int] = None,

72

after: Optional[str] = None,

73

before: Optional[str] = None,

74

filters: Optional[dict] = None,

75

**kwargs

76

) -> dict:

77

"""List and analyze API responses"""

78

79

def retrieve(

80

self,

81

response_id: str,

82

**kwargs

83

) -> dict:

84

"""Retrieve detailed response analysis"""

85

86

input_items: InputItems

87

output_items: OutputItems

88

89

class InputItems:

90

"""Input content analysis"""

91

92

def list(self, **kwargs) -> dict: ...

93

def retrieve(self, item_id: str, **kwargs) -> dict: ...

94

95

class OutputItems:

96

"""Output content analysis"""

97

98

def list(self, **kwargs) -> dict: ...

99

def retrieve(self, item_id: str, **kwargs) -> dict: ...

100

101

class AsyncResponses:

102

"""Async response analysis"""

103

104

async def list(self, **kwargs) -> dict: ...

105

async def retrieve(self, response_id: str, **kwargs) -> dict: ...

106

input_items: AsyncInputItems

107

output_items: AsyncOutputItems

108

```

109

110

### Request Labeling

111

112

Categorize and tag API requests for better organization, analysis, and filtering.

113

114

```python { .api }

115

class Labels:

116

"""Request labeling and categorization"""

117

118

def create(

119

self,

120

*,

121

log_id: str,

122

label: str,

123

value: Optional[str] = None,

124

**kwargs

125

) -> dict:

126

"""

127

Create a label for a request log.

128

129

Parameters:

130

- log_id: ID of the log entry to label

131

- label: Label name/category

132

- value: Optional label value

133

134

Returns:

135

Created label object

136

"""

137

138

def list(

139

self,

140

*,

141

log_id: Optional[str] = None,

142

label: Optional[str] = None,

143

**kwargs

144

) -> dict:

145

"""List labels with optional filtering"""

146

147

def update(

148

self,

149

label_id: str,

150

*,

151

value: Optional[str] = None,

152

**kwargs

153

) -> dict:

154

"""Update an existing label"""

155

156

def delete(

157

self,

158

label_id: str,

159

**kwargs

160

) -> dict:

161

"""Delete a label"""

162

163

class AsyncLabels:

164

"""Async request labeling"""

165

166

async def create(self, **kwargs) -> dict: ...

167

async def list(self, **kwargs) -> dict: ...

168

async def update(self, label_id: str, **kwargs) -> dict: ...

169

async def delete(self, label_id: str, **kwargs) -> dict: ...

170

```

171

172

## Usage Examples

173

174

### Basic Request Logging

175

176

```python

177

from portkey_ai import Portkey

178

179

# Initialize with observability enabled

180

portkey = Portkey(

181

api_key="PORTKEY_API_KEY",

182

virtual_key="VIRTUAL_KEY",

183

debug=True, # Enable detailed logging

184

metadata={

185

"environment": "production",

186

"user_id": "user123",

187

"session_id": "session456"

188

}

189

)

190

191

# Make a request (automatically logged)

192

response = portkey.chat.completions.create(

193

messages=[{"role": "user", "content": "Hello"}],

194

model="gpt-4",

195

metadata={

196

"request_type": "greeting",

197

"category": "customer_support"

198

}

199

)

200

201

# Retrieve recent logs

202

logs = portkey.logs.list(limit=10, order="desc")

203

print(f"Found {len(logs['data'])} recent requests")

204

205

for log in logs['data']:

206

print(f"Request {log['id']}: {log['model']} - {log['status']}")

207

print(f" Tokens: {log['usage']['total_tokens']}")

208

print(f" Duration: {log['duration_ms']}ms")

209

```

210

211

### Advanced Log Filtering

212

213

```python

214

from datetime import datetime, timedelta

215

216

# Filter logs by date range and criteria

217

yesterday = datetime.now() - timedelta(days=1)

218

logs = portkey.logs.list(

219

filters={

220

"date": {

221

"gte": yesterday.isoformat(),

222

"lte": datetime.now().isoformat()

223

},

224

"model": "gpt-4",

225

"status": "success",

226

"provider": "openai",

227

"metadata.environment": "production"

228

},

229

limit=50

230

)

231

232

# Analyze request patterns

233

total_requests = len(logs['data'])

234

total_tokens = sum(log['usage']['total_tokens'] for log in logs['data'])

235

avg_latency = sum(log['duration_ms'] for log in logs['data']) / total_requests

236

237

print(f"Analysis for last 24 hours:")

238

print(f" Total requests: {total_requests}")

239

print(f" Total tokens: {total_tokens}")

240

print(f" Average latency: {avg_latency:.2f}ms")

241

```

242

243

### Request Tracing

244

245

```python

246

import uuid

247

248

# Use trace IDs to track request flows

249

trace_id = str(uuid.uuid4())

250

251

# First request in trace

252

response1 = portkey.chat.completions.create(

253

messages=[{"role": "user", "content": "What is Python?"}],

254

model="gpt-4",

255

trace_id=trace_id,

256

metadata={"step": "initial_query"}

257

)

258

259

# Follow-up request in same trace

260

response2 = portkey.chat.completions.create(

261

messages=[

262

{"role": "user", "content": "What is Python?"},

263

{"role": "assistant", "content": response1.choices[0].message.content},

264

{"role": "user", "content": "Give me a code example"}

265

],

266

model="gpt-4",

267

trace_id=trace_id,

268

metadata={"step": "follow_up"}

269

)

270

271

# Retrieve all logs for this trace

272

trace_logs = portkey.logs.list(

273

filters={"trace_id": trace_id}

274

)

275

276

print(f"Trace {trace_id} has {len(trace_logs['data'])} requests")

277

```

278

279

### Response Analysis

280

281

```python

282

# Analyze response patterns and content

283

responses = portkey.responses.list(

284

filters={

285

"model": "gpt-4",

286

"date": {"gte": "2024-01-01"}

287

},

288

limit=100

289

)

290

291

# Analyze input/output patterns

292

for response in responses['data']:

293

response_detail = portkey.responses.retrieve(response['id'])

294

295

print(f"Response {response['id']}:")

296

print(f" Input tokens: {response_detail['input_tokens']}")

297

print(f" Output tokens: {response_detail['output_tokens']}")

298

print(f" Cost: ${response_detail['cost']:.4f}")

299

300

# Analyze input items

301

input_items = portkey.responses.input_items.list(

302

response_id=response['id']

303

)

304

305

# Analyze output items

306

output_items = portkey.responses.output_items.list(

307

response_id=response['id']

308

)

309

```

310

311

### Request Labeling and Categorization

312

313

```python

314

# Create labels for request categorization

315

recent_logs = portkey.logs.list(limit=20)

316

317

for log in recent_logs['data']:

318

# Auto-label based on content

319

if 'translate' in log['request']['messages'][0]['content'].lower():

320

portkey.labels.create(

321

log_id=log['id'],

322

label="category",

323

value="translation"

324

)

325

elif 'code' in log['request']['messages'][0]['content'].lower():

326

portkey.labels.create(

327

log_id=log['id'],

328

label="category",

329

value="coding"

330

)

331

332

# Label by performance

333

if log['duration_ms'] > 5000:

334

portkey.labels.create(

335

log_id=log['id'],

336

label="performance",

337

value="slow"

338

)

339

340

# Query logs by labels

341

coding_requests = portkey.logs.list(

342

filters={"labels.category": "coding"}

343

)

344

345

slow_requests = portkey.logs.list(

346

filters={"labels.performance": "slow"}

347

)

348

349

print(f"Found {len(coding_requests['data'])} coding requests")

350

print(f"Found {len(slow_requests['data'])} slow requests")

351

```

352

353

### Real-time Monitoring

354

355

```python

356

import time

357

358

def monitor_requests():

359

"""Monitor requests in real-time"""

360

last_check = datetime.now()

361

362

while True:

363

# Get new logs since last check

364

new_logs = portkey.logs.list(

365

filters={

366

"date": {"gte": last_check.isoformat()}

367

},

368

order="asc"

369

)

370

371

for log in new_logs['data']:

372

print(f"New request: {log['id']}")

373

print(f" Model: {log['model']}")

374

print(f" Status: {log['status']}")

375

print(f" Duration: {log['duration_ms']}ms")

376

print(f" Tokens: {log['usage']['total_tokens']}")

377

378

# Alert on errors

379

if log['status'] == 'error':

380

print(f" ERROR: {log['error']['message']}")

381

382

# Alert on slow requests

383

if log['duration_ms'] > 10000:

384

print(f" WARNING: Slow request ({log['duration_ms']}ms)")

385

386

last_check = datetime.now()

387

time.sleep(30) # Check every 30 seconds

388

389

# Run monitoring (in production, use proper async/threading)

390

# monitor_requests()

391

```

392

393

### Custom Analytics Dashboard

394

395

```python

396

from collections import defaultdict

397

398

def generate_analytics_report(days=7):

399

"""Generate comprehensive analytics report"""

400

401

# Get logs for specified period

402

start_date = datetime.now() - timedelta(days=days)

403

logs = portkey.logs.list(

404

filters={

405

"date": {"gte": start_date.isoformat()}

406

},

407

limit=1000

408

)

409

410

# Aggregate metrics

411

metrics = {

412

'total_requests': len(logs['data']),

413

'by_model': defaultdict(int),

414

'by_provider': defaultdict(int),

415

'by_status': defaultdict(int),

416

'total_tokens': 0,

417

'total_cost': 0,

418

'avg_latency': 0,

419

'error_rate': 0

420

}

421

422

latencies = []

423

errors = 0

424

425

for log in logs['data']:

426

metrics['by_model'][log['model']] += 1

427

metrics['by_provider'][log['provider']] += 1

428

metrics['by_status'][log['status']] += 1

429

metrics['total_tokens'] += log['usage']['total_tokens']

430

metrics['total_cost'] += log['cost']

431

latencies.append(log['duration_ms'])

432

433

if log['status'] == 'error':

434

errors += 1

435

436

metrics['avg_latency'] = sum(latencies) / len(latencies) if latencies else 0

437

metrics['error_rate'] = (errors / len(logs['data'])) * 100 if logs['data'] else 0

438

439

# Print report

440

print(f"Analytics Report ({days} days)")

441

print("=" * 40)

442

print(f"Total Requests: {metrics['total_requests']}")

443

print(f"Total Tokens: {metrics['total_tokens']:,}")

444

print(f"Total Cost: ${metrics['total_cost']:.2f}")

445

print(f"Average Latency: {metrics['avg_latency']:.0f}ms")

446

print(f"Error Rate: {metrics['error_rate']:.2f}%")

447

448

print("\nTop Models:")

449

for model, count in sorted(metrics['by_model'].items(), key=lambda x: x[1], reverse=True)[:5]:

450

print(f" {model}: {count} requests")

451

452

print("\nProviders:")

453

for provider, count in metrics['by_provider'].items():

454

print(f" {provider}: {count} requests")

455

456

return metrics

457

458

# Generate report

459

analytics = generate_analytics_report(days=30)

460

```

461

462

### Async Observability Operations

463

464

```python

465

import asyncio

466

from portkey_ai import AsyncPortkey

467

468

async def async_observability_example():

469

portkey = AsyncPortkey(

470

api_key="PORTKEY_API_KEY",

471

virtual_key="VIRTUAL_KEY"

472

)

473

474

# Make async request with metadata

475

response = await portkey.chat.completions.create(

476

messages=[{"role": "user", "content": "Hello async world"}],

477

model="gpt-4",

478

metadata={"async": "true", "test": "observability"}

479

)

480

481

# Async log retrieval

482

logs = await portkey.logs.list(limit=5)

483

484

# Async labeling

485

if logs['data']:

486

await portkey.labels.create(

487

log_id=logs['data'][0]['id'],

488

label="async_test",

489

value="true"

490

)

491

492

# Async response analysis

493

responses = await portkey.responses.list(limit=5)

494

for resp in responses['data']:

495

detail = await portkey.responses.retrieve(resp['id'])

496

print(f"Response {resp['id']}: {detail['input_tokens']} → {detail['output_tokens']} tokens")

497

498

asyncio.run(async_observability_example())

499

```

500

501

## Analytics Metrics

502

503

Portkey automatically tracks 40+ production-critical metrics including:

504

505

### Performance Metrics

506

- Request latency (p50, p95, p99)

507

- Throughput (requests per minute/hour)

508

- Error rates by provider/model

509

- Token usage and costs

510

511

### Usage Metrics

512

- Requests by model, provider, user

513

- Token consumption patterns

514

- Cost analysis and optimization

515

- Geographic distribution

516

517

### Quality Metrics

518

- Response quality scores

519

- User feedback integration

520

- A/B test results

521

- Conversion tracking

522

523

### Infrastructure Metrics

524

- Cache hit rates

525

- Fallback trigger frequency

526

- Load balancing distribution

527

- Provider availability