Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions lib/Logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const fs = require('fs');
const path = require('path');

class Logger {
constructor(options = {}) {
this.logLevel = options.logLevel || 'info';
this.logFile = options.logFile || path.join(process.cwd(), 'osmosis.log');
this.logLevels = ['error', 'warn', 'info', 'debug'];
}

_shouldLog(level) {
return this.logLevels.indexOf(level) <= this.logLevels.indexOf(this.logLevel);
}

_log(level, message, metadata = {}) {
if (!this._shouldLog(level)) return;

const timestamp = new Date().toISOString();
const logEntry = JSON.stringify({
timestamp,
level,
message,
...metadata
}) + '\n';

// Console output
switch(level) {
case 'error':
console.error(logEntry);
break;
case 'warn':
console.warn(logEntry);
break;
case 'info':
console.info(logEntry);
break;
case 'debug':
console.debug(logEntry);
break;
}

// File logging
try {
fs.appendFileSync(this.logFile, logEntry);
} catch (err) {
console.error('Failed to write to log file:', err);
}
}

error(message, metadata = {}) {
this._log('error', message, metadata);
}

warn(message, metadata = {}) {
this._log('warn', message, metadata);
}

info(message, metadata = {}) {
this._log('info', message, metadata);
}

debug(message, metadata = {}) {
this._log('debug', message, metadata);
}
}

module.exports = Logger;
67 changes: 67 additions & 0 deletions test/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const Logger = require('../lib/Logger');

describe('Logger', () => {
const logFile = path.join(process.cwd(), 'test-osmosis.log');

afterEach(() => {
// Clean up log file after each test
try {
fs.unlinkSync(logFile);
} catch (err) {
// Ignore if file doesn't exist
}
});

it('should create a log file when logging', () => {
const logger = new Logger({ logFile });
logger.info('Test log message');

assert(fs.existsSync(logFile), 'Log file was not created');
});

it('should log messages at the correct log level', () => {
const consoleLog = console.log;
const consoleError = console.error;
let loggedMessages = [];

// Mock console methods
console.log = console.error = (msg) => {
loggedMessages.push(msg);
};

const logger = new Logger({
logFile,
logLevel: 'warn'
});

logger.debug('Debug message');
logger.info('Info message');
logger.warn('Warning message');
logger.error('Error message');

console.log = consoleLog;
console.error = consoleError;

const logContent = fs.readFileSync(logFile, 'utf-8');

assert(logContent.includes('Warning message'), 'Warning message should be logged');
assert(logContent.includes('Error message'), 'Error message should be logged');
assert(!logContent.includes('Debug message'), 'Debug message should not be logged');
assert(!logContent.includes('Info message'), 'Info message should not be logged');
});

it('should include metadata in log entries', () => {
const logger = new Logger({ logFile });
logger.info('Test with metadata', { url: 'https://example.com', status: 200 });

const logContent = fs.readFileSync(logFile, 'utf-8');
const logEntry = JSON.parse(logContent.trim());

assert.strictEqual(logEntry.message, 'Test with metadata');
assert.strictEqual(logEntry.url, 'https://example.com');
assert.strictEqual(logEntry.status, 200);
});
});
67 changes: 67 additions & 0 deletions test/logger.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { describe, it, expect, afterEach } from 'vitest';
import fs from 'fs';
import path from 'path';
import Logger from '../lib/Logger.js';

describe('Logger', () => {
const logFile = path.join(process.cwd(), 'test-osmosis.log');

afterEach(() => {
// Clean up log file after each test
try {
fs.unlinkSync(logFile);
} catch (err) {
// Ignore if file doesn't exist
}
});

it('should create a log file when logging', () => {
const logger = new Logger({ logFile });
logger.info('Test log message');

expect(fs.existsSync(logFile)).toBe(true);
});

it('should log messages at the correct log level', () => {
const consoleLog = console.log;
const consoleError = console.error;
let loggedMessages = [];

// Mock console methods
console.log = console.error = (msg) => {
loggedMessages.push(msg);
};

const logger = new Logger({
logFile,
logLevel: 'warn'
});

logger.debug('Debug message');
logger.info('Info message');
logger.warn('Warning message');
logger.error('Error message');

console.log = consoleLog;
console.error = consoleError;

const logContent = fs.readFileSync(logFile, 'utf-8');

expect(logContent).toContain('Warning message');
expect(logContent).toContain('Error message');
expect(logContent).not.toContain('Debug message');
expect(logContent).not.toContain('Info message');
});

it('should include metadata in log entries', () => {
const logger = new Logger({ logFile });
logger.info('Test with metadata', { url: 'https://example.com', status: 200 });

const logContent = fs.readFileSync(logFile, 'utf-8');
const logEntry = JSON.parse(logContent.trim());

expect(logEntry.message).toBe('Test with metadata');
expect(logEntry.url).toBe('https://example.com');
expect(logEntry.status).toBe(200);
});
});