使用log4net输出俄文字符显示为问号的解决方法及编码查询
解决log4net输出俄文字符显示为问号的问题
问题背景
使用log4net输出俄文字符时,日志中显示为问号(如Русский变为???????),相关配置与代码如下:
Web.config日志配置
<configuration> <appSettings> <add key="logFilePath" value="~/logTest.log" /> </appSettings> </configSections> <log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="C:\log.txt"/> <encoding value="utf-8" /> <appendToFile value="true"/> <rollingStyle value="Size"/> <maxSizeRollBackups value="5"/> <maximumFileSize value="2MB"/> <staticLogFileName value="true"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline%date [%thread] %level %logger - %message%newline%exception%newline------------------------- ---------------------------------------"/> </layout> </appender> <root> <level value="WARN"/> <appender-ref ref="RollingFileAppender"/> </root> </log4net>
日志处理类ClsLog实现
namespace Utils { public class ClsLog { private static readonly log4net.ILog log = log4net.LogManager .GetLogger(System.Reflection.MethodBase .GetCurrentMethod().DeclaringType); private static bool isInitialized = false; public static void WriteLog(enmLogType logType, string message) { Initialize(); log.Debug(message); } private static void Initialize() { if (isInitialized) return; string path = ConfigurationManager.AppSettings["logFilePath"]; string currentDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); currentDir = currentDir.Substring(6); currentDir += "\\.."; FileInfo finfo = new FileInfo(currentDir + "\\log4net.config"); log4net.Config.XmlConfigurator.ConfigureAndWatch(finfo); log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository(); foreach (IAppender a in h.Root.Appenders) { if (a is FileAppender) { FileAppender fa = (FileAppender)a; // Programmatically set this to the desired location here if (path != null) { string logFileLocation = path; fa.File = logFileLocation; fa.ActivateOptions(); break; } } } isInitialized = true; } } }
测试代码
public void print() { Utils.ClsLog.WriteLog(enmLogType.Debug, "Русский"); }
当前日志输出:
2023-01-16 12:52:17,282 DEBUG ???????
期望输出:
2023-01-16 12:52:17,282 DEBUG Русский
解决方案
1. 修复编码被重置的问题
在Initialize方法中,修改FileAppender的文件路径后调用ActivateOptions()会重置编码配置,导致UTF-8设置失效。需要在调用ActivateOptions()前重新指定编码:
修改Initialize方法中的对应代码块:
if (path != null) { string logFileLocation = path; fa.File = logFileLocation; // 重新设置UTF-8编码 fa.Encoding = System.Text.Encoding.UTF8; fa.ActivateOptions(); break; }
2. 确保配置文件本身的编码正确
将Web.config文件保存为UTF-8编码(无BOM也可),避免配置项中的<encoding value="utf-8" />被错误解析。
3. 使用正确的编辑器查看日志
不要用系统默认的记事本(默认ANSI编码打开),改用支持UTF-8的编辑器(如Notepad++),打开时选择UTF-8编码查看日志内容。
查看日志文件编码的方法
方法1:通过编辑器查看
用Notepad++打开日志文件,编辑器右下角会显示当前文件的编码类型(如UTF-8、ANSI等)。
方法2:通过代码检测
编写代码读取文件的BOM标识判断编码:
using System.IO; using System.Text; public static Encoding GetFileEncoding(string filePath) { using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { byte[] bom = new byte[4]; int readBytes = fs.Read(bom, 0, 4); // 检测BOM if (readBytes >= 3 && bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) return Encoding.UTF8; if (readBytes >= 2 && bom[0] == 0xFF && bom[1] == 0xFE) return Encoding.Unicode; if (readBytes >= 2 && bom[0] == 0xFE && bom[1] == 0xFF) return Encoding.BigEndianUnicode; if (readBytes >=4 && bom[0] == 0xFF && bom[1] == 0xFE && bom[2] == 0x00 && bom[3] == 0x00) return Encoding.UTF32; // 无BOM时默认按ANSI处理,也可根据实际场景调整 return Encoding.Default; } } // 调用示例 Encoding encoding = GetFileEncoding("~/logTest.log"); Console.WriteLine($"日志文件编码:{encoding.EncodingName}");
内容的提问来源于stack exchange,提问作者h.z.
相关产品推荐
相关产品推荐

