or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context.mdindex.mdplatform.mdpropagation.mdtiming.mdtrace-state.mdutilities.mdvalidation.md

validation.mddocs/

0

# Validation & Error Handling

1

2

Attribute validation, sanitization, and comprehensive error handling infrastructure with global error handler support and logging integration.

3

4

## Capabilities

5

6

### Attribute Validation & Sanitization

7

8

Functions for validating and cleaning OpenTelemetry attributes according to specification requirements.

9

10

```typescript { .api }

11

/**

12

* Sanitize attributes object, removing invalid keys and values

13

* @param attributes - Raw attributes object to sanitize

14

* @returns Clean Attributes object with valid key-value pairs

15

*/

16

function sanitizeAttributes(attributes: unknown): Attributes;

17

18

/**

19

* Check if a value is a valid OpenTelemetry attribute value

20

* @param val - Value to validate

21

* @returns True if value is valid AttributeValue (string, number, boolean, or homogeneous array)

22

*/

23

function isAttributeValue(val: unknown): val is AttributeValue;

24

```

25

26

**Usage Examples:**

27

28

```typescript

29

import { sanitizeAttributes, isAttributeValue } from "@opentelemetry/core";

30

31

// Sanitize mixed attributes object

32

const rawAttributes = {

33

"user.id": "12345", // Valid string

34

"request.size": 1024, // Valid number

35

"cache.enabled": true, // Valid boolean

36

"tags": ["web", "api"], // Valid string array

37

"": "invalid-empty-key", // Invalid: empty key

38

"valid.key": undefined, // Invalid: undefined value

39

"another.key": { nested: "object" }, // Invalid: object value

40

"mixed.array": ["string", 123], // Invalid: mixed array types

41

"valid.null": null // Valid: null is allowed

42

};

43

44

const cleanAttributes = sanitizeAttributes(rawAttributes);

45

console.log(cleanAttributes);

46

// Result: {

47

// "user.id": "12345",

48

// "request.size": 1024,

49

// "cache.enabled": true,

50

// "tags": ["web", "api"],

51

// "valid.null": null

52

// }

53

54

// Validate individual values

55

console.log(isAttributeValue("string")); // true

56

console.log(isAttributeValue(42)); // true

57

console.log(isAttributeValue(true)); // true

58

console.log(isAttributeValue(null)); // true

59

console.log(isAttributeValue([1, 2, 3])); // true (homogeneous array)

60

console.log(isAttributeValue(["a", "b"])); // true (homogeneous array)

61

console.log(isAttributeValue([1, "mixed"])); // false (mixed array)

62

console.log(isAttributeValue({})); // false (object)

63

console.log(isAttributeValue(undefined)); // false (undefined)

64

65

// Use in span creation

66

function createSpanWithAttributes(name: string, rawAttrs: unknown) {

67

const cleanAttrs = sanitizeAttributes(rawAttrs);

68

const span = trace.getTracer("my-service").startSpan(name, {

69

attributes: cleanAttrs

70

});

71

return span;

72

}

73

74

// Safe attribute setting

75

function setSpanAttribute(span: Span, key: string, value: unknown) {

76

if (key && key.length > 0 && isAttributeValue(value)) {

77

span.setAttribute(key, value);

78

} else {

79

console.warn(`Invalid attribute: ${key}=${value}`);

80

}

81

}

82

```

83

84

### Error Handling Infrastructure

85

86

Global error handling system with pluggable error handlers and default logging implementation.

87

88

```typescript { .api }

89

/**

90

* Error handler function type

91

*/

92

type ErrorHandler = (ex: Exception) => void;

93

94

/**

95

* Set the global error handler for OpenTelemetry operations

96

* @param handler - Error handler function to use globally

97

*/

98

function setGlobalErrorHandler(handler: ErrorHandler): void;

99

100

/**

101

* Invoke the global error handler with an exception

102

* @param ex - Exception to handle

103

*/

104

function globalErrorHandler(ex: Exception): void;

105

106

/**

107

* Get a logging error handler that outputs errors using diag logger

108

* @returns ErrorHandler that logs errors with JSON serialization

109

*/

110

function loggingErrorHandler(): ErrorHandler;

111

```

112

113

**Usage Examples:**

