@vibesignals/observe
v1.0.5
Published
The simplest observability integration ever - Dual-mode support (Custom Events + OpenTelemetry OTLP), zero-config, framework agnostic
Downloads
602
Maintainers
Readme
Vibesignals SDK
The Simplest Observability Integration Ever ⚡
Zero-config observability for modern applications with dual-mode support: use custom events for business analytics OR OpenTelemetry OTLP for standards-compliant observability. Just 2 lines of code to get started.
✨ Features
- 🚀 Zero Configuration - Works out of the box with sensible defaults
- 📦 Flexible Bundle - 58KB for custom events, 176KB with full OpenTelemetry support
- 🎯 Dual Mode Support - Choose custom events OR OpenTelemetry OTLP (or both!)
- 🔧 Three Operating Modes:
- Custom Events: Flexible business analytics (default)
- OpenTelemetry OTLP: Standards-compliant observability
- Hybrid: Best of both worlds
- 🌐 Framework Agnostic - Works with Express, Next.js, React, Vue, Angular, and vanilla JavaScript
- 💪 TypeScript First - Full type safety and IntelliSense support
- 🛡️ Privacy Focused - Built-in data sanitization and masking
- ⚡ High Performance - Minimal overhead (<50ms)
- 📊 Rich Insights - Errors, performance, traces, metrics, and more
🎯 Quick Start
Installation
npm install @vibesignals/observeMode 1: Custom Events (Default - Simplest)
Perfect for business analytics, custom metrics, and flexible event tracking.
import { observe } from '@vibesignals/observe';
observe.init('YOUR_API_KEY');
// Done! Everything is now being tracked automatically ✨
// Track custom events
observe.event('user.signup', { plan: 'premium' });
observe.metric('checkout.duration', 1234);You now have:
- ✅ Error tracking
- ✅ Performance monitoring (Web Vitals)
- ✅ HTTP request tracing
- ✅ Console log capture
- ✅ Custom events and metrics
API Endpoint: POST /api/v1/events/batch
Mode 2: OpenTelemetry OTLP (Standards-Compliant)
Perfect for distributed tracing, microservices, and vendor-neutral observability.
import { otlp } from '@vibesignals/observe';
// Configure OpenTelemetry OTLP exporters
const { tracer, meter } = await otlp.configureOTLP({
apiKey: 'YOUR_API_KEY',
serviceName: 'my-service',
serviceVersion: '1.0.0',
// endpoint: 'https://custom-backend.com', // Optional: only for dev/testing/self-hosted
});
// Use OpenTelemetry Tracer API
const span = tracer.startSpan('process-order');
span.setAttribute('order.id', '12345');
span.end();
// Use OpenTelemetry Metrics API
const counter = meter.createCounter('orders.total');
counter.add(1, { status: 'completed' });You now have:
- ✅ OTLP/HTTP traces (Protobuf or JSON)
- ✅ OTLP/HTTP metrics (counters, histograms, gauges)
- ✅ Distributed tracing with W3C Trace Context
- ✅ OpenTelemetry Semantic Conventions
- ✅ Vendor-neutral telemetry
API Endpoints:
POST /v1/traces(OTLP)POST /v1/metrics(OTLP)POST /v1/logs(OTLP)
Mode 3: Hybrid (Best of Both Worlds)
Perfect for comprehensive monitoring - business events + technical observability.
import { observe, otlp } from '@vibesignals/observe';
// Initialize both systems
observe.init('YOUR_API_KEY', {
mode: 'hybrid',
});
const { tracer } = await otlp.configureOTLP({
apiKey: 'YOUR_API_KEY',
serviceName: 'ecommerce-api',
});
// Use both together
async function processOrder(orderId) {
// Start OTLP trace
const span = tracer.startSpan('process-order');
const spanContext = span.spanContext();
try {
// ... your business logic ...
// Send custom business event linked to trace
observe.event('order.completed', {
order_id: orderId,
// Link to distributed trace
trace_id: spanContext.traceId,
span_id: spanContext.spanId,
});
span.setStatus({ code: SpanStatusCode.OK });
} catch (error) {
span.recordException(error);
observe.event('order.failed', {
order_id: orderId,
error: error.message,
trace_id: spanContext.traceId,
});
throw error;
} finally {
span.end();
}
}You now have:
- ✅ Custom business events
- ✅ OpenTelemetry distributed traces
- ✅ Events linked to traces (query together in ClickHouse!)
- ✅ Comprehensive monitoring
Both API endpoints used!
📊 Mode Comparison
| Feature | Custom Events | OpenTelemetry OTLP | Hybrid | |---------|--------------|-------------------|---------| | Setup | 2 lines | ~10 lines | Both | | Bundle Size | ~58KB | ~176KB | ~176KB | | Use Case | Business analytics | Technical observability | Both | | Standards | Proprietary | CNCF OpenTelemetry | Both | | Learning Curve | Low | Medium | Medium | | Best For | Simple apps, custom metrics | Microservices, distributed systems | Comprehensive monitoring |
📚 Documentation
Core Documentation
Integration Guides
Advanced
🔧 Configuration
Custom Events Mode Configuration
observe.init('YOUR_API_KEY', {
// Mode selection
mode: 'custom-events', // 'custom-events' | 'otlp' | 'hybrid'
// Connection (endpoint is optional - only for dev/testing/self-hosted)
// endpoint: 'http://localhost:8080', // Optional: defaults to https://api.vibesignals.ai
environment: 'production',
release: 'v1.2.3',
// Batching
batchSize: 1000,
maxBatchSize: 10000,
flushInterval: 5000,
// Auto-instrumentation
autoInstrument: true,
captureConsole: true,
captureErrors: true,
capturePerformance: true,
captureHttp: true,
// Sampling
sampleRate: 1.0, // 100% of events
// Filter/modify events
beforeSend: (event) => {
delete event.context.user?.email;
return event;
},
// Privacy controls
privacy: {
maskEmails: true,
maskIPs: true,
sensitiveKeys: ['password', 'token', 'apiKey'],
},
// Retry strategy
retry: {
maxRetries: 3,
initialDelay: 1000,
maxDelay: 60000,
backoffMultiplier: 2,
jitter: true,
},
});OpenTelemetry OTLP Configuration
const { tracer, meter, shutdown } = await otlp.configureOTLP({
// Required
apiKey: 'YOUR_API_KEY',
serviceName: 'my-service',
// Optional
endpoint: 'http://localhost:8080', // Base URL
serviceVersion: '1.0.0',
useTLS: false, // Auto-detected for localhost
// Resource attributes (added to all telemetry)
resourceAttributes: {
'deployment.environment': 'production',
'service.namespace': 'backend',
'host.name': 'server-1',
},
});
// Remember to shutdown on process exit
process.on('SIGTERM', async () => {
await shutdown();
process.exit(0);
});Development Mode
Enable dev mode to see what's being tracked in your console:
observe.init('YOUR_API_KEY', {
dev: true, // Pretty prints to console instead of sending
});
// Output:
// 🔍 [Vibesignals] HTTP
// Data: { method: 'GET', url: '/api/users', duration: 145 }
// ⚠️ [Vibesignals] ERROR
// Data: { message: 'Database connection failed' }🎨 Framework Integrations
Express.js (Custom Events)
import express from 'express';
import { observe, integrations } from '@vibesignals/observe';
observe.init('YOUR_API_KEY');
const app = express();
// Add Vibesignals middleware
const expressIntegration = integrations.Express();
app.use(expressIntegration.middleware());
// Error handler
app.use(expressIntegration.errorHandler());
app.listen(3000);Express.js (OpenTelemetry)
import express from 'express';
import { otlp } from '@vibesignals/observe';
const { tracer } = await otlp.configureOTLP({
apiKey: 'YOUR_API_KEY',
serviceName: 'express-api',
});
const app = express();
app.get('/api/users', async (req, res) => {
const span = tracer.startSpan('GET /api/users');
try {
const users = await fetchUsers();
span.setStatus({ code: SpanStatusCode.OK });
res.json(users);
} finally {
span.end();
}
});
app.listen(3000);Next.js
// pages/_app.tsx
import { observe, integrations } from '@vibesignals/observe';
observe.init('YOUR_API_KEY');
const nextIntegration = integrations.NextJS();
export default nextIntegration.wrapApp(MyApp);React
import { observe, integrations } from '@vibesignals/observe';
observe.init('YOUR_API_KEY');
const reactIntegration = integrations.React();
const ErrorBoundary = reactIntegration.createErrorBoundary();
function App() {
return (
<ErrorBoundary>
<YourApp />
</ErrorBoundary>
);
}Vue.js
import { createApp } from 'vue';
import { observe, integrations } from '@vibesignals/observe';
observe.init('YOUR_API_KEY');
const app = createApp(App);
const vueIntegration = integrations.Vue();
vueIntegration.install(app);Angular
// app.module.ts
import { ErrorHandler } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { observe, integrations } from '@vibesignals/observe';
observe.init('YOUR_API_KEY');
const angularIntegration = integrations.Angular();
const providers = angularIntegration.createAngularProviders(angularIntegration);
@NgModule({
providers: [
{ provide: ErrorHandler, useClass: providers.ErrorHandler },
{ provide: HTTP_INTERCEPTORS, useClass: providers.HttpInterceptor, multi: true },
]
})
export class AppModule {}🎯 Manual Instrumentation
Custom Events & Metrics
import { observe } from '@vibesignals/observe';
// Track custom events
observe.event('button_clicked', {
button_id: 'signup-cta',
page: '/pricing',
});
// Track metrics
observe.metric('cart.value', 149.99, {
currency: 'USD',
items: 3,
});
// Trace function execution
await observe.trace('process-payment', async () => {
return await processPayment();
}, {
payment_method: 'stripe',
});
// Manual span creation
const span = observe.startSpan('database-query');
span.setTag('query_type', 'select');
await executeQuery();
span.finish();OpenTelemetry Tracing
import { otlp, SpanStatusCode } from '@vibesignals/observe';
const { tracer } = await otlp.configureOTLP({...});
// Manual span
const span = tracer.startSpan('operation-name');
span.setAttribute('user.id', userId);
span.addEvent('processing started');
span.setStatus({ code: SpanStatusCode.OK });
span.end();
// Nested spans
const parentSpan = tracer.startSpan('parent-operation');
const childSpan = tracer.startSpan('child-operation', {
parent: parentSpan.spanContext(),
});
childSpan.end();
parentSpan.end();OpenTelemetry Metrics
const { meter } = await otlp.configureOTLP({...});
// Counter (monotonically increasing)
const requestCounter = meter.createCounter('http.requests', {
description: 'Total HTTP requests',
});
requestCounter.add(1, { method: 'GET', status: 200 });
// Histogram (distribution)
const latencyHistogram = meter.createHistogram('http.latency', {
description: 'HTTP request latency',
unit: 'ms',
});
latencyHistogram.record(123.45, { route: '/api/users' });
// UpDownCounter (can increase/decrease)
const activeConnections = meter.createUpDownCounter('connections.active');
activeConnections.add(1); // New connection
activeConnections.add(-1); // Connection closedUser Context
import { observe } from '@vibesignals/observe';
// Set user context
observe.setUser({
id: 'user_123',
email: '[email protected]',
username: 'johndoe',
subscription: 'premium',
});
// Set custom context
observe.setContext('cart', {
items: 3,
total: 149.99,
});
// Clear context
observe.clearContext();🚀 Advanced Features
Error Tracking
// Automatically tracked
throw new Error('Something went wrong');
// Manually track
try {
riskyOperation();
} catch (error) {
observe.event('operation.failed', {
error: error.message,
stack: error.stack,
});
}Performance Monitoring
Automatically tracks:
- ✅ Page Load Time
- ✅ Web Vitals (LCP, FID, CLS)
- ✅ HTTP Request Duration
- ✅ Custom Performance Marks
// Custom performance tracking
await observe.trace('heavy-operation', async () => {
return await heavyComputation();
});HTTP Request Tracking
Automatically captures:
- ✅ Method, URL, Status Code
- ✅ Request/Response Duration
- ✅ Headers (sanitized)
- ✅ Errors and Timeouts
Privacy & Security
observe.init('YOUR_API_KEY', {
privacy: {
maskEmails: true, // [email protected] → u***@example.com
maskIPs: true, // 192.168.1.1 → 192.168.*.*
sensitiveKeys: [ // Remove these keys from all data
'password',
'creditCard',
'ssn',
'apiKey',
],
},
beforeSend: (event) => {
// Custom filtering
if (event.data.sensitive) {
return null; // Drop the event
}
return event;
},
});📦 Bundle Size
| Mode | Bundle Size | Notes | |------|-------------|-------| | Custom Events | ~58KB | Lightweight, zero dependencies | | OpenTelemetry OTLP | ~176KB | Includes OpenTelemetry SDKs | | Hybrid | ~176KB | Both modes available |
Optimization tip: Use dynamic imports to lazy-load OTLP:
// Only load when needed
if (shouldEnableOTLP) {
const { otlp } = await import('@vibesignals/observe');
await otlp.configureOTLP({...});
}🗄️ Data Storage (ClickHouse)
Tables
| Table | API | Purpose |
|-------|-----|---------|
| events | Custom Events | Business events, flexible JSON schema |
| otlp_traces | OTLP | Distributed tracing spans |
| otlp_metrics | OTLP | Metrics (counters, histograms, gauges) |
| otlp_logs | OTLP | Application logs |
Cross-Table Queries
Link custom events to OTLP traces:
-- Find all data for a trace
SELECT 'trace' AS type, name, start_time
FROM otlp_traces
WHERE trace_id = '0af7651916cd43dd8448eb211c80319c'
UNION ALL
SELECT 'event' AS type, event_type, timestamp
FROM events
WHERE JSONExtractString(data, 'trace_id') = '0af7651916cd43dd8448eb211c80319c'
ORDER BY timestamp;🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📄 License
MIT © Vibesignals
🔗 Links
- Documentation Site
- npm Package
- GitHub Repository
- OpenTelemetry Documentation
- Vibesignals API Documentation
💡 Need Help?
- 📖 Read the docs
- 💬 Open an issue
- 🌟 Star us on GitHub if you find this useful!
Built with ❤️ by the Vibesignals team
🚀 Start monitoring your application in 2 minutes!
