Initial commit
This commit is contained in:
97
.gitignore
vendored
Normal file
97
.gitignore
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/macos,windows,linux,visualstudiocode
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,linux,visualstudiocode
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/macos,windows,linux,visualstudiocode
|
||||
4
index.ts
Normal file
4
index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './logger';
|
||||
export { LoggerComponent, LogLevel, getLogger, logger } from './logger';
|
||||
export const version = '1.0.0';
|
||||
export const ior = 'com.metatrom.examples.logger@1.0.0';
|
||||
38
logger.d.ts
vendored
Normal file
38
logger.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
declare module 'ior:esm:com.metatrom.examples.logger@1.0.0' {
|
||||
export enum LogLevel {
|
||||
TRACE = 0,
|
||||
DEBUG = 1,
|
||||
INFO = 2,
|
||||
WARN = 3,
|
||||
ERROR = 4,
|
||||
FATAL = 5,
|
||||
}
|
||||
|
||||
export interface ILoggerComponent {
|
||||
init(): Promise<void>;
|
||||
setLevel(level: LogLevel): void;
|
||||
trace(message: string, ...args: unknown[]): void;
|
||||
debug(message: string, ...args: unknown[]): void;
|
||||
info(message: string, ...args: unknown[]): void;
|
||||
warn(message: string, ...args: unknown[]): void;
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
fatal(message: string, ...args: unknown[]): void;
|
||||
child(context: string): ILoggerComponent;
|
||||
}
|
||||
|
||||
export class LoggerComponent implements ILoggerComponent {
|
||||
constructor(context?: string);
|
||||
init(): Promise<void>;
|
||||
setLevel(level: LogLevel): void;
|
||||
trace(message: string, ...args: unknown[]): void;
|
||||
debug(message: string, ...args: unknown[]): void;
|
||||
info(message: string, ...args: unknown[]): void;
|
||||
warn(message: string, ...args: unknown[]): void;
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
fatal(message: string, ...args: unknown[]): void;
|
||||
child(context: string): ILoggerComponent;
|
||||
}
|
||||
|
||||
export function getLogger(context?: string): ILoggerComponent;
|
||||
export const logger: LoggerComponent;
|
||||
}
|
||||
190
logger.ts
Normal file
190
logger.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
// Define types locally to avoid circular dependency
|
||||
export enum LogLevel {
|
||||
TRACE = 0,
|
||||
DEBUG = 1,
|
||||
INFO = 2,
|
||||
WARN = 3,
|
||||
ERROR = 4,
|
||||
FATAL = 5,
|
||||
}
|
||||
|
||||
export interface ILoggerComponent {
|
||||
init(): Promise<void>;
|
||||
setLevel(level: LogLevel): void;
|
||||
trace(message: string, ...args: unknown[]): void;
|
||||
debug(message: string, ...args: unknown[]): void;
|
||||
info(message: string, ...args: unknown[]): void;
|
||||
warn(message: string, ...args: unknown[]): void;
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
fatal(message: string, ...args: unknown[]): void;
|
||||
child(context: string): ILoggerComponent;
|
||||
}
|
||||
|
||||
// ANSI color codes for terminal output
|
||||
const COLORS = {
|
||||
RESET: '\x1b[0m',
|
||||
BRIGHT: '\x1b[1m',
|
||||
DIM: '\x1b[2m',
|
||||
RED: '\x1b[31m',
|
||||
GREEN: '\x1b[32m',
|
||||
YELLOW: '\x1b[33m',
|
||||
BLUE: '\x1b[34m',
|
||||
MAGENTA: '\x1b[35m',
|
||||
CYAN: '\x1b[36m',
|
||||
WHITE: '\x1b[37m',
|
||||
GRAY: '\x1b[90m',
|
||||
};
|
||||
|
||||
const LEVEL_COLORS = {
|
||||
[LogLevel.TRACE]: COLORS.GRAY,
|
||||
[LogLevel.DEBUG]: COLORS.CYAN,
|
||||
[LogLevel.INFO]: COLORS.GREEN,
|
||||
[LogLevel.WARN]: COLORS.YELLOW,
|
||||
[LogLevel.ERROR]: COLORS.RED,
|
||||
[LogLevel.FATAL]: COLORS.BRIGHT + COLORS.RED,
|
||||
};
|
||||
|
||||
const LEVEL_NAMES = {
|
||||
[LogLevel.TRACE]: 'TRACE',
|
||||
[LogLevel.DEBUG]: 'DEBUG',
|
||||
[LogLevel.INFO]: 'INFO ',
|
||||
[LogLevel.WARN]: 'WARN ',
|
||||
[LogLevel.ERROR]: 'ERROR',
|
||||
[LogLevel.FATAL]: 'FATAL',
|
||||
};
|
||||
|
||||
export class LoggerComponent implements ILoggerComponent {
|
||||
private level: LogLevel;
|
||||
private context: string;
|
||||
private static globalLevel: LogLevel = LogLevel.INFO;
|
||||
|
||||
constructor(context = 'main') {
|
||||
this.context = context;
|
||||
this.level = LoggerComponent.globalLevel;
|
||||
|
||||
// Check environment variable for log level
|
||||
const envLevel = process.env.LOG_LEVEL?.toUpperCase();
|
||||
if (envLevel && LogLevel[envLevel as keyof typeof LogLevel] !== undefined) {
|
||||
this.level = LogLevel[envLevel as keyof typeof LogLevel];
|
||||
LoggerComponent.globalLevel = this.level;
|
||||
} else if (process.env.DEBUG === 'true') {
|
||||
this.level = LogLevel.DEBUG;
|
||||
LoggerComponent.globalLevel = LogLevel.DEBUG;
|
||||
}
|
||||
}
|
||||
|
||||
async init(): Promise<void> {
|
||||
this.info(`Logger initialized for context: ${this.context}`);
|
||||
}
|
||||
|
||||
setLevel(level: LogLevel): void {
|
||||
this.level = level;
|
||||
LoggerComponent.globalLevel = level;
|
||||
}
|
||||
|
||||
private formatMessage(
|
||||
level: LogLevel,
|
||||
message: string,
|
||||
args: unknown[],
|
||||
): string {
|
||||
const timestamp = new Date().toISOString();
|
||||
const levelColor = LEVEL_COLORS[level];
|
||||
const levelName = LEVEL_NAMES[level];
|
||||
|
||||
// Format the main message
|
||||
let formattedMessage = message;
|
||||
if (args.length > 0) {
|
||||
// Handle object arguments
|
||||
const argStrings = args.map((arg) => {
|
||||
// Special handling for Error objects
|
||||
if (arg instanceof Error) {
|
||||
return `${arg.name}: ${arg.message}${arg.stack ? '\n' + arg.stack : ''}`;
|
||||
}
|
||||
if (typeof arg === 'object' && arg !== null) {
|
||||
try {
|
||||
// Check if it's an empty object
|
||||
const str = JSON.stringify(arg, null, 2);
|
||||
if (str === '{}' && Object.getOwnPropertyNames(arg).length > 0) {
|
||||
// Object has non-enumerable properties, try to get more info
|
||||
return `${arg.constructor.name}: ${String(arg)}`;
|
||||
}
|
||||
return str;
|
||||
} catch {
|
||||
return String(arg);
|
||||
}
|
||||
}
|
||||
return String(arg);
|
||||
});
|
||||
formattedMessage = `${message} ${argStrings.join(' ')}`;
|
||||
}
|
||||
|
||||
// Build the log line with colors
|
||||
return `${COLORS.DIM}[${timestamp}]${COLORS.RESET} ${levelColor}[${levelName}]${COLORS.RESET} ${COLORS.BRIGHT}[${this.context}]${COLORS.RESET} ${formattedMessage}`;
|
||||
}
|
||||
|
||||
private log(level: LogLevel, message: string, args: unknown[]): void {
|
||||
if (level < this.level) return;
|
||||
|
||||
const formattedMessage = this.formatMessage(level, message, args);
|
||||
|
||||
switch (level) {
|
||||
case LogLevel.TRACE:
|
||||
case LogLevel.DEBUG:
|
||||
console.log(formattedMessage);
|
||||
break;
|
||||
case LogLevel.INFO:
|
||||
console.log(formattedMessage);
|
||||
break;
|
||||
case LogLevel.WARN:
|
||||
console.warn(formattedMessage);
|
||||
break;
|
||||
case LogLevel.ERROR:
|
||||
case LogLevel.FATAL:
|
||||
console.error(formattedMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
trace(message: string, ...args: unknown[]): void {
|
||||
this.log(LogLevel.TRACE, message, args);
|
||||
}
|
||||
|
||||
debug(message: string, ...args: unknown[]): void {
|
||||
this.log(LogLevel.DEBUG, message, args);
|
||||
}
|
||||
|
||||
info(message: string, ...args: unknown[]): void {
|
||||
this.log(LogLevel.INFO, message, args);
|
||||
}
|
||||
|
||||
warn(message: string, ...args: unknown[]): void {
|
||||
this.log(LogLevel.WARN, message, args);
|
||||
}
|
||||
|
||||
error(message: string, ...args: unknown[]): void {
|
||||
this.log(LogLevel.ERROR, message, args);
|
||||
}
|
||||
|
||||
fatal(message: string, ...args: unknown[]): void {
|
||||
this.log(LogLevel.FATAL, message, args);
|
||||
}
|
||||
|
||||
child(context: string): ILoggerComponent {
|
||||
const childLogger = new LoggerComponent(`${this.context}:${context}`);
|
||||
childLogger.level = this.level;
|
||||
return childLogger;
|
||||
}
|
||||
}
|
||||
|
||||
// Export a singleton instance for convenience
|
||||
let defaultLogger: LoggerComponent | null = null;
|
||||
|
||||
export function getLogger(context = 'main'): ILoggerComponent {
|
||||
if (!defaultLogger) {
|
||||
defaultLogger = new LoggerComponent(context);
|
||||
}
|
||||
return defaultLogger;
|
||||
}
|
||||
|
||||
// Export default instance
|
||||
export const logger = new LoggerComponent('main');
|
||||
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "@metatrom/logger",
|
||||
"version": "1.0.0",
|
||||
"main": "logger.ts",
|
||||
"type": "module",
|
||||
"metatrom": {
|
||||
"ior": "com.metatrom.examples.logger@1.0.0",
|
||||
"capabilities": {
|
||||
"p2p": false,
|
||||
"contracts": false,
|
||||
"viewer": true,
|
||||
"sync": false
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user