{"_id":"@dooherceg/error-logging-service","name":"@dooherceg/error-logging-service","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@dooherceg/error-logging-service","private":false,"version":"1.0.0","description":"A lightweight, framework-agnostic JavaScript/TypeScript logging library.","homepage":"https://github.com/zmirnes/error-logging-service#readme","bugs":{"url":"https://github.com/zmirnes/error-logging-service/issues"},"repository":{"type":"git","url":"git+https://github.com/zmirnes/error-logging-service.git"},"license":"MIT","author":{"name":"dooherceg"},"main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest","test:run":"vitest run","coverage":"vitest run --coverage"},"devDependencies":{"@vitest/coverage-v8":"^4.0.18","tsup":"^8.5.1","typescript":"^5.9.3","vitest":"^4.0.18"},"gitHead":"29976dd7cb347b1e9006aa9bbd85c9974f9bf153","_id":"@dooherceg/error-logging-service@1.0.0","_nodeVersion":"24.2.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-ykStOOYBI6SH5nfUPRapOMZTBhMUWjTGtwBCudWF7b5DEJ2GI4lmE0bOcU3OU4mWRC4zBGLKKunY0/MEiRiJOg==","shasum":"0ab0c842c44559e645ffb699491a2a48f3497442","tarball":"https://registry.npmjs.org/@dooherceg/error-logging-service/-/error-logging-service-1.0.0.tgz","fileCount":9,"unpackedSize":81808,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC+o5zQn5q+rjcJbO9k2ZeYDZ+9VADa8FWtsyhCUyWf5AiBOH44g2q3lhl2sp25Zgw/I3yARVR9ZvPNSZMLZJxWMDg=="}]},"_npmUser":{"name":"dooherceg","email":"rti@dooherceg.ba"},"directories":{},"maintainers":[{"name":"dooherceg","email":"rti@dooherceg.ba"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/error-logging-service_1.0.0_1771835741548_0.35225633218767527"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-23T08:35:41.449Z","1.0.0":"2026-02-23T08:35:41.695Z","modified":"2026-02-23T08:35:41.926Z"},"maintainers":[{"name":"dooherceg","email":"rti@dooherceg.ba"}],"description":"A lightweight, framework-agnostic JavaScript/TypeScript logging library.","homepage":"https://github.com/zmirnes/error-logging-service#readme","repository":{"type":"git","url":"git+https://github.com/zmirnes/error-logging-service.git"},"author":{"name":"dooherceg"},"bugs":{"url":"https://github.com/zmirnes/error-logging-service/issues"},"license":"MIT","readme":"# error-logging-service\r\n\r\nA lightweight, framework-agnostic JavaScript/TypeScript logging library built around clean architecture principles.\r\nInitialize once, use anywhere — with full control over how logs are transported and enriched.\r\n\r\n---\r\n\r\n## Features\r\n\r\n- **Framework agnostic** — works in React, Vue, Angular, Node.js, or any JS environment\r\n- **Transport pattern** — define exactly how and where logs are sent\r\n- **Plugin pipeline** — enrich, filter, or transform log entries before they are sent\r\n- **Singleton** — initialize once at app startup, access anywhere\r\n- **TypeScript first** — fully typed with strict mode support\r\n- **Minimal footprint** — zero runtime dependencies\r\n\r\n---\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install error-logging-service\r\n```\r\n\r\n---\r\n\r\n## Quick Start\r\n\r\n```typescript\r\nimport {Logger, LogLevel, ConsoleTransport} from 'error-logging-service'\r\n\r\n// Initialize once at app startup\r\nLogger.init({\r\n    transports: [new ConsoleTransport()],\r\n})\r\n\r\n// Use anywhere in your application\r\nconst logger = Logger.getInstance()\r\n\r\nlogger.debug('App started')\r\nlogger.info('User logged in', {userId: '123'})\r\nlogger.warn('Deprecated API called')\r\nlogger.error('Payment failed', new Error('Card declined'), {orderId: 'ord-456'})\r\n```\r\n\r\n---\r\n\r\n## Log Levels\r\n\r\n| Level   | Value | Use case                                |\r\n|---------|-------|-----------------------------------------|\r\n| `DEBUG` | 0     | Detailed information during development |\r\n| `INFO`  | 1     | General application events              |\r\n| `WARN`  | 2     | Something unexpected, but not breaking  |\r\n| `ERROR` | 3     | A failure that affects functionality    |\r\n\r\n---\r\n\r\n## Transports\r\n\r\nA transport defines **how** a log entry is sent. Implement the `Transport` interface to create your own.\r\n\r\n### Built-in: ConsoleTransport\r\n\r\n```typescript\r\nimport {ConsoleTransport} from 'error-logging-service'\r\n\r\nnew ConsoleTransport({\r\n    formatter: (entry) => `[${entry.level}] ${entry.message}` // custom format\r\n})\r\n```\r\n\r\n### Custom Transport\r\n\r\nImplement the `Transport` interface to send logs anywhere — your own API, Sentry, Datadog, or any other service.\r\n\r\n```typescript\r\nimport {Transport, LogEntry} from 'error-logging-service'\r\n\r\nclass HttpTransport implements Transport {\r\n    readonly name = 'http'\r\n\r\n    async send(entry: LogEntry): Promise<void> {\r\n        await fetch('/api/logs', {\r\n            method: 'POST',\r\n            headers: {\r\n                'Content-Type': 'application/json',\r\n                'Authorization': `Bearer ${your_token}`\r\n            },\r\n            body: JSON.stringify({\r\n                ...entry,\r\n                // Error objects are not JSON-serializable by default\r\n                // serialize them manually\r\n                error: entry.error\r\n                    ? {message: entry.error.message, stack: entry.error.stack}\r\n                    : undefined,\r\n            }),\r\n        })\r\n    }\r\n}\r\n\r\nLogger.init({\r\n    transports: [new HttpTransport()]\r\n})\r\n```\r\n\r\n### Multiple Transports\r\n\r\nAll registered transports receive every log entry in parallel. If one fails, the others continue.\r\n\r\n```typescript\r\nLogger.init({\r\n    transports: [\r\n        new ConsoleTransport(),\r\n        new HttpTransport(),\r\n    ]\r\n})\r\n```\r\n\r\n---\r\n\r\n## Plugins\r\n\r\nPlugins run before transports — they form a **pipeline** that processes each log entry in order.\r\n\r\nA plugin is a function that receives a `LogEntry` and returns a `LogEntry` or `null`. Returning `null` drops the entry —\r\nit will not be sent to any transport.\r\n\r\n### Enrichment — add data to every log\r\n\r\n```typescript\r\nimport {Plugin} from 'error-logging-service'\r\n\r\nconst withUserContext: Plugin = (entry) => ({\r\n    ...entry,\r\n    context: {\r\n        ...entry.context,\r\n        userId: getCurrentUser().id,\r\n        sessionId: getSessionId(),\r\n    }\r\n})\r\n\r\nconst withAppMeta: Plugin = (entry) => ({\r\n    ...entry,\r\n    context: {\r\n        ...entry.context,\r\n        appVersion: '2.4.1',\r\n        environment: process.env.NODE_ENV,\r\n    }\r\n})\r\n```\r\n\r\n### Filtering — drop entries conditionally\r\n\r\n```typescript\r\n// Drop all health check logs\r\nconst filterHealthChecks: Plugin = (entry) => {\r\n    if (entry.message.includes('healthcheck')) return null\r\n    return entry\r\n}\r\n\r\n// Sample — only send 10% of DEBUG logs in production\r\nconst sampleDebug: Plugin = (entry) => {\r\n    if (entry.level === LogLevel.DEBUG && Math.random() > 0.1) return null\r\n    return entry\r\n}\r\n```\r\n\r\n### Redaction — remove sensitive data\r\n\r\n```typescript\r\nconst redactSensitiveData: Plugin = (entry) => ({\r\n    ...entry,\r\n    message: entry.message.replace(/password=\\S+/gi, 'password=[REDACTED]')\r\n})\r\n```\r\n\r\n### Error serialization — fix empty error objects in JSON\r\n\r\n```typescript\r\nconst serializeError: Plugin = (entry) => {\r\n    if (!entry.error) return entry\r\n\r\n    return {\r\n        ...entry,\r\n        error: {\r\n            message: entry.error.message,\r\n            name: entry.error.name,\r\n            stack: entry.error.stack,\r\n        } as unknown as Error\r\n    }\r\n}\r\n```\r\n\r\n### Registering plugins\r\n\r\n```typescript\r\nLogger.init({\r\n    plugins: [\r\n        withUserContext,\r\n        withAppMeta,\r\n        filterHealthChecks,\r\n        redactSensitiveData,\r\n        serializeError,\r\n    ],\r\n    transports: [new HttpTransport()]\r\n})\r\n```\r\n\r\nPlugins can also be added after initialization:\r\n\r\n```typescript\r\nLogger.getInstance().addPlugin(myPlugin)\r\n```\r\n\r\n---\r\n\r\n## React Integration\r\n\r\n### Initialize before the React tree mounts\r\n\r\n```tsx\r\n// main.tsx\r\nimport {Logger, ConsoleTransport} from 'error-logging-service'\r\n\r\nLogger.init({\r\n    transports: [new ConsoleTransport()],\r\n})\r\n\r\ncreateRoot(document.getElementById('root')!).render(<App/>)\r\n```\r\n\r\n### useLogger hook\r\n\r\n```tsx\r\n// hooks/useLogger.ts\r\nimport {Logger} from 'error-logging-service'\r\n\r\nexport function useLogger() {\r\n    return Logger.getInstance()\r\n}\r\n\r\n// In any component\r\nfunction PaymentForm() {\r\n    const logger = useLogger()\r\n\r\n    const handleSubmit = async () => {\r\n        try {\r\n            await processPayment()\r\n        } catch (error) {\r\n            logger.error('Payment failed', error as Error, {component: 'PaymentForm'})\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n### ErrorBoundary integration\r\n\r\nSince `ErrorBoundary` must be a class component, use `Logger.getInstance()` directly:\r\n\r\n```tsx\r\nimport {Logger} from 'error-logging-service'\r\nimport {Component, ReactNode} from 'react'\r\n\r\nclass ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> {\r\n    constructor(props: { children: ReactNode }) {\r\n        super(props)\r\n        this.state = {hasError: false}\r\n    }\r\n\r\n    static getDerivedStateFromError() {\r\n        return {hasError: true}\r\n    }\r\n\r\n    componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\r\n        Logger.getInstance().error(\r\n            'Uncaught error caught by ErrorBoundary',\r\n            error,\r\n            {componentStack: errorInfo.componentStack}\r\n        )\r\n    }\r\n\r\n    render() {\r\n        if (this.state.hasError) return <div>Something went wrong.</div>\r\n        return this.props.children\r\n    }\r\n}\r\n```\r\n\r\n---\r\n\r\n## API Reference\r\n\r\n### `Logger.init(config)`\r\n\r\nInitializes the logger. Must be called once before any other method.\r\n\r\n| Option       | Type          | Default | Description        |\r\n|--------------|---------------|---------|--------------------|\r\n| `transports` | `Transport[]` | `[]`    | List of transports |\r\n| `plugins`    | `Plugin[]`    | `[]`    | List of plugins    |\r\n\r\n### `Logger.getInstance()`\r\n\r\nReturns the existing logger instance. Throws if `init` has not been called.\r\n\r\n### `Logger.reset()`\r\n\r\nResets the singleton. **For use in tests only.**\r\n\r\n### `logger.debug / info / warn / error `\r\n\r\n```\r\nlogger.debug(message: string, context?: Record<string, unknown>): void\r\nlogger.info(message: string, context?: Record<string, unknown>): void\r\nlogger.warn(message: string, context?: Record<string, unknown>): void\r\nlogger.error(message: string, error?: Error, context?: Record<string, unknown>): void\r\n```\r\n\r\n### `logger.addTransport(transport)`\r\n\r\nRegisters a transport after initialization. Throws if a transport with the same name is already registered.\r\n\r\n### `logger.removeTransport(name)`\r\n\r\nRemoves a transport by name.\r\n\r\n### `logger.addPlugin(plugin)`\r\n\r\nAdds a plugin to the end of the pipeline after initialization.\r\n\r\n---\r\n\r\n## Project Structure\r\n\r\n```\r\nsrc/\r\n├── core/\r\n│   ├── Logger.ts           # Singleton logger class\r\n│   ├── LogEntry.ts         # LogEntry model and factory\r\n│   └── LogLevel.ts         # LogLevel enum\r\n├── transports/\r\n│   ├── Transport.ts        # Transport interface (Strategy pattern)\r\n│   └── ConsoleTransport.ts # Built-in console transport\r\n├── plugins/\r\n│   └── Plugin.ts           # Plugin type definition\r\n└── index.ts                # Public API\r\n```\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT","readmeFilename":"README.md","_rev":"1-916ae97f3e0be557906d4a4336e089e3"}