前言:
electron 终端打印中文乱码,但有些同事终端 编码 是 urf8 , 有些是 gbk,所以添加编码检测,保证所有人终端打印中文不乱码
采用了 winston
日志库
使用 iconv-lite
库来进行字符编码转换。
1. 关键逻辑 (可以 cmd/powerShell 输入 chcp 查看当前编码集)
常见 Windows 代码页:
437 → 美国英语(OEM US)
936 → 简体中文(GBK/GB2312)
950 → 繁体中文(Big5)
65001 → UTF-8
判断代码:
const output = execSync('chcp', { encoding: 'utf8' }).toLowerCase().trim();
if (output.includes('65001')) {
return 'utf8';
}
if (output.includes('936')) {
return 'gbk';
}
2.核心片段
/* eslint-disable @typescript-eslint/no-explicit-any */
import winston from 'winston';
import { format, TransformableInfo } from 'logform';
import DailyRotateFile from 'winston-daily-rotate-file';
import * as Transport from 'winston-transport';
import iconv from 'iconv-lite';
import { safeFormat } from 'shared/static.tools';
import { LogLevel } from 'shared/types';
import { DEFULT_LABEL } from './type';
import { execSync } from 'child_process';
/**
* 自动探测当前终端编码
*/
type SupportedEncoding = 'utf8' | 'gbk';
function detectEncoding(): SupportedEncoding {
try {
if (process.platform !== 'win32') {
return 'utf8'; // macOS / Linux 默认 UTF-8
}
// Windows: 检查 code page
const output = execSync('chcp', { encoding: 'utf8' }).toLowerCase().trim();
if (output.includes('65001')) {
return 'utf8';
}
if (output.includes('936')) {
return 'gbk';
}
} catch {
// 如果 execSync 出错,走默认
}
return 'utf8';
}
/**
* 自定义 ConsoleTransport:自动转码,解决 Windows 控制台中文乱码
*/
class EncodedConsoleTransport extends Transport {
private _encoding: SupportedEncoding;
constructor(opts?: Transport.TransportStreamOptions) {
super(opts);
this._encoding = detectEncoding(); // 初始化时就探测好
}
override log(info: any, callback: () => void): void {
setImmediate(() => this.emit('logged', info));
let formatted = `${info.timestamp} [${info.level}]`;
if (info.label && info.label !== DEFULT_LABEL) {
formatted += ` [${String(info.label).substring(0, 9)}]`;
}
formatted += `: ${info.message}`;
const encodedBuffer = iconv.encode(formatted + '\n', this._encoding);
process.stdout.write(encodedBuffer);
callback();
}
}
const consoleTransport = new EncodedConsoleTransport({
level: 'debug',
});
const transports: Transport[] = [consoleTransport];
const winstonLogger = winston.createLogger({
format: format.combine(
format.timestamp({ format: 'HH:mm:ss.SSS' }),
format.colorize(), // 不同等级 level 的日志上色(info=绿色,warn=黄色,error=红色)
format.splat(), // 支持 %s, %d, %j 等格式化
format.simple() // 简单格式化
),
transports: transports,
});