Log Management
1 Initialize Log
Initialize the host log. Provide the function to print log levels and proxy host log printing.
1.1 Interface Prototype
hostHandle.initLog(level, printer)
1.2 Parameter Description
| parameter | Data Type | Required | Attribute Description |
|---|---|---|---|
level | String | Yes | Log Priority String |
printer | Object | No | Log Printer, used for customizing log output |
1.3 LogLevel Log Level
The following string values can be used as log levels:
| Level String | Description |
|---|---|
'debug' | Debug Information |
'info' | General Information |
'warning' or 'warn' | Warning Message |
'error' | Error Message |
'fault' | Severe Error |
1.4 Log Printer Interface
The Log Printer is an object that needs to implement the printLog method:
{
printLog: (level, message) => void
}
Parameter Description
| parameter | Data Type | Description |
|---|---|---|
level | String | Log level string (e.g., 'debug', 'info', 'error', etc.) |
message | String | Log Message |
1.5 Code Example
1.5.1 Basic Usage
const { TJHostHandle } = require('webglhost-runtime-pc');
// Initialize SDK
TJHostHandle.initialize('sdk-key', 'sdk-secret', (hostHandle, error) => {
if (error) {
console.error('SDK initialization failed:', error);
return;
}
// Initialize log with DEBUG level, using default console printer
hostHandle.initLog('debug');
console.log('Log initialized with DEBUG level');
});
1.5.2 Use Custom Log Printer
const { TJHostHandle } = require('webglhost-runtime-pc');
// Custom log printer
class CustomLogPrinter {
printLog(level, message) {
const timestamp = new Date().toISOString();
const formattedMessage = `[${timestamp}] [${level}] ${message}`;
// Output to console with colors
switch (level.toLowerCase()) {
case 'debug':
console.log('\x1b[36m%s\x1b[0m', formattedMessage); // Cyan
break;
case 'info':
console.log('\x1b[32m%s\x1b[0m', formattedMessage); // Green
break;
case 'warning':
case 'warn':
console.log('\x1b[33m%s\x1b[0m', formattedMessage); // Yellow
break;
case 'error':
case 'fault':
console.log('\x1b[31m%s\x1b[0m', formattedMessage); // Red
break;
default:
console.log(formattedMessage);
}
}
}
// Initialize with custom printer
TJHostHandle.initialize('sdk-key', 'sdk-secret', (hostHandle, error) => {
if (error) return;
const printer = new CustomLogPrinter();
hostHandle.initLog('info', printer); // INFO level with custom printer
});
1.5.3 Log Writing to File
const fs = require('fs');
const path = require('path');
const os = require('os');
class FileLogPrinter {
constructor(logFilePath) {
this.logFilePath = logFilePath;
this.ensureLogFile();
}
ensureLogFile() {
const dir = path.dirname(this.logFilePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
printLog(level, message) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] [${level}] ${message}\n`;
// Write to console
console.log(logEntry.trim());
// Write to file
fs.appendFileSync(this.logFilePath, logEntry, 'utf-8');
}
}
// Usage
const logPath = path.join(os.homedir(), '.webglhost', 'logs', 'game.log');
const filePrinter = new FileLogPrinter(logPath);
hostHandle.initLog('debug', filePrinter); // DEBUG level, log to file
1.5.4 Multi-target Log Output
class MultiTargetLogPrinter {
constructor(targets) {
this.targets = targets; // Array of log printers
}
printLog(level, message) {
// Send log to all targets
for (const target of this.targets) {
try {
target.printLog(level, message);
} catch (error) {
console.error('Error in log target:', error);
}
}
}
}
// Create multiple log targets
const consolePrinter = new CustomLogPrinter();
const filePrinter = new FileLogPrinter('./logs/game.log');
// Combine them
const multiPrinter = new MultiTargetLogPrinter([consolePrinter, filePrinter]);
hostHandle.initLog('info', multiPrinter); // INFO level, log to console and file
2 Complete Example
const { TJHostHandle } = require('webglhost-runtime-pc');
const fs = require('fs');
const path = require('path');
const os = require('os');
class AdvancedLogPrinter {
constructor(options = {}) {
this.logToConsole = options.logToConsole !== false;
this.logToFile = options.logToFile !== false;
this.logFilePath = options.logFilePath || this.getDefaultLogPath();
this.maxFileSize = options.maxFileSize || 10 * 1024 * 1024; // 10MB
this.logFilter = options.logFilter || ((level) => true);
if (this.logToFile) {
this.ensureLogDirectory();
}
}
getDefaultLogPath() {
const logsDir = path.join(os.homedir(), '.webglhost', 'logs');
const timestamp = new Date().toISOString().replace(/:/g, '-').split('.')[0];
return path.join(logsDir, `game-${timestamp}.log`);
}
ensureLogDirectory() {
const dir = path.dirname(this.logFilePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
printLog(level, message) {
// Apply filter
if (!this.logFilter(level)) {
return;
}
const timestamp = new Date().toISOString();
const levelName = this.getLevelName(level);
const formattedMessage = `[${timestamp}] [${levelName}] ${message}`;
// Console output
if (this.logToConsole) {
this.printToConsole(level, formattedMessage);
}
// File output
if (this.logToFile) {
this.printToFile(formattedMessage);
}
}
printToConsole(level, message) {
const colors = {
'debug': '\x1b[36m', // Cyan
'info': '\x1b[32m', // Green
'warning': '\x1b[33m', // Yellow
'warn': '\x1b[33m', // Yellow
'error': '\x1b[31m', // Red
'fault': '\x1b[35m' // Magenta
};
const resetColor = '\x1b[0m';
const color = colors[level.toLowerCase()] || '';
console.log(`${color}${message}${resetColor}`);
}
printToFile(message) {
try {
// Check file size and rotate if necessary
if (fs.existsSync(this.logFilePath)) {
const stats = fs.statSync(this.logFilePath);
if (stats.size > this.maxFileSize) {
this.rotateLogFile();
}
}
// Append to log file
fs.appendFileSync(this.logFilePath, message + '\n', 'utf-8');
} catch (error) {
console.error('Failed to write to log file:', error);
}
}
rotateLogFile() {
const ext = path.extname(this.logFilePath);
const base = this.logFilePath.slice(0, -ext.length);
const timestamp = new Date().toISOString().replace(/:/g, '-').split('.')[0];
const newPath = `${base}-${timestamp}${ext}`;
fs.renameSync(this.logFilePath, newPath);
console.log(`Log file rotated: ${newPath}`);
}
}
// Usage example
class GameLogger {
constructor() {
this.hostHandle = null;
this.logLevel = 'info';
}
async initialize(sdkKey, sdkSecret) {
return new Promise((resolve, reject) => {
TJHostHandle.initialize(sdkKey, sdkSecret, (hostHandle, error) => {
if (error) {
reject(error);
return;
}
this.hostHandle = hostHandle;
this.setupLogger();
resolve();
});
});
}
setupLogger() {
// Determine log level based on environment
const isDevelopment = process.env.NODE_ENV === 'development';
this.logLevel = isDevelopment ? 'debug' : 'info';
// Create advanced log printer
const printer = new AdvancedLogPrinter({
logToConsole: true,
logToFile: true,
logFilePath: path.join(os.homedir(), '.webglhost', 'logs', 'game.log'),
maxFileSize: 10 * 1024 * 1024, // 10MB
logFilter: (level) => {
// Only log messages at or above current log level
const levelOrder = ['debug', 'info', 'warning', 'error', 'fault'];
const currentIndex = levelOrder.indexOf(this.logLevel.toLowerCase());
const messageIndex = levelOrder.indexOf(level.toLowerCase());
return messageIndex >= currentIndex;
}
});
// Initialize log system
this.hostHandle.initLog(this.logLevel, printer);
console.log(`Logger initialized with level: ${this.logLevel}`);
}
setLogLevel(level) {
this.logLevel = level;
this.setupLogger(); // Re-initialize with new level
}
}
// Main usage
async function main() {
const logger = new GameLogger();
try {
await logger.initialize('sdk-key', 'sdk-secret');
// Change log level at runtime (if needed)
if (process.argv.includes('--debug')) {
logger.setLogLevel('debug');
}
console.log('Application started with logging enabled');
} catch (error) {
console.error('Failed to initialize logger:', error);
}
}
main();
3 Best Practices
-
The Development Environment uses DEBUG level
const level = process.env.NODE_ENV === 'development' ? 'debug' : 'info';hostHandle.initLog(level, printer); -
Use INFO or WARNING level in the production environment
const level = process.env.NODE_ENV === 'production' ? 'warning' : 'debug';
-
Implement log rotation
-
Automatically create a new file when the log file exceeds a certain size
-
Retain the last N log files
-
-
Log File Location
-
macOS:
~/Library/Logs/WebGLHost/ -
Windows:
%APPDATA%\WebGLHost\Logs\ -
Linux:
~/.local/share/WebGLHost/logs/
-
-
Performance Considerations
-
Avoid printing excessive logs during high-frequency operations
-
File I/O uses asynchronous operations (on non-Critical Path)
-
Consider using a log buffering mechanism
-
-
Log Privacy
-
Do not record sensitive information (passwords, tokens, etc.)
-
Desensitize user data
-