You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:56:46