@vtex/diagnostics-web
v5.1.1
Published
Diagnostics library for Web applications
Maintainers
Readme
OpenTelemetry Diagnostics Library for Web
A JavaScript library for browsers that simplifies telemetry collection using OpenTelemetry, providing unified interfaces for metrics, logs, events and traces in web applications.
Installation
npm install @vtex/diagnostics-webQuick Start
Here's how to set up basic telemetry for your web application:
import { NewTelemetryClient, Exporters, Types, Config } from '@vtex/diagnostics-web';
async function init() {
// Initialize the central telemetry client
const telemetryClient = await NewTelemetryClient(
"my-app",
"web-component",
"v1.0.0",
{}
);
// Create traces client with OTLP exporter
const tracesClient = await telemetryClient.newTracesClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.TRACES,
options: {
endpoint: 'http://localhost:4318/v1/traces',
},
}, 'otlp', Config.ExporterProfile.BACKOFFICE)
});
// Start tracing
const span = tracesClient.startSpan("my-operation", {});
try {
// Your business logic here
span.setAttributes({ 'my.attribute': 'value' });
// Create a child span for a sub-operation
const childSpan = tracesClient.startSpan("sub-operation", {});
// ... more logic
childSpan.end();
} catch (error) {
console.error(error);
throw error;
} finally {
span.end();
}
}
init().catch(console.error);Metrics Example
import { NewTelemetryClient, Exporters, Types, Config } from '@vtex/diagnostics-web';
async function setupMetrics() {
const telemetryClient = await NewTelemetryClient("metrics-client", "web-component", "v1.0.0", {});
const metricsClient = await telemetryClient.newMetricsClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.METRICS,
options: {
endpoint: 'http://localhost:4318/v1/metrics'
}
}, 'otlp', Config.ExporterProfile.BACKOFFICE)
});
// Create a counter
const requestCounter = metricsClient.counter("http_requests_total");
requestCounter.add(1, { method: "GET", path: "/api" });
// Create a histogram
const responseTimeHistogram = metricsClient.histogram("response_time_seconds");
responseTimeHistogram.record(0.35, { method: "GET", path: "/api" });
// Create a gauge
const activeConnectionsGauge = metricsClient.gauge("active_connections");
activeConnectionsGauge.set(42, { pool: "main" });
return { metricsClient, requestCounter, responseTimeHistogram, activeConnectionsGauge };
}Logging Example
import { NewTelemetryClient, Exporters, Types, Config } from '@vtex/diagnostics-web';
async function setupLogging() {
const telemetryClient = await NewTelemetryClient("logs-client", "web-component", "v1.0.0", {});
const logsClient = await telemetryClient.newLogsClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.LOGS,
options: {
endpoint: 'http://localhost:4318/v1/logs'
}
}, 'otlp', Config.ExporterProfile.BACKOFFICE)
});
// Log different levels
logsClient.info("Application started", { version: "1.0.0" });
logsClient.warn("Resource usage high", { memory: "85%" });
try {
// Some operation that might fail
throw new Error("API connection failed");
} catch (err) {
logsClient.error("Operation failed", { error: err.message });
}
return logsClient;
}Events Example
Events are structured logs that do not have a severity level. They are useful for capturing meaningful occurrences in your application.
import { NewTelemetryClient, Exporters, Types, Config } from '@vtex/diagnostics-web';
async function setupEvents() {
const telemetryClient = await NewTelemetryClient("events-client", "web-component", "v1.0.0", {});
const eventsClient = await telemetryClient.newEventsClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.LOGS, // Events use the LOGS telemetry type
options: {
endpoint: 'http://localhost:4318/v1/logs'
}
}, 'otlp', Config.ExporterProfile.BACKOFFICE)
});
// Send an event
eventsClient.event("user_login", { userId: "123", method: "google" });
eventsClient.event("add_to_cart", { productId: "abc", quantity: 2 });
return eventsClient;
}Automatic Instrumentation
The library supports automatic instrumentations for various important metrics and events in web applications:
import { NewTelemetryClient, Types } from '@vtex/diagnostics-web';
async function setupInstrumentation() {
const telemetryClient = await NewTelemetryClient("my-app", "web-component", "v1.0.0", {});
// Configure default instrumentations
telemetryClient.useDefaultInstrumentations({
instrumentationLevel: Types.InstrumentationLevel.COMPREHENSIVE,
});
// This will automatically enable collection of:
// - Web Vitals (CLS, FID, LCP, etc.)
// - Exception tracking (uncaught errors, promise rejections)
// - User interactions
// - Resource loading
// - Long tasks
}React Integration
Telemetry Provider
// TelemetryProvider.jsx
'use client';
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { NewTelemetryClient, Exporters, Types, Config } from "@vtex/diagnostics-web";
type TelemetryContextType = {
tracesClient: any | null;
logsClient: any | null;
metricsClient: any | null;
eventsClient: any | null;
isLoaded: boolean;
};
export const TelemetryContext = createContext<TelemetryContextType>({
tracesClient: null,
logsClient: null,
metricsClient: null,
eventsClient: null,
isLoaded: false,
});
export function TelemetryProvider({ children }: { children: ReactNode }) {
const [clients, setClients] = useState<TelemetryContextType>({
tracesClient: null,
logsClient: null,
metricsClient: null,
eventsClient: null,
isLoaded: false,
});
useEffect(() => {
const initTelemetry = async () => {
try {
const telemetryClient = await NewTelemetryClient("my-react-app", "ui", "v1.0.0", {});
const tracesClient = await telemetryClient.newTracesClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.TRACES,
options: {
endpoint: 'http://localhost:4318/v1/traces',
}
}, 'otlp', Config.ExporterProfile.DEBUG)
});
const logsClient = await telemetryClient.newLogsClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.LOGS,
options: {
endpoint: 'http://localhost:4318/v1/logs'
}
}, 'otlp', Config.ExporterProfile.DEBUG)
});
const metricsClient = await telemetryClient.newMetricsClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.METRICS,
options: {
endpoint: 'http://localhost:4318/v1/metrics'
}
}, 'otlp', Config.ExporterProfile.DEBUG)
});
const eventsClient = await telemetryClient.newEventsClient({
exporter: Exporters.CreateExporter({
telemetryType: Types.TelemetryType.LOGS,
options: {
endpoint: 'http://localhost:4318/v1/logs'
}
}, 'otlp', Config.ExporterProfile.DEBUG)
});
telemetryClient.useDefaultInstrumentations({
instrumentationLevel: Types.InstrumentationLevel.COMPREHENSIVE,
});
setClients({
tracesClient,
logsClient,
metricsClient,
eventsClient,
isLoaded: true,
});
} catch (error) {
console.error('Failed to initialize telemetry:', error);
}
};
initTelemetry();
}, []);
return (
<TelemetryContext.Provider value={clients}>
{children}
</TelemetryContext.Provider>
);
}
export function useTelemetry() {
return useContext(TelemetryContext);
}Using the hook in components
// MyComponent.jsx
import { useTelemetry } from './TelemetryProvider';
export default function MyComponent() {
const { tracesClient, logsClient, eventsClient, isLoaded } = useTelemetry();
const handleClick = () => {
if (!isLoaded) return;
const span = tracesClient.startSpan("button_click", {});
try {
// Click logic
logsClient.info("Button clicked", { component: "MyComponent" });
eventsClient.event("button_clicked", { component: "MyComponent" });
// More operations...
} catch (error) {
logsClient.error("Error handling click", { error: error.message });
} finally {
span.end();
}
};
return (
<button onClick={handleClick}>Click Me</button>
);
}Advanced Configuration
Exporter Profiles
The library offers different configuration profiles to optimize behavior for your environment:
import { Config } from '@vtex/diagnostics-web';
// Available in Config.ExporterProfile:
// - DEBUG: High verbosity for development
// - BACKOFFICE: For administrative applications
// - STOREFRONT: Optimized for high traffic (store frontends)
const exporter = Exporters.CreateExporter(config, 'otlp', Config.ExporterProfile.DEBUG);Instrumentation Levels
Control the level of automatic instrumentation based on your needs:
import { Types } from '@vtex/diagnostics-web';
// Available levels:
// - MINIMAL: Minimal instrumentation (lowest overhead)
// - COMPREHENSIVE: Full instrumentation (Web Vitals, exceptions, interactions, etc.)
telemetryClient.useDefaultInstrumentations({
instrumentationLevel: Types.InstrumentationLevel.COMPREHENSIVE,
});Custom Sampling
import { Samplers } from '@vtex/diagnostics-web';
// Create a composed sampler
const customSampler = new Samplers.Traces.ComposedSampler([
new Samplers.Traces.DebugSampler(), // Sample spans with debug flag
new Samplers.Traces.MetadataSampler() // Sample based on metadata
]);
// Use the custom sampler
const tracesClient = await telemetryClient.newTracesClient({
exporter: /* exporter configuration */,
sampler: customSampler
});Processors
The library supports processors that can modify or enrich telemetry data:
import { Processors } from '@vtex/diagnostics-web';
// Use processor to add VTEX attributes
const tracesClient = await telemetryClient.newTracesClient({
exporter: /* exporter configuration */,
processors: [new Processors.VTEXAttrs.SpanProcessor()]
});
const logsClient = await telemetryClient.newLogsClient({
exporter: /* exporter configuration */,
processors: [new Processors.VTEXAttrs.LogProcessor()]
});Architecture
The library is structured in organized modules:
- config: Exporter configurations and version
- discovery: Resource discovery
- exporters: Exporter implementations (OTLP, stdout)
- instrumentation: Automatic instrumentations (Web Vitals, exceptions, etc.)
- logs: Logs client
- events: Events client
- metrics: Metrics client (counters, histograms, gauges)
- processors: Processors for data enrichment
- samplers: Sampling strategies
- telemetry: Main telemetry client
- traces: Traces client and spans
- types: Type definitions
- utils: Various utilities