114

115

```typescript

116

import {

117

setGlobalErrorHandler,

118

globalErrorHandler,

119

loggingErrorHandler

120

} from "@opentelemetry/core";

121

import { diag } from "@opentelemetry/api";

122

123

// Set up custom error handler

124

const customErrorHandler = (error: Exception) => {

125

console.error("OpenTelemetry Error:", error);

126

127

// Send to external error tracking service

128

if (typeof window !== 'undefined' && window.errorTracker) {

129

window.errorTracker.captureException(error);

130

}

131

132

// Log structured error information

133

const errorInfo = {

134

message: error.message || "Unknown error",

135

stack: error.stack,

136

timestamp: new Date().toISOString(),

137

source: "opentelemetry-core"

138

};

139

140

console.error("Error details:", JSON.stringify(errorInfo, null, 2));

141

};

142

143

// Set the global error handler

144

setGlobalErrorHandler(customErrorHandler);

145

146

// Use default logging error handler

147

const loggingHandler = loggingErrorHandler();

148

setGlobalErrorHandler(loggingHandler);

149

150

// Trigger error handling

151

try {

152

throw new Error("Something went wrong in telemetry");

153

} catch (error) {

154

globalErrorHandler(error); // Will use the configured handler

155

}

156

157

// Error handling in async operations

158

async function riskyTelemetryOperation() {

159

try {

160

// Some telemetry operation that might fail

161

await exportData();

162

} catch (error) {

163

// Use global error handler

164

globalErrorHandler(error);

165

166

// Still throw for caller to handle business logic

167

throw error;

168

}

169

}

170

171

// Safe error handler wrapper

172

function safeErrorHandler(handler: ErrorHandler): ErrorHandler {

173

return (error: Exception) => {

174

try {

175

handler(error);

176

} catch (handlerError) {

177

// Fallback to console if handler itself fails

178

console.error("Error handler failed:", handlerError);

179

console.error("Original error:", error);

180

}

181

};

182

}

183

184

setGlobalErrorHandler(safeErrorHandler(customErrorHandler));

185

```

186

187

### Export Result Types

188

189

Types and enums for representing the results of export operations.

190

191

```typescript { .api }

192

/**

193

* Result codes for export operations

194

*/

195

enum ExportResultCode {

196

/** Export operation succeeded */

197

SUCCESS,

198

/** Export operation failed */

199

FAILED

200

}

201

202

/**

203

* Result of an export operation

204

*/

205

interface ExportResult {

206

/** Result status code */

207

code: ExportResultCode;

208

/** Optional error information if export failed */

209

error?: Error;

210

}

211

```

212

213

**Usage Examples:**

214

215

```typescript

216

import { ExportResult, ExportResultCode } from "@opentelemetry/core";

217

218

// Create export results

219

const successResult: ExportResult = {

220

code: ExportResultCode.SUCCESS

221

};

222

223

const failureResult: ExportResult = {

224

code: ExportResultCode.FAILED,

225

error: new Error("Network timeout")

226

};

227

228

// Use in exporter implementations

229

class CustomExporter {

230

async export(data: any[]): Promise<ExportResult> {

231

try {

232

await this.sendData(data);

233

return { code: ExportResultCode.SUCCESS };

234

} catch (error) {

235

return {

236

code: ExportResultCode.FAILED,

237

error: error instanceof Error ? error : new Error(String(error))

238

};

239

}

240

}

241

242

private async sendData(data: any[]): Promise<void> {

243

// Implementation

244

}

245

}

246

247

// Handle export results

248

async function performExport(exporter: CustomExporter, data: any[]) {

249

const result = await exporter.export(data);

250

251

switch (result.code) {

252

case ExportResultCode.SUCCESS:

253

console.log("Export successful");

254

break;

255

256

case ExportResultCode.FAILED:

257

console.error("Export failed:", result.error?.message);

258

259

// Use global error handler for failed exports

260

if (result.error) {

261

globalErrorHandler(result.error);

262

}

263

264

// Implement retry logic

265

await scheduleRetry(data);

266

break;

267

}

268

}

269

270

// Batch export with error handling

271

async function batchExport(items: any[], batchSize: number = 100): Promise<ExportResult[]> {

272

const results: ExportResult[] = [];

273

274

for (let i = 0; i < items.length; i += batchSize) {

275

const batch = items.slice(i, i + batchSize);

276

277

try {

278

const result = await exportBatch(batch);

279

results.push(result);

280

281

if (result.code === ExportResultCode.FAILED) {

282

console.warn(`Batch ${i / batchSize + 1} failed:`, result.error?.message);

283

}

284

} catch (error) {

285

const failureResult: ExportResult = {

286

code: ExportResultCode.FAILED,

287

error: error instanceof Error ? error : new Error(String(error))

288

};

289

290

results.push(failureResult);

291

globalErrorHandler(failureResult.error!);

292

}

293

}

294

295

return results;

296

}

297

298

// Result aggregation

299

function aggregateResults(results: ExportResult[]): {

300

successCount: number;

301

failureCount: number;

302

errors: Error[];

303

} {

304

return results.reduce((acc, result) => {

305

if (result.code === ExportResultCode.SUCCESS) {

306

acc.successCount++;

307

} else {

308

acc.failureCount++;

309

if (result.error) {

310

acc.errors.push(result.error);

311

}

312

}

313

return acc;

314

}, { successCount: 0, failureCount: 0, errors: [] as Error[] });

315

}

316

```

