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
Common utility functions including deep object merging, timeout handling, URL pattern matching, and configuration parsing that support various SDK operations.
Deep object merging with circular reference protection and array handling.
/**
* Deep merge multiple objects with circular reference protection
* @param args - Objects to merge (later objects override earlier ones)
* @returns Merged object with all properties combined
*/
function merge(...args: any[]): any;Usage Examples:
import { merge } from "@opentelemetry/core";
// Basic object merging
const config1 = {
server: {
port: 3000,
host: "localhost"
},
features: ["logging", "metrics"]
};
const config2 = {
server: {
port: 8080,
ssl: true
},
features: ["tracing"],
database: {
url: "postgresql://localhost:5432/app"
}
};
const mergedConfig = merge(config1, config2);
console.log(mergedConfig);
// Result: {
// server: {
// port: 8080, // Overridden
// host: "localhost", // Preserved
// ssl: true // Added
// },
// features: ["tracing"], // Arrays are replaced, not merged
// database: {
// url: "postgresql://localhost:5432/app"
// }
// }
// Merge with multiple sources
const defaults = {
timeout: 5000,
retries: 3,
headers: {
"User-Agent": "OpenTelemetry/1.0"
}
};
const userConfig = {
timeout: 10000,
headers: {
"Authorization": "Bearer token123"
}
};
const envConfig = {
retries: 5,
headers: {
"X-Environment": "production"
}
};
const finalConfig = merge(defaults, userConfig, envConfig);
console.log(finalConfig);
// Result: {
// timeout: 10000,
// retries: 5,
// headers: {
// "User-Agent": "OpenTelemetry/1.0",
// "Authorization": "Bearer token123",
// "X-Environment": "production"
// }
// }
// Handle circular references safely
const obj1 = { name: "parent" };
const obj2 = { child: obj1 };
obj1.parent = obj2; // Creates circular reference
const obj3 = { version: "1.0" };
const merged = merge(obj1, obj3); // Won't cause infinite recursion
// Use in configuration management
class ConfigManager {
private defaultConfig = {
tracing: {
enabled: true,
samplingRate: 1.0,
exporters: ["console"]
},
metrics: {
enabled: false,
interval: 30000
}
};
loadConfig(userConfig: any, envConfig: any = {}) {
return merge(this.defaultConfig, userConfig, envConfig);
}
}Promise timeout handling with custom error types.
/**
* Error thrown when operations exceed their timeout
*/
class TimeoutError extends Error {
constructor(message?: string);
}
/**
* Add timeout to a promise, rejecting with TimeoutError if exceeded
* @param promise - Promise to add timeout to
* @param timeout - Timeout in milliseconds
* @returns Promise that resolves with original result or rejects with TimeoutError
*/
function callWithTimeout<T>(promise: Promise<T>, timeout: number): Promise<T>;Usage Examples:
import { callWithTimeout, TimeoutError } from "@opentelemetry/core";
// Add timeout to network requests
async function fetchWithTimeout(url: string, timeoutMs: number = 5000) {
const fetchPromise = fetch(url);
try {
const response = await callWithTimeout(fetchPromise, timeoutMs);
return response;
} catch (error) {
if (error instanceof TimeoutError) {
console.error(`Request to ${url} timed out after ${timeoutMs}ms`);
throw new Error(`Network timeout: ${url}`);
}
throw error; // Re-throw other errors
}
}
// Use with export operations
async function exportWithTimeout<T>(exportFn: () => Promise<T>, timeout: number = 10000): Promise<T> {
try {
return await callWithTimeout(exportFn(), timeout);
} catch (error) {
if (error instanceof TimeoutError) {
console.error("Export operation timed out");
return Promise.reject(new Error("Export timeout"));
}
throw error;
}
}
// Database operations with timeout
class DatabaseClient {
async query(sql: string, timeout: number = 30000) {
const queryPromise = this.executeQuery(sql);
try {
return await callWithTimeout(queryPromise, timeout);
} catch (error) {
if (error instanceof TimeoutError) {
console.error(`Database query timed out: ${sql}`);
// Cancel the query if possible
this.cancelQuery();
throw new Error("Database query timeout");
}
throw error;
}
}
private async executeQuery(sql: string): Promise<any[]> {
// Database query implementation
return [];
}
private cancelQuery(): void {
// Query cancellation implementation
}
}
// Batch operations with individual timeouts
async function processBatchWithTimeout<T, R>(
items: T[],
processor: (item: T) => Promise<R>,
itemTimeout: number = 5000
): Promise<Array<R | Error>> {
const results = await Promise.allSettled(
items.map(item => callWithTimeout(processor(item), itemTimeout))
);
return results.map((result, index) => {
if (result.status === 'fulfilled') {
return result.value;
} else {
const error = result.reason;
if (error instanceof TimeoutError) {
console.warn(`Item ${index} timed out`);
return new Error(`Item ${index} timeout`);
}
return error;
}
});
}
// Retry with timeout
async function retryWithTimeout<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
timeout: number = 5000,
backoff: number = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await callWithTimeout(operation(), timeout);
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
if (error instanceof TimeoutError) {
console.warn(`Attempt ${attempt} timed out`);
} else {
console.warn(`Attempt ${attempt} failed:`, error.message);
}
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, backoff * attempt));
}
}
}
throw lastError!;
}URL pattern matching and filtering for instrumentation configuration.
/**
* Check if URL matches a string or regex pattern
* @param url - URL to test
* @param urlToMatch - String or RegExp pattern to match against
* @returns True if URL matches the pattern
*/
function urlMatches(url: string, urlToMatch: string | RegExp): boolean;
/**
* Check if URL should be ignored based on ignore patterns
* @param url - URL to test
* @param ignoredUrls - Array of string or RegExp patterns to ignore
* @returns True if URL should be ignored
*/
function isUrlIgnored(url: string, ignoredUrls?: Array<string | RegExp>): boolean;Usage Examples:
import { urlMatches, isUrlIgnored } from "@opentelemetry/core";
// Basic URL matching
console.log(urlMatches("https://api.example.com/users", "https://api.example.com")); // true
console.log(urlMatches("https://api.example.com/users", /\/users$/)); // true
console.log(urlMatches("https://other.com/users", "https://api.example.com")); // false
// Configure ignored URLs for instrumentation
const ignoredUrls = [
"https://internal.monitoring.com",
/\/health$/,
/\/metrics$/,
"http://localhost:3000/debug"
];
// Check if URLs should be ignored
console.log(isUrlIgnored("https://api.example.com/users", ignoredUrls)); // false
console.log(isUrlIgnored("https://api.example.com/health", ignoredUrls)); // true
console.log(isUrlIgnored("https://internal.monitoring.com/status", ignoredUrls)); // true
// Use in HTTP instrumentation
class HttpInstrumentation {
private ignoredUrls: Array<string | RegExp>;
constructor(config: { ignoredUrls?: Array<string | RegExp> } = {}) {
this.ignoredUrls = config.ignoredUrls || [];
}
shouldInstrument(url: string): boolean {
return !isUrlIgnored(url, this.ignoredUrls);
}
instrumentRequest(url: string, options: any) {
if (!this.shouldInstrument(url)) {
console.log(`Skipping instrumentation for ignored URL: ${url}`);
return this.makeUninstrumentedRequest(url, options);
}
console.log(`Instrumenting request to: ${url}`);
return this.makeInstrumentedRequest(url, options);
}
private makeInstrumentedRequest(url: string, options: any) {
// Create span and instrument the request
}
private makeUninstrumentedRequest(url: string, options: any) {
// Make request without instrumentation
}
}
// Advanced pattern matching
const complexIgnorePatterns = [
// Ignore all internal services
/^https?:\/\/.*\.internal\./,
// Ignore health and monitoring endpoints
/\/(health|ping|status|metrics|ready|live)$/,
// Ignore static assets
/\.(css|js|png|jpg|gif|ico|svg|woff|woff2)$/,
// Ignore specific domains
"https://analytics.google.com",
"https://www.googletagmanager.com",
// Ignore development servers
/^https?:\/\/localhost/,
/^https?:\/\/127\.0\.0\.1/
];
function shouldTraceUrl(url: string): boolean {
return !isUrlIgnored(url, complexIgnorePatterns);
}
// URL categorization
function categorizeUrl(url: string): string {
const categories = [
{ pattern: /\/api\//, category: "api" },
{ pattern: /\/(health|ping|status)$/, category: "health" },
{ pattern: /\/(metrics|telemetry)$/, category: "monitoring" },
{ pattern: /\/static\//, category: "static" },
{ pattern: /\/admin\//, category: "admin" }
];
for (const { pattern, category } of categories) {
if (urlMatches(url, pattern)) {
return category;
}
}
return "unknown";
}
// Use in middleware
function createTracingMiddleware(ignoredUrls: Array<string | RegExp> = []) {
return (req: any, res: any, next: any) => {
const url = req.url;
if (isUrlIgnored(url, ignoredUrls)) {
// Skip tracing for ignored URLs
req.skipTracing = true;
} else {
// Enable tracing
req.urlCategory = categorizeUrl(url);
req.shouldTrace = true;
}
next();
};
}One-time callback execution with promise-based result handling.
/**
* Ensures a callback is only invoked once, with promise-based result handling
*/
class BindOnceFuture<
R,
This = unknown,
T extends (this: This, ...args: unknown[]) => R = () => R
> {
/**
* Create a new BindOnceFuture
* @param callback - Function to bind and call once
* @param that - Context ('this' value) for the callback
*/
constructor(callback: T, that: This);
/** Whether the callback has been called */
readonly isCalled: boolean;
/** Promise that resolves with the callback result */
readonly promise: Promise<R>;
/**
* Call the callback (only the first call will execute)
* @param args - Arguments to pass to the callback
* @returns Promise resolving to callback result
*/
call(...args: Parameters<T>): Promise<R>;
}Usage Examples:
import { BindOnceFuture } from "@opentelemetry/core";
// Create one-time initialization function
class ServiceManager {
private initFuture: BindOnceFuture<void, this, () => void>;
constructor() {
this.initFuture = new BindOnceFuture(this.doInitialization, this);
}
async initialize(): Promise<void> {
// This will only run once, regardless of how many times initialize() is called
return this.initFuture.call();
}
private doInitialization(): void {
console.log("Initializing service...");
// Expensive initialization logic here
}
async getService(): Promise<any> {
await this.initialize(); // Safe to call multiple times
return this.service;
}
}
// One-time resource cleanup
class ResourceManager {
private cleanupFuture: BindOnceFuture<Promise<void>, this, () => Promise<void>>;
constructor() {
this.cleanupFuture = new BindOnceFuture(this.doCleanup, this);
}
async cleanup(): Promise<void> {
return this.cleanupFuture.call();
}
private async doCleanup(): Promise<void> {
console.log("Cleaning up resources...");
// Cleanup logic that should only run once
await this.closeConnections();
await this.releaseResources();
}
private async closeConnections(): Promise<void> {
// Implementation
}
private async releaseResources(): Promise<void> {
// Implementation
}
}
// One-time configuration loading
class ConfigLoader {
private loadConfigFuture: BindOnceFuture<any, this, () => any>;
constructor() {
this.loadConfigFuture = new BindOnceFuture(this.loadConfiguration, this);
}
async getConfig(): Promise<any> {
return this.loadConfigFuture.call();
}
private loadConfiguration(): any {
console.log("Loading configuration...");
// Expensive config loading that should only happen once
return {
database: { url: "postgresql://localhost:5432/app" },
redis: { url: "redis://localhost:6379" },
features: ["tracing", "metrics"]
};
}
}
// Multiple callers, single execution
async function demonstrateUsage() {
const configLoader = new ConfigLoader();
// Multiple concurrent calls - only loads once
const [config1, config2, config3] = await Promise.all([
configLoader.getConfig(),
configLoader.getConfig(),
configLoader.getConfig()
]);
console.log("All configs are identical:",
config1 === config2 && config2 === config3); // true
// Check if already called
console.log("Config was loaded:", configLoader.loadConfigFuture?.isCalled); // true
}
// Error handling with BindOnceFuture
class ErrorProneInitializer {
private initFuture: BindOnceFuture<string, this, () => string>;
constructor() {
this.initFuture = new BindOnceFuture(this.riskyInitialization, this);
}
async initialize(): Promise<string> {
try {
return await this.initFuture.call();
} catch (error) {
console.error("Initialization failed:", error);
throw error;
}
}
private riskyInitialization(): string {
if (Math.random() < 0.5) {
throw new Error("Random initialization failure");
}
return "Successfully initialized";
}
}
// Use with different callback signatures
function createCounter(): BindOnceFuture<number, object, (start: number) => number> {
const context = {};
return new BindOnceFuture((start: number) => {
console.log(`Counter starting at ${start}`);
return start;
}, context);
}
const counter = createCounter();
counter.call(10).then(result => console.log("Counter result:", result)); // 10
counter.call(20).then(result => console.log("Counter result:", result)); // Still 10Configuration parsing and type conversion utilities.
/**
* Convert string value to DiagLogLevel enum value
* Returns undefined only for null/undefined input.
* For invalid string values, logs a warning and returns DiagLogLevel.INFO as fallback.
* @param value - String representation of log level
* @returns DiagLogLevel enum value or undefined if input is null/undefined
*/
function diagLogLevelFromString(value: string | undefined): DiagLogLevel | undefined;Usage Examples:
import { diagLogLevelFromString } from "@opentelemetry/core";
import { DiagLogLevel, diag } from "@opentelemetry/api";
// Parse log level from environment variable
const logLevelStr = process.env.OTEL_LOG_LEVEL || "info";
const logLevel = diagLogLevelFromString(logLevelStr);
if (logLevel !== undefined) {
diag.setLogger(console, logLevel);
console.log(`Log level set to: ${DiagLogLevel[logLevel]}`);
} else {
console.warn(`Invalid log level: ${logLevelStr}, using default`);
diag.setLogger(console, DiagLogLevel.INFO);
}
// Configuration parser with validation
class TelemetryConfig {
static parseConfig(env: Record<string, string | undefined>) {
return {
logLevel: diagLogLevelFromString(env.OTEL_LOG_LEVEL) ?? DiagLogLevel.INFO,
serviceName: env.OTEL_SERVICE_NAME ?? "unknown-service",
serviceVersion: env.OTEL_SERVICE_VERSION ?? "1.0.0",
environment: env.OTEL_ENVIRONMENT ?? "development"
};
}
static setDiagnostics(config: ReturnType<typeof TelemetryConfig.parseConfig>) {
diag.setLogger(console, config.logLevel);
// Log configuration at startup
diag.info("OpenTelemetry configuration:", {
serviceName: config.serviceName,
serviceVersion: config.serviceVersion,
environment: config.environment,
logLevel: DiagLogLevel[config.logLevel]
});
}
}
// Usage in application startup
const config = TelemetryConfig.parseConfig(process.env);
TelemetryConfig.setDiagnostics(config);
// Test different log level formats
const testLogLevels = [
"debug", "DEBUG", "Debug",
"info", "INFO", "Info",
"warn", "WARN", "Warn",
"error", "ERROR", "Error",
"none", "NONE", "None",
"all", "ALL", "All",
"invalid", "", undefined
];
testLogLevels.forEach(level => {
const parsed = diagLogLevelFromString(level);
console.log(`"${level}" -> ${parsed !== undefined ? DiagLogLevel[parsed] : 'undefined'}`);
});
// Dynamic log level adjustment
function setLogLevel(levelStr: string): boolean {
const level = diagLogLevelFromString(levelStr);
if (level !== undefined) {
diag.setLogger(console, level);
diag.info(`Log level changed to: ${DiagLogLevel[level]}`);
return true;
} else {
diag.warn(`Invalid log level: ${levelStr}`);
return false;
}
}
// Runtime configuration updates
function updateTelemetryConfig(updates: Record<string, string>) {
if (updates.OTEL_LOG_LEVEL) {
const success = setLogLevel(updates.OTEL_LOG_LEVEL);
if (!success) {
delete updates.OTEL_LOG_LEVEL; // Remove invalid value
}
}
// Apply other configuration updates
return updates;
}Internal utilities namespace for advanced SDK operations.
/**
* Internal utilities namespace (use with caution)
*/
const internal: {
/** Internal export utilities */
_export: any;
};Usage Examples:
import { internal } from "@opentelemetry/core";
// Access internal export utilities (advanced usage)
// Note: Internal APIs are subject to change without notice
const exportUtils = internal._export;
// These are internal utilities used by other OpenTelemetry packages
// Use with caution as they may change without notice
console.log("Internal export utilities available:", !!exportUtils);Install with Tessl CLI
npx tessl i tessl/npm-opentelemetry--core