OpenTelemetry Core provides constants and utilities shared by all OpenTelemetry SDK packages.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Attribute validation, sanitization, and comprehensive error handling infrastructure with global error handler support and logging integration.
Functions for validating and cleaning OpenTelemetry attributes according to specification requirements.
/**
* Sanitize attributes object, removing invalid keys and values
* @param attributes - Raw attributes object to sanitize
* @returns Clean Attributes object with valid key-value pairs
*/
function sanitizeAttributes(attributes: unknown): Attributes;
/**
* Check if a value is a valid OpenTelemetry attribute value
* @param val - Value to validate
* @returns True if value is valid AttributeValue (string, number, boolean, or homogeneous array)
*/
function isAttributeValue(val: unknown): val is AttributeValue;Usage Examples:
import { sanitizeAttributes, isAttributeValue } from "@opentelemetry/core";
// Sanitize mixed attributes object
const rawAttributes = {
"user.id": "12345", // Valid string
"request.size": 1024, // Valid number
"cache.enabled": true, // Valid boolean
"tags": ["web", "api"], // Valid string array
"": "invalid-empty-key", // Invalid: empty key
"valid.key": undefined, // Invalid: undefined value
"another.key": { nested: "object" }, // Invalid: object value
"mixed.array": ["string", 123], // Invalid: mixed array types
"valid.null": null // Valid: null is allowed
};
const cleanAttributes = sanitizeAttributes(rawAttributes);
console.log(cleanAttributes);
// Result: {
// "user.id": "12345",
// "request.size": 1024,
// "cache.enabled": true,
// "tags": ["web", "api"],
// "valid.null": null
// }
// Validate individual values
console.log(isAttributeValue("string")); // true
console.log(isAttributeValue(42)); // true
console.log(isAttributeValue(true)); // true
console.log(isAttributeValue(null)); // true
console.log(isAttributeValue([1, 2, 3])); // true (homogeneous array)
console.log(isAttributeValue(["a", "b"])); // true (homogeneous array)
console.log(isAttributeValue([1, "mixed"])); // false (mixed array)
console.log(isAttributeValue({})); // false (object)
console.log(isAttributeValue(undefined)); // false (undefined)
// Use in span creation
function createSpanWithAttributes(name: string, rawAttrs: unknown) {
const cleanAttrs = sanitizeAttributes(rawAttrs);
const span = trace.getTracer("my-service").startSpan(name, {
attributes: cleanAttrs
});
return span;
}
// Safe attribute setting
function setSpanAttribute(span: Span, key: string, value: unknown) {
if (key && key.length > 0 && isAttributeValue(value)) {
span.setAttribute(key, value);
} else {
console.warn(`Invalid attribute: ${key}=${value}`);
}
}Global error handling system with pluggable error handlers and default logging implementation.
/**
* Error handler function type
*/
type ErrorHandler = (ex: Exception) => void;
/**
* Set the global error handler for OpenTelemetry operations
* @param handler - Error handler function to use globally
*/
function setGlobalErrorHandler(handler: ErrorHandler): void;
/**
* Invoke the global error handler with an exception
* @param ex - Exception to handle
*/
function globalErrorHandler(ex: Exception): void;
/**
* Get a logging error handler that outputs errors using diag logger
* @returns ErrorHandler that logs errors with JSON serialization
*/
function loggingErrorHandler(): ErrorHandler;Usage Examples:
import {
setGlobalErrorHandler,
globalErrorHandler,
loggingErrorHandler
} from "@opentelemetry/core";
import { diag } from "@opentelemetry/api";
// Set up custom error handler
const customErrorHandler = (error: Exception) => {
console.error("OpenTelemetry Error:", error);
// Send to external error tracking service
if (typeof window !== 'undefined' && window.errorTracker) {
window.errorTracker.captureException(error);
}
// Log structured error information
const errorInfo = {
message: error.message || "Unknown error",
stack: error.stack,
timestamp: new Date().toISOString(),
source: "opentelemetry-core"
};
console.error("Error details:", JSON.stringify(errorInfo, null, 2));
};
// Set the global error handler
setGlobalErrorHandler(customErrorHandler);
// Use default logging error handler
const loggingHandler = loggingErrorHandler();
setGlobalErrorHandler(loggingHandler);
// Trigger error handling
try {
throw new Error("Something went wrong in telemetry");
} catch (error) {
globalErrorHandler(error); // Will use the configured handler
}
// Error handling in async operations
async function riskyTelemetryOperation() {
try {
// Some telemetry operation that might fail
await exportData();
} catch (error) {
// Use global error handler
globalErrorHandler(error);
// Still throw for caller to handle business logic
throw error;
}
}
// Safe error handler wrapper
function safeErrorHandler(handler: ErrorHandler): ErrorHandler {
return (error: Exception) => {
try {
handler(error);
} catch (handlerError) {
// Fallback to console if handler itself fails
console.error("Error handler failed:", handlerError);
console.error("Original error:", error);
}
};
}
setGlobalErrorHandler(safeErrorHandler(customErrorHandler));Types and enums for representing the results of export operations.
/**
* Result codes for export operations
*/
enum ExportResultCode {
/** Export operation succeeded */
SUCCESS,
/** Export operation failed */
FAILED
}
/**
* Result of an export operation
*/
interface ExportResult {
/** Result status code */
code: ExportResultCode;
/** Optional error information if export failed */
error?: Error;
}Usage Examples:
import { ExportResult, ExportResultCode } from "@opentelemetry/core";
// Create export results
const successResult: ExportResult = {
code: ExportResultCode.SUCCESS
};
const failureResult: ExportResult = {
code: ExportResultCode.FAILED,
error: new Error("Network timeout")
};
// Use in exporter implementations
class CustomExporter {
async export(data: any[]): Promise<ExportResult> {
try {
await this.sendData(data);
return { code: ExportResultCode.SUCCESS };
} catch (error) {
return {
code: ExportResultCode.FAILED,
error: error instanceof Error ? error : new Error(String(error))
};
}
}
private async sendData(data: any[]): Promise<void> {
// Implementation
}
}
// Handle export results
async function performExport(exporter: CustomExporter, data: any[]) {
const result = await exporter.export(data);
switch (result.code) {
case ExportResultCode.SUCCESS:
console.log("Export successful");
break;
case ExportResultCode.FAILED:
console.error("Export failed:", result.error?.message);
// Use global error handler for failed exports
if (result.error) {
globalErrorHandler(result.error);
}
// Implement retry logic
await scheduleRetry(data);
break;
}
}
// Batch export with error handling
async function batchExport(items: any[], batchSize: number = 100): Promise<ExportResult[]> {
const results: ExportResult[] = [];
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
try {
const result = await exportBatch(batch);
results.push(result);
if (result.code === ExportResultCode.FAILED) {
console.warn(`Batch ${i / batchSize + 1} failed:`, result.error?.message);
}
} catch (error) {
const failureResult: ExportResult = {
code: ExportResultCode.FAILED,
error: error instanceof Error ? error : new Error(String(error))
};
results.push(failureResult);
globalErrorHandler(failureResult.error!);
}
}
return results;
}
// Result aggregation
function aggregateResults(results: ExportResult[]): {
successCount: number;
failureCount: number;
errors: Error[];
} {
return results.reduce((acc, result) => {
if (result.code === ExportResultCode.SUCCESS) {
acc.successCount++;
} else {
acc.failureCount++;
if (result.error) {
acc.errors.push(result.error);
}
}
return acc;
}, { successCount: 0, failureCount: 0, errors: [] as Error[] });
}Types for defining instrumentation library metadata.
/**
* An instrumentation scope consists of the name and optional version
* used to obtain a tracer or meter from a provider
*/
interface InstrumentationScope {
/** Instrumentation library name */
readonly name: string;
/** Optional instrumentation library version */
readonly version?: string;
/** Optional schema URL */
readonly schemaUrl?: string;
}Usage Examples:
import { InstrumentationScope } from "@opentelemetry/core";
// Define instrumentation scopes
const webServerScope: InstrumentationScope = {
name: "my-web-server",
version: "1.2.0",
schemaUrl: "https://opentelemetry.io/schemas/1.21.0"
};
const databaseScope: InstrumentationScope = {
name: "database-client",
version: "2.5.1"
};
// Use with tracer provider
const tracer = trace.getTracer(
webServerScope.name,
webServerScope.version,
{ schemaUrl: webServerScope.schemaUrl }
);
// Create spans with scope information
const span = tracer.startSpan("handle-request");
span.setAttribute("instrumentation.name", webServerScope.name);
span.setAttribute("instrumentation.version", webServerScope.version || "unknown");
// Validate scope information
function validateScope(scope: InstrumentationScope): boolean {
if (!scope.name || scope.name.trim().length === 0) {
console.error("Instrumentation scope must have a non-empty name");
return false;
}
if (scope.version && scope.version.trim().length === 0) {
console.warn("Empty version string provided for scope:", scope.name);
}
if (scope.schemaUrl && !isValidUrl(scope.schemaUrl)) {
console.warn("Invalid schema URL provided:", scope.schemaUrl);
}
return true;
}
// Helper function for URL validation
function isValidUrl(url: string): boolean {
try {
new URL(url);
return true;
} catch {
return false;
}
}
// Use scopes in instrumentation libraries
class MyInstrumentation {
private scope: InstrumentationScope;
constructor(scope: InstrumentationScope) {
if (!validateScope(scope)) {
throw new Error("Invalid instrumentation scope");
}
this.scope = scope;
}
createTracer() {
return trace.getTracer(
this.scope.name,
this.scope.version,
{ schemaUrl: this.scope.schemaUrl }
);
}
createMeter() {
return metrics.getMeter(
this.scope.name,
this.scope.version,
{ schemaUrl: this.scope.schemaUrl }
);
}
}Install with Tessl CLI
npx tessl i tessl/npm-opentelemetry--core