317

318

### Instrumentation Scope Types

319

320

Types for defining instrumentation library metadata.

321

322

```typescript { .api }

323

/**

324

* An instrumentation scope consists of the name and optional version

325

* used to obtain a tracer or meter from a provider

326

*/

327

interface InstrumentationScope {

328

/** Instrumentation library name */

329

readonly name: string;

330

/** Optional instrumentation library version */

331

readonly version?: string;

332

/** Optional schema URL */

333

readonly schemaUrl?: string;

334

}

335

```

336

337

**Usage Examples:**

338

339

```typescript

340

import { InstrumentationScope } from "@opentelemetry/core";

341

342

// Define instrumentation scopes

343

const webServerScope: InstrumentationScope = {

344

name: "my-web-server",

345

version: "1.2.0",

346

schemaUrl: "https://opentelemetry.io/schemas/1.21.0"

347

};

348

349

const databaseScope: InstrumentationScope = {

350

name: "database-client",

351

version: "2.5.1"

352

};

353

354

// Use with tracer provider

355

const tracer = trace.getTracer(

356

webServerScope.name,

357

webServerScope.version,

358

{ schemaUrl: webServerScope.schemaUrl }

359

);

360

361

// Create spans with scope information

362

const span = tracer.startSpan("handle-request");

363

span.setAttribute("instrumentation.name", webServerScope.name);

364

span.setAttribute("instrumentation.version", webServerScope.version || "unknown");

365

366

// Validate scope information

367

function validateScope(scope: InstrumentationScope): boolean {

368

if (!scope.name || scope.name.trim().length === 0) {

369

console.error("Instrumentation scope must have a non-empty name");

370

return false;

371

}

372

373

if (scope.version && scope.version.trim().length === 0) {

374

console.warn("Empty version string provided for scope:", scope.name);

375

}

376

377

if (scope.schemaUrl && !isValidUrl(scope.schemaUrl)) {

378

console.warn("Invalid schema URL provided:", scope.schemaUrl);

379

}

380

381

return true;

382

}

383

384

// Helper function for URL validation

385

function isValidUrl(url: string): boolean {

386

try {

387

new URL(url);

388

return true;

389

} catch {

390

return false;

391

}

392

}

393

394

// Use scopes in instrumentation libraries

395

class MyInstrumentation {

396

private scope: InstrumentationScope;

397

398

constructor(scope: InstrumentationScope) {

399

if (!validateScope(scope)) {

400

throw new Error("Invalid instrumentation scope");

401

}

402

this.scope = scope;

403

}

404

405

createTracer() {

406

return trace.getTracer(

407

this.scope.name,

408

this.scope.version,

409

{ schemaUrl: this.scope.schemaUrl }

410

);

411

}

412

413

createMeter() {

414

return metrics.getMeter(

415

this.scope.name,

416

this.scope.version,

417

{ schemaUrl: this.scope.schemaUrl }

418

);

419

}

420

}

421

```