npm package: @loglito/loglito
Description: JavaScript/TypeScript client library for Loglito logging service
Author: Loglito Team
Latest version: 0.1.32

# @loglito/loglito

[![npm version](https://badge.fury.io/js/%40loglito%2Fjs.svg)](https://badge.fury.io/js/%40loglito%2Fjs)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

The official JavaScript/TypeScript client library for [Loglito](https://loglito.io), a powerful logging and observability platform designed for solo developers.

## Features

- 🚀 **High Performance** - Intelligent buffering with configurable flush intervals
- 🔄 **Auto-Retry** - Built-in retry logic with exponential backoff
- 📝 **Multiple Calling Patterns** - Flexible API supporting various usage styles
- 🧪 **TypeScript Support** - Full TypeScript definitions included
- 🌐 **Universal** - Works in Node.js and modern browsers
- 📦 **Batch Logging** - Send multiple logs in a single request
- ⚡ **Immediate Mode** - Option for real-time logging without buffering
- 🛡️ **Error Handling** - Comprehensive error types for different scenarios
- 🔍 **Trace Functionality** - Group related logs with trace IDs for better debugging

## Installation

```bash
npm install @loglito/loglito
```

```bash
yarn add @loglito/loglito
```

## Quick Start

```typescript
import { Loglito } from '@loglito/loglito';

// Initialize the client with your API key
const loglito = new Loglito({ 
  apiKey: 'your-api-key-here',
  project: 'my_awesome_project' // Optional: project name added as __project_name to all logs
});

// Simple logging
await loglito.log('Hello world!');

// Level, message, and data
await loglito.log('info', 'User subscribed', { 
  user_id: 123, 
  plan: 'premium' 
});

// NEW: Convenient shortcut methods for different log levels
await loglito.info('User logged in', { user_id: 2132 });
await loglito.debug('API response', { status: 200, endpoint: '/users' });
await loglito.warning('Rate limit approaching', { current_usage: 85, limit: 100 });
await loglito.error('Database connection failed', { error: 'timeout', retries: 3 });

// Traditional structured logging
await loglito.log({
  message: 'User logged in',
  data: {
    username: 'john',
    ip_address: '192.168.1.1'
  }
});

// Log with specific level
await loglito.log('warning', 'Low disk space', {
  disk_usage: '85%',
  server: 'web-01'
});

// Trace functionality - group related logs
loglito.setTrace('request-123');
await loglito.info('Request started', { endpoint: '/api/users' });
await loglito.debug('Database query executed', { time: 23.5 });
await loglito.info('Request completed', { status: 200 });
loglito.clearTrace(); // Clear trace for next operation
```

## Shortcut Methods

For convenience, the client provides shortcut methods for common log levels:

```typescript
import { Loglito } from '@loglito/loglito';

const loglito = new Loglito({ apiKey: 'your-api-key' });

// Info level logging
await loglito.info('User logged in', { user_id: 2132 });

// Debug level logging
await loglito.debug('SQL query executed', {
  query: 'SELECT * FROM users WHERE id = ?',
  params: [123],
  execution_time: 0.045
});

// Warning level logging
await loglito.warning('Rate limit approaching', {
  current_usage: 85,
  limit: 100,
  user_id: 456
});

// Error level logging
await loglito.error('Payment processing failed', {
  error: 'card_declined',
  order_id: 'ORD-789',
  amount: 99.99
});

// The data parameter is optional
await loglito.info('Application started');
await loglito.debug('Cache miss');
```

## Configuration

### Basic Configuration

```typescript
import { Loglito } from '@loglito/loglito';

const loglito = new Loglito({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.loglito.io',  // Custom API endpoint
  timeout: 30000,                      // Request timeout in milliseconds
  retries: 3,                          // Number of retry attempts
  verifySsl: true                      // SSL certificate verification
});
```

### Performance Configuration (Buffering)

The client uses intelligent buffering for optimal performance:

```typescript
const loglito = new Loglito({
  apiKey: 'your-api-key',
  bufferSize: 100,        // Flush after 100 logs
  flushInterval: 2000,    // Flush every 2 seconds
  immediateMode: false    // Use buffering (default)
});

// For real-time logging (no buffering)
const loglitoImmediate = new Loglito({
  apiKey: 'your-api-key',
  immediateMode: true
});
```

### Project Parameter

You can set a project name that will be automatically added as `__project_name` to all log entries:

```typescript
// Project parameter - adds __project_name to all logs
const loglito = new Loglito({
  apiKey: 'your-api-key',
  project: 'my_awesome_project'
});

await loglito.log('User login');
// Results in: {"__message": "User login", "__project_name": "my_awesome_project", ...}
```

### Default Data

You can also configure default data that will be automatically included in all log entries:

```typescript
// Set default data that will be included in ALL logs
const loglito = new Loglito({
  apiKey: 'your-api-key',
  project: 'my_awesome_project', // Project ID
  data: {
    version: '1.0.2',
    environment: 'production',
    service: 'user-authentication'
  }
});

// All logs will now include the default data
await loglito.log('User login');
// Results in: {"__message": "User login", "project": "nextsearch", "version": "1.0.2", ...}

await loglito.log('info', 'Payment processed', { amount: 99.99 });
// Results in: {"__level": "info", "__message": "Payment processed", "amount": 99.99, "project": "nextsearch", ...}

// Specific log data can override default data
await loglito.log('warning', 'Test environment issue', { environment: 'testing' });
// The "environment" field will be "testing" instead of "production"

// Works with all log methods
await loglito.info('User action', { action: 'file_upload' });
// Includes both the default data AND the specific action data
```

### Environment Variables

You can also configure the client using environment variables:

```typescript
const loglito = new Loglito({
  apiKey: process.env.LOGLITO_API_KEY!,
  baseUrl: process.env.LOGLITO_BASE_URL || 'https://loglito.io'
});
```

## Usage Examples

### Multiple Calling Patterns

The `log()` method supports several flexible calling patterns:

```typescript
const loglito = new Loglito({ apiKey: 'your-api-key' });

// 1. Simple string message
await loglito.log('Application started');

// 2. Level, message, and data object (RECOMMENDED)
await loglito.log('info', 'User subscribed', { 
  user_id: 123, 
  plan: 'premium' 
});

// 3. Level, message, and multiple data objects
await loglito.log('info', 'User action', 
  { user_id: 123 }, 
  { action: 'file_upload' }, 
  { file_size: 1024 }
);

// 4. Object-style arguments
await loglito.log({
  level: 'info',
  message: 'User authentication successful',
  data: { user_id: 123 }
});

// 5. Mixed approach with additional properties
await loglito.log('error', 'Payment failed', 
  { order_id: '12345', amount: 99.99 },
  { retry_count: 3, processor: 'stripe' }
);
```

### API Payload Format

All logs are sent to the API in a consistent batch format:

```json
{
  "logs": [
    {
      "log": {
        "__date": "2024-01-15T10:30:00.123Z",
        "__message": "User subscribed",
        "__level": "info",
        "user_id": 123,
        "plan": "premium"
      }
    }
  ]
}
```

### Structured Logging

```typescript
// E-commerce example
await loglito.log('info', 'Order placed', {
  order_id: 'ORD-12345',
  customer_id: 'CUST-789',
  total_amount: 99.99,
  items: [
    { product: 'Widget A', quantity: 2, price: 29.99 },
    { product: 'Widget B', quantity: 1, price: 39.99 }
  ],
  payment_method: 'credit_card',
  shipping_address: {
    city: 'New York',
    state: 'NY',
    zip: '10001'
  }
});

// Error logging with context
await loglito.log('error', 'Database connection failed', {
  error_type: 'ConnectionTimeout',
  database: 'postgres',
  host: 'db.example.com',
  retry_count: 3,
  port: 5432
});

// Debug logging for performance monitoring
await loglito.log('debug', 'API response time', {
  endpoint: '/api/users',
  method: 'GET',
  response_time: 0.245,
  status_code: 200,
  user_id: 123
});
```

### Batch Logging

For high-volume applications, use batch logging to send multiple logs in a single request:

```typescript
const logs = [
  {
    message: 'User login',
    level: 'info' as const,
    data: { user_id: 123, ip: '192.168.1.1' }
  },
  {
    message: 'Page view',
    level: 'debug' as const,
    data: { page: '/dashboard', user_id: 123 }
  },
  {
    message: 'API call',
    level: 'info' as const,
    data: { endpoint: '/api/users', method: 'GET', status: 200 }
  }
];

await loglito.logBatch(logs);
```

### Trace Functionality

Use trace IDs to group related log entries together, making it easier to follow request flows or batch operations:

```typescript
const loglito = new Loglito({ apiKey: 'your-api-key' });

// Request tracing example
loglito.setTrace('request-abc123');

await loglito.info('Request started', { endpoint: '/api/users', method: 'GET' });
await loglito.debug('Database query executed', { 
  query: 'SELECT * FROM users WHERE active = ?', 
  execution_time: 23.5 
});
await loglito.debug('Cache lookup performed', { 
  cache_key: 'users_active', 
  cache_hit: true 
});
await loglito.info('Request completed', { 
  status_code: 200, 
  response_time: 45.2 
});

// Clear trace for next request
loglito.clearTrace();

// Batch processing example
loglito.setTrace('batch-xyz789');

const batchLogs = [
  { message: 'Batch job started', level: 'info', data: { job_type: 'user_export' } },
  { message: 'Processing chunk 1', level: 'debug', data: { records: 100 } },
  { message: 'Processing chunk 2', level: 'debug', data: { records: 100 } },
  { message: 'Batch job completed', level: 'info', data: { total_records: 200 } }
];

await loglito.logBatch(batchLogs);

// Multiple operations with different traces
loglito.setTrace('email-operation-456');
await loglito.info('Email sending started');
await loglito.info('Email sent successfully');

loglito.setTrace('file-operation-789');
await loglito.info('File processing started');
await loglito.info('File processed successfully');

// Operations without trace
loglito.clearTrace();
await loglito.info('Background cleanup completed');
```

All logs sent while a trace ID is set will automatically include `__trace_id` in the log data, making it easy to filter and group related logs in your Loglito dashboard.

### Using async/await and Promises

```typescript
// Using async/await
try {
  const success = await loglito.log('info', 'User action', { user_id: 123 });
  if (success) {
    console.log('Log sent successfully');
  }
} catch (error) {
  console.error('Failed to send log:', error);
}

// Using Promises
loglito.log('info', 'Background task', { task_id: 'bg-001' })
  .then(success => {
    if (success) {
      console.log('Log queued successfully');
    }
  })
  .catch(error => {
    console.error('Failed to queue log:', error);
  });
```

### Manual Flushing

```typescript
// Queue some logs
await loglito.log('info', 'Event 1');
await loglito.log('info', 'Event 2');
await loglito.log('info', 'Event 3');

// Manually flush all queued logs
const flushed = await loglito.flush(5000); // 5 second timeout
if (flushed) {
  console.log('All logs flushed successfully');
}
```

## API Reference

### Loglito Class

#### Constructor

```typescript
new Loglito(config: LoglitoConfig)
```

**LoglitoConfig Properties:**
- `apiKey` (string): Your Loglito API key (required)
- `baseUrl` (string, optional): Base URL for the Loglito API
- `timeout` (number, optional): Request timeout in milliseconds
- `retries` (number, optional): Number of retry attempts for failed requests
- `verifySsl` (boolean, optional): Whether to verify SSL certificates
- `bufferSize` (number, optional): Maximum logs to buffer before forcing flush
- `flushInterval` (number, optional): Time in milliseconds between automatic flushes
- `immediateMode` (boolean, optional): Send logs immediately without buffering

#### Methods

##### `log(...args): Promise<boolean>`

Send a single log entry to Loglito.

**Calling Patterns:**
- `log(message: string)`
- `log(level: LogLevel, message: string)`
- `log(level: LogLevel, message: string, data: object)`
- `log(level: LogLevel, message: string, ...dataObjects: object[])`
- `log(options: { level?, message?, data?, [key]: any })`

**Returns:** `Promise<boolean>` - True if successful, False otherwise

##### `logBatch(logs: LogEntry[]): Promise<boolean>`

Send multiple log entries in a single request.

**Parameters:**
- `logs` (LogEntry[]): Array of log objects

**Returns:** `Promise<boolean>` - True if successful, False otherwise

##### `flush(timeoutMs?: number): Promise<boolean>`

Manually flush all queued logs.

**Parameters:**
- `timeoutMs` (number, optional): Maximum time to wait for flush completion

**Returns:** `Promise<boolean>` - True if flush completed successfully

##### `testConnection(): Promise<boolean>`

Test the connection to Loglito by sending a test log.

**Returns:** `Promise<boolean>` - True if connection is successful

##### `close(): Promise<void>`

Close the client and flush any remaining logs.

**Returns:** `Promise<void>`

##### `info(message: string, data?: Record<string, any>): Promise<boolean>`

Send an info level log entry.

**Parameters:**
- `message` (string): Log message
- `data` (object, optional): Additional structured data

**Returns:** `Promise<boolean>` - True if successful, False otherwise

##### `debug(message: string, data?: Record<string, any>): Promise<boolean>`

Send a debug level log entry.

**Parameters:**
- `message` (string): Log message
- `data` (object, optional): Additional structured data

**Returns:** `Promise<boolean>` - True if successful, False otherwise

##### `warning(message: string, data?: Record<string, any>): Promise<boolean>`

Send a warning level log entry.

**Parameters:**
- `message` (string): Log message
- `data` (object, optional): Additional structured data

**Returns:** `Promise<boolean>` - True if successful, False otherwise

##### `error(message: string, data?: Record<string, any>): Promise<boolean>`

Send an error level log entry.

**Parameters:**
- `message` (string): Log message
- `data` (object, optional): Additional structured data

**Returns:** `Promise<boolean>` - True if successful, False otherwise

##### `setTrace(traceId: string): void`

Set a trace ID that will be automatically added to all subsequent log entries.

**Parameters:**
- `traceId` (string): The trace ID to set. This will be added as `__trace_id` to all logs.

**Returns:** `void`

##### `clearTrace(): void`

Clear the current trace ID.

After calling this method, subsequent log entries will not include the trace ID.

**Returns:** `void`

### Types

```typescript
// Log levels
type LogLevel = 'debug' | 'info' | 'warning' | 'error' | 'critical';

// Log entry for batch operations
interface LogEntry {
  message?: string;
  level?: LogLevel;
  data?: Record<string, any>;
  [key: string]: any;
}

// Configuration interface
interface LoglitoConfig {
  apiKey: string;
  baseUrl?: string;
  timeout?: number;
  retries?: number;
  verifySsl?: boolean;
  bufferSize?: number;
  flushInterval?: number;
  immediateMode?: boolean;
}
```

## Error Handling

The client provides specific exception types for different error scenarios:

```typescript
import { 
  Loglito, 
  LoglitoError, 
  LoglitoAuthenticationError, 
  LoglitoConnectionError,
  LoglitoServerError
} from '@loglito/loglito';

try {
  const loglito = new Loglito({ apiKey: 'invalid-key' });
  await loglito.log('info', 'Test message', { test: true });
} catch (error) {
  if (error instanceof LoglitoAuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof LoglitoConnectionError) {
    console.error('Connection failed');
  } else if (error instanceof LoglitoServerError) {
    console.error('Server error:', error.statusCode);
  } else if (error instanceof LoglitoError) {
    console.error('General Loglito error');
  }
}
```

## Integration Examples

### Express.js Application

```typescript
import express from 'express';
import { Loglito } from '@loglito/loglito';

const app = express();
const loglito = new Loglito({ apiKey: 'your-api-key' });

app.get('/user/:id', async (req, res) => {
  await loglito.log('info', 'User profile accessed', {
    user_id: parseInt(req.params.id),
    endpoint: '/user',
    method: 'GET',
    ip: req.ip
  });
  
  // ... your application logic ...
});
```

### Next.js Application

```typescript
// pages/api/users.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { Loglito } from '@loglito/loglito';

const loglito = new Loglito({ 
  apiKey: process.env.LOGLITO_API_KEY! 
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  await loglito.log('info', 'API endpoint called', {
    method: req.method,
    url: req.url,
    user_agent: req.headers['user-agent']
  });
  
  // ... your API logic ...
}
```

### React Application

```typescript
// hooks/useLogging.ts
import { useEffect } from 'react';
import { Loglito } from '@loglito/loglito';

const loglito = new Loglito({ 
  apiKey: process.env.REACT_APP_LOGLITO_API_KEY! 
});

export function useLogging() {
  useEffect(() => {
    loglito.log('info', 'Application loaded', {
      user_agent: navigator.userAgent,
      timestamp: Date.now()
    });

    return () => {
      loglito.close();
    };
  }, []);

  return loglito;
}

// In your component
function App() {
  const loglito = useLogging();
  
  const handleUserAction = async (action: string) => {
    await loglito.log('info', 'User action', { action });
  };
  
  // ... rest of component
}
```

### Browser Usage

```html
<!DOCTYPE html>
<html>
<head>
  <title>Loglito Browser Example</title>
</head>
<body>
  <script type="module">
    import { Loglito } from 'https://unpkg.com/@loglito/loglito@latest/dist/index.esm.js';
    
    const loglito = new Loglito({ 
      apiKey: 'your-api-key' 
    });
    
    // Log page view
    await loglito.log('info', 'Page viewed', {
      page: window.location.pathname,
      referrer: document.referrer,
      user_agent: navigator.userAgent
    });
    
    // Clean up on page unload
    window.addEventListener('beforeunload', () => {
      loglito.close();
    });
  </script>
</body>
</html>
```

## Development

### Building

```bash
npm run build
```

### Testing

```bash
npm test
```

### Testing Published Package

To test the published package from npm:

```bash
npm run test:published
```

This script will:
1. Install `@loglito/loglito` from npm in a temporary directory
2. Test all major functionality
3. Clean up afterwards

### Type Checking

```bash
npm run type-check
```

### Linting

```bash
npm run lint
```