houser-js-utils
Version:
A comprehensive collection of TypeScript utility functions for common development tasks including array manipulation, string processing, date handling, random number generation, validation, and much more.
461 lines (460 loc) • 13.5 kB
JavaScript
const LoggingUtils = {
/**
* Default configuration options for logging.
* @default
* ```typescript
* {
* level: "info",
* timestamp: true,
* prefix: "",
* group: false,
* groupCollapsed: false,
* stackTrace: false
* }
* ```
*/
defaultOptions: {
level: "info",
timestamp: true,
prefix: "",
group: false,
groupCollapsed: false,
stackTrace: false
},
/**
* Internal storage for all log entries.
* @default []
*/
logEntries: [],
/**
* Maximum number of log entries to store before removing oldest entries.
* @default 1000
*/
maxLogEntries: 1e3,
/**
* Clears all stored log entries from memory.
* @example
* ```typescript
* // Clear all stored logs
* LoggingUtils.clearLogEntries();
* console.log("Logs cleared");
*
* // Clear logs after exporting
* const logs = LoggingUtils.exportLogEntries();
* LoggingUtils.clearLogEntries();
* ```
*/
clearLogEntries() {
this.logEntries = [];
},
/**
* Logs a debug message with optional metadata.
* @param message - The debug message to log
* @param options - Optional configuration for the log entry
* @example
* ```typescript
* // Simple debug message
* LoggingUtils.debug("Processing started");
*
* // Debug with data and prefix
* LoggingUtils.debug("Data processed", {
* prefix: "DataService",
* data: { count: 100, status: "success" }
* });
*
* // Debug with grouping
* LoggingUtils.debug("Complex operation", {
* group: true,
* groupCollapsed: true,
* data: { steps: ["step1", "step2"] }
* });
* ```
*/
debug(message, options = {}) {
this.log(message, { ...options, level: "debug" });
},
/**
* Logs an error message with optional stack trace and metadata.
* @param message - The error message to log
* @param options - Optional configuration for the log entry
* @example
* ```typescript
* try {
* // ... some code that might throw
* } catch (error) {
* LoggingUtils.error("Failed to process data", {
* data: error,
* prefix: "DataService",
* stackTrace: true
* });
* }
*
* // Error with custom data
* LoggingUtils.error("API request failed", {
* data: {
* status: 500,
* endpoint: "/api/data",
* response: "Internal Server Error"
* }
* });
* ```
*/
error(message, options = {}) {
this.log(message, { ...options, level: "error", stackTrace: true });
},
/**
* Exports all stored log entries as a formatted JSON string.
* @returns A JSON string containing all log entries
* @example
* ```typescript
* // Export logs to file
* const logs = LoggingUtils.exportLogEntries();
* const blob = new Blob([logs], { type: 'application/json' });
* const url = URL.createObjectURL(blob);
*
* // Export logs to server
* const logs = LoggingUtils.exportLogEntries();
* await fetch('/api/logs', {
* method: 'POST',
* body: logs,
* headers: { 'Content-Type': 'application/json' }
* });
* ```
*/
exportLogEntries() {
return JSON.stringify(this.logEntries, null, 2);
},
/**
* Formats a number of bytes into a human-readable string with appropriate unit.
* @param bytes - The number of bytes to format
* @returns A formatted string with appropriate unit (B, KB, MB, GB, TB)
* @example
* ```typescript
* const size = LoggingUtils.formatBytes(1024 * 1024);
* console.log(size); // "1.00 MB"
*
* const smallSize = LoggingUtils.formatBytes(500);
* console.log(smallSize); // "500.00 B"
*
* const largeSize = LoggingUtils.formatBytes(1024 * 1024 * 1024 * 2);
* console.log(largeSize); // "2.00 GB"
* ```
*/
formatBytes(bytes) {
const units = ["B", "KB", "MB", "GB", "TB"];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
},
/**
* Gets a copy of all stored log entries.
* @returns An array of log entries
* @example
* ```typescript
* // Get all logs
* const allLogs = LoggingUtils.getLogEntries();
* console.log(`Total logs: ${allLogs.length}`);
*
* // Filter logs in memory
* const errorLogs = LoggingUtils.getLogEntries()
* .filter(log => log.level === 'error');
* ```
*/
getLogEntries() {
return [...this.logEntries];
},
/**
* Gets log entries filtered by a specific log level.
* @param level - The log level to filter by
* @returns An array of filtered log entries
* @example
* ```typescript
* // Get all error logs
* const errorLogs = LoggingUtils.getLogEntriesByLevel("error");
* console.log(`Error count: ${errorLogs.length}`);
*
* // Get all debug logs
* const debugLogs = LoggingUtils.getLogEntriesByLevel("debug");
* console.log(`Debug count: ${debugLogs.length}`);
* ```
*/
getLogEntriesByLevel(level) {
return this.logEntries.filter((entry) => entry.level === level);
},
/**
* Gets log entries within a specific time range.
* @param startTime - The start time of the range
* @param endTime - The end time of the range
* @returns An array of filtered log entries
* @example
* ```typescript
* // Get logs from today
* const today = new Date();
* const yesterday = new Date(today);
* yesterday.setDate(yesterday.getDate() - 1);
*
* const todayLogs = LoggingUtils.getLogEntriesByTimeRange(yesterday, today);
* console.log(`Logs in last 24 hours: ${todayLogs.length}`);
*
* // Get logs from specific time period
* const startDate = new Date("2024-01-01");
* const endDate = new Date("2024-01-02");
* const periodLogs = LoggingUtils.getLogEntriesByTimeRange(startDate, endDate);
* ```
*/
getLogEntriesByTimeRange(startTime, endTime) {
return this.logEntries.filter(
(entry) => new Date(entry.timestamp) >= startTime && new Date(entry.timestamp) <= endTime
);
},
/**
* Logs an informational message with optional metadata.
* @param message - The info message to log
* @param options - Optional configuration for the log entry
* @example
* ```typescript
* // Simple info message
* LoggingUtils.info("Application started");
*
* // Info with data and prefix
* LoggingUtils.info("User logged in", {
* prefix: "Auth",
* data: { userId: "123", role: "admin" }
* });
*
* // Info with grouping
* LoggingUtils.info("Configuration loaded", {
* group: true,
* data: { settings: { theme: "dark", language: "en" } }
* });
* ```
*/
info(message, options = {}) {
this.log(message, { ...options, level: "info" });
},
/**
* Imports log entries from a JSON string.
* @param json - The JSON string containing log entries
* @throws {Error} If the JSON string is invalid or cannot be parsed
* @example
* ```typescript
* // Import logs from file
* const json = await fetch('/logs.json').then(r => r.text());
* LoggingUtils.importLogEntries(json);
*
* // Import logs from server
* const response = await fetch('/api/logs');
* const json = await response.text();
* LoggingUtils.importLogEntries(json);
* ```
*/
importLogEntries(json) {
try {
const entries = JSON.parse(json);
this.logEntries = entries.slice(-this.maxLogEntries);
} catch (error) {
this.error("Failed to import log entries", { data: error });
}
},
/**
* Logs a message with the specified options.
* @param message - The message to log
* @param options - Configuration options for the log entry
* @example
* ```typescript
* // Custom log with all options
* LoggingUtils.log("Custom message", {
* level: "info",
* prefix: "Custom",
* group: true,
* groupCollapsed: true,
* stackTrace: true,
* data: { custom: "data" }
* });
*
* // Simple log with default options
* LoggingUtils.log("Simple message");
* ```
*/
log(message, options = {}) {
const opts = { ...this.defaultOptions, ...options };
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
const prefix = opts.prefix ? `[${opts.prefix}] ` : "";
const fullMessage = `${prefix}${message}`;
const entry = {
timestamp,
level: opts.level || "info",
message: fullMessage,
data: opts.data
};
if (opts.stackTrace) {
entry.stack = new Error().stack;
}
this.logEntries.push(entry);
if (this.logEntries.length > this.maxLogEntries) {
this.logEntries.shift();
}
if (opts.group) {
if (opts.groupCollapsed) {
console.groupCollapsed(fullMessage);
} else {
console.group(fullMessage);
}
}
switch (opts.level) {
case "debug":
console.debug(fullMessage, opts.data || "");
break;
case "info":
console.info(fullMessage, opts.data || "");
break;
case "warn":
console.warn(fullMessage, opts.data || "");
break;
case "error":
console.error(fullMessage, opts.data || "");
if (entry.stack) {
console.error(entry.stack);
}
break;
}
if (opts.group) {
console.groupEnd();
}
},
/**
* Logs memory usage information if available in the browser.
* @param label - The label for the memory measurement
* @example
* ```typescript
* // Log memory usage
* LoggingUtils.measureMemory("After data load");
* // Output: Memory: After data load { used: "50.2 MB", total: "100.0 MB", limit: "500.0 MB" }
*
* // Track memory usage over time
* setInterval(() => {
* LoggingUtils.measureMemory("Periodic check");
* }, 60000);
* ```
*/
measureMemory(label) {
if (performance.memory) {
const { usedJSHeapSize, totalJSHeapSize, jsHeapSizeLimit } = performance.memory;
this.debug(`Memory: ${label}`, {
data: {
used: this.formatBytes(usedJSHeapSize),
total: this.formatBytes(totalJSHeapSize),
limit: this.formatBytes(jsHeapSizeLimit)
}
});
}
},
/**
* Creates a performance measurement for synchronous operations.
* @param label - The label for the performance measurement
* @returns A function to end the measurement and log the duration
* @example
* ```typescript
* // Measure a synchronous operation
* const endMeasurement = LoggingUtils.measurePerformance("Data processing");
* // ... do some work ...
* endMeasurement();
* // Output: Performance: Data processing { duration: "123.45ms" }
*
* // Measure multiple operations
* const endTotal = LoggingUtils.measurePerformance("Total processing");
*
* const endStep1 = LoggingUtils.measurePerformance("Step 1");
* // ... do step 1 ...
* endStep1();
*
* const endStep2 = LoggingUtils.measurePerformance("Step 2");
* // ... do step 2 ...
* endStep2();
*
* endTotal();
* ```
*/
measurePerformance(label) {
const startTime = performance.now();
return () => {
const endTime = performance.now();
const duration = endTime - startTime;
this.debug(`Performance: ${label}`, {
data: { duration: `${duration.toFixed(2)}ms` }
});
};
},
/**
* Measures the performance of an asynchronous function.
* @param label - The label for the performance measurement
* @param fn - The async function to measure
* @returns A Promise with the function result
* @example
* ```typescript
* // Measure an API call
* const result = await LoggingUtils.measureAsyncPerformance(
* "API call",
* async () => await fetchData()
* );
*
* // Measure multiple async operations
* const results = await Promise.all([
* LoggingUtils.measureAsyncPerformance("API 1", () => fetchData1()),
* LoggingUtils.measureAsyncPerformance("API 2", () => fetchData2())
* ]);
* ```
*/
async measureAsyncPerformance(label, fn) {
const startTime = performance.now();
try {
const result = await fn();
const endTime = performance.now();
const duration = endTime - startTime;
this.debug(`Performance: ${label}`, {
data: { duration: `${duration.toFixed(2)}ms` }
});
return result;
} catch (error) {
const endTime = performance.now();
const duration = endTime - startTime;
this.error(`Performance: ${label}`, {
data: { duration: `${duration.toFixed(2)}ms`, error }
});
throw error;
}
},
/**
* Logs a warning message with optional metadata.
* @param message - The warning message to log
* @param options - Optional configuration for the log entry
* @example
* ```typescript
* // Simple warning
* LoggingUtils.warn("Resource usage high");
*
* // Warning with data and prefix
* LoggingUtils.warn("High memory usage", {
* prefix: "System",
* data: { cpu: "80%", memory: "75%" }
* });
*
* // Warning with grouping
* LoggingUtils.warn("Multiple issues detected", {
* group: true,
* data: { issues: ["CPU", "Memory", "Disk"] }
* });
* ```
*/
warn(message, options = {}) {
this.log(message, { ...options, level: "warn" });
}
};
export {
LoggingUtils
};
//# sourceMappingURL=LoggingUtils.mjs.map