@reasonable-logging/js-sdk
v1.0.1
Published
Official JavaScript SDK for Reasonable logging platform
Maintainers
Readme
🚀 @reasonable-logging/js-sdk
The official JavaScript SDK for Reasonable - Simple, powerful logging and event tracking for modern applications.
✨ Features
- 🎯 Simple & Intuitive - Get started in minutes with our clean API
- 🏗️ TypeScript First - Built with full TypeScript support and type safety
- 🔥 Lightweight - Zero dependencies, minimal bundle size
- 🚀 Performance - Optimized for speed with batching and async operations
- 🛡️ Reliable - Comprehensive error handling and retry logic
- 📊 Rich Metadata - Attach custom metadata to every log and event
- 🎨 Flexible - Works in Node.js, browsers, and edge environments
- 🔍 Developer Experience - Child loggers, global metadata, and more
📦 Installation
npm install @reasonable-logging/js-sdkyarn add @reasonable-logging/js-sdkpnpm add @reasonable-logging/js-sdk🚀 Quick Start
import { ReasonableLogger } from '@reasonable-logging/js-sdk';
// Initialize the logger
const logger = new ReasonableLogger({
projectId: 'your-project-id',
apiKey: 'your-api-key',
application: 'my-awesome-app'
});
// Start logging!
await logger.info('User logged in', { userId: '123', plan: 'pro' });
await logger.error('Payment failed', { error: 'card_declined', amount: 99.99 });
// Track custom events
await logger.userEvent('signup', 'user-123', { plan: 'pro', source: 'organic' });
await logger.businessEvent('purchase', { amount: 99.99, plan: 'pro' });📖 API Reference
Constructor
const logger = new ReasonableLogger({
projectId: string, // Your Reasonable project ID
apiKey: string, // Your API key
baseUrl?: string, // Custom API endpoint (optional, defaults to https://reasonable.sh)
application?: string, // Application name (optional)
timeout?: number // Request timeout in ms (default: 5000)
});Logging Methods
All logging methods return a Promise<LogResponse> and accept optional metadata.
📝 Basic Logging
// Log levels: debug, info, warn, error, fatal
await logger.debug('Debug message', { context: 'debugging' });
await logger.info('User action', { userId: '123', action: 'click' });
await logger.warn('Rate limit approaching', { current: 95, limit: 100 });
await logger.error('Database error', { query: 'SELECT *', error: 'timeout' });
await logger.fatal('System crash', { exitCode: 1, reason: 'out_of_memory' });📊 Event Tracking
// User events (signup, login, logout, etc.)
await logger.userEvent('signup', 'user-123', {
plan: 'pro',
source: 'organic',
campaign: 'summer2024'
});
// Business events (purchase, conversion, etc.)
await logger.businessEvent('purchase', {
amount: 99.99,
currency: 'USD',
plan: 'pro',
paymentMethod: 'card'
});
// Performance events (load times, response times, etc.)
await logger.performanceEvent('page_load', {
loadTime: 1250,
route: '/dashboard',
browser: 'Chrome'
});
// Custom events (anything else!)
await logger.customEvent('feature_used', {
feature: 'dark_mode',
enabled: true,
userId: 'user-123'
});🌟 Advanced Features
Global Metadata
Set metadata that will be included with every log entry:
logger.setGlobalMeta({
version: '2.1.0',
environment: 'production',
region: 'us-west-2',
buildId: 'abc123'
});
// Now every log will include this metadata automatically
await logger.info('User action'); // Includes version, environment, etc.Child Loggers
Create specialized loggers with their own context:
// Create a child logger for a specific component
const authLogger = logger.child({ component: 'auth', module: 'login' });
// All logs from this child will include the component and module context
await authLogger.info('Login attempt', { email: '[email protected]' });
await authLogger.error('Login failed', { reason: 'invalid_password' });
// Create child loggers for different users
const userLogger = logger.child({ userId: 'user-123', plan: 'pro' });
await userLogger.info('Profile updated');🏗️ Framework Integration
React
import React, { useEffect } from 'react';
import { ReasonableLogger } from '@reasonable-logging/js-sdk';
const logger = new ReasonableLogger({
projectId: process.env.REACT_APP_REASONABLE_PROJECT_ID,
apiKey: process.env.REACT_APP_REASONABLE_API_KEY,
application: 'my-react-app'
});
function App() {
useEffect(() => {
// Set browser context
logger.setGlobalMeta({
userAgent: navigator.userAgent,
url: window.location.href,
timestamp: new Date().toISOString()
});
logger.info('App initialized');
}, []);
const handleClick = async () => {
await logger.userEvent('button_click', undefined, {
button: 'cta',
page: 'home'
});
};
return <button onClick={handleClick}>Click me!</button>;
}Node.js/Express
const express = require('express');
const { ReasonableLogger } = require('@reasonable-logging/js-sdk');
const app = express();
const logger = new ReasonableLogger({
projectId: process.env.REASONABLE_PROJECT_ID,
apiKey: process.env.REASONABLE_API_KEY,
application: 'my-api'
});
// Middleware to add request context
app.use((req, res, next) => {
req.logger = logger.child({
requestId: req.headers['x-request-id'],
userAgent: req.headers['user-agent'],
ip: req.ip,
method: req.method,
path: req.path
});
next();
});
app.get('/api/users', async (req, res) => {
try {
await req.logger.info('Fetching users');
const users = await getUsers();
await req.logger.info('Users fetched successfully', {
count: users.length
});
res.json(users);
} catch (error) {
await req.logger.error('Failed to fetch users', {
error: error.message
});
res.status(500).json({ error: 'Internal server error' });
}
});Next.js
// lib/logger.ts
import { ReasonableLogger } from '@reasonable-logging/js-sdk';
export const logger = new ReasonableLogger({
projectId: process.env.NEXT_PUBLIC_REASONABLE_PROJECT_ID!,
apiKey: process.env.REASONABLE_API_KEY!,
application: 'my-nextjs-app'
});
// pages/api/users.ts
import { logger } from '../../lib/logger';
export default async function handler(req, res) {
const requestLogger = logger.child({
requestId: req.headers['x-request-id'],
method: req.method,
url: req.url
});
try {
await requestLogger.info('API request started');
// Your API logic here
await requestLogger.info('API request completed');
res.status(200).json({ success: true });
} catch (error) {
await requestLogger.error('API request failed', { error: error.message });
res.status(500).json({ error: 'Internal server error' });
}
}🔧 Configuration
Environment Variables
For security, we recommend using environment variables:
# .env
REASONABLE_PROJECT_ID=your-project-id
REASONABLE_API_KEY=your-api-key
REASONABLE_BASE_URL=https://your-custom-domain.com # optionalTypeScript Configuration
The SDK is built with TypeScript and provides full type safety:
import { ReasonableLogger, LogData, EventData, LogResponse } from '@reasonable-logging/js-sdk';
// All types are exported for your convenience
const logData: LogData = {
level: 'INFO',
message: 'Typed log entry',
meta: { typed: true }
};
const response: LogResponse = await logger.log(logData);🚨 Error Handling
The SDK handles errors gracefully and provides detailed error information:
try {
await logger.info('This might fail');
} catch (error) {
console.error('Logging failed:', error.message);
// Your app continues to work normally
}
// Or handle errors in the response
const response = await logger.info('Safe logging');
if (!response.success) {
console.error('Log failed:', response.error);
}🎯 Best Practices
1. Use Environment-Specific Loggers
// Create different loggers for different environments
const logger = new ReasonableLogger({
projectId: process.env.NODE_ENV === 'production'
? 'prod-project-id'
: 'dev-project-id',
apiKey: process.env.REASONABLE_API_KEY,
application: `my-app-${process.env.NODE_ENV}`
});2. Structure Your Metadata
// Consistent metadata structure
await logger.info('User action', {
// User context
userId: 'user-123',
email: '[email protected]',
// Action context
action: 'profile_update',
section: 'settings',
// Technical context
version: '2.1.0',
platform: 'web',
browser: 'Chrome'
});3. Use Child Loggers for Components
// Create specialized loggers
const authLogger = logger.child({ component: 'auth' });
const paymentLogger = logger.child({ component: 'payment' });
const analyticsLogger = logger.child({ component: 'analytics' });
// Each maintains its own context
await authLogger.info('Login successful');
await paymentLogger.error('Payment failed');
await analyticsLogger.info('Event tracked');4. Log Business Events
// Track important business metrics
await logger.businessEvent('user_signup', {
plan: 'pro',
source: 'organic',
revenue: 29.99,
trial: false
});
await logger.businessEvent('feature_used', {
feature: 'advanced_search',
plan: 'enterprise',
userId: 'user-123'
});📊 Monitoring & Observability
Performance Tracking
// Track application performance
const startTime = Date.now();
try {
await someExpensiveOperation();
await logger.performanceEvent('operation_completed', {
duration: Date.now() - startTime,
operation: 'data_export',
recordCount: 1500
});
} catch (error) {
await logger.error('Operation failed', {
duration: Date.now() - startTime,
operation: 'data_export',
error: error.message
});
}User Journey Tracking
// Track user flow through your application
await logger.userEvent('page_view', userId, { page: 'landing' });
await logger.userEvent('cta_click', userId, { cta: 'sign_up', page: 'landing' });
await logger.userEvent('form_start', userId, { form: 'signup' });
await logger.userEvent('form_complete', userId, { form: 'signup', duration: 45 });
await logger.userEvent('signup_success', userId, { plan: 'pro' });🔗 API Endpoints
The SDK communicates with these Reasonable API endpoints:
- Logs:
POST /api/v1/logs- Send log entries - Events:
POST /api/v1/events- Send custom events
🛠️ Development
# Clone the repository
git clone https://github.com/reasonable-logging/reasonable.git
cd reasonable/sdk/js
# Install dependencies
npm install
# Run tests
npm test
# Build the project
npm run build
# Watch mode for development
npm run dev🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📝 License
MIT © entwicklerstube ug (haftungsbeschränkt)
🆘 Support
- 📖 Documentation: https://docs.reasonable.dev
- 📧 Email: [email protected]
- 🐛 Issues: GitHub Issues
