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

C# Windows服务log4net配置异常:配置文件启动失败,代码配置日志丢失

解决Windows服务中log4net日志异常问题

首先,咱们一步步拆解你遇到的两个核心问题:app.config配置log4net时服务无法启动,以及代码初始化Logger后日志时常不生成,结合你新增Socket模块的背景,大概率是配置遗漏、初始化时机不对,或者Socket阻塞操作干扰了日志流程。下面是具体的排查和修复方案:

一、修复app.config配置方式的服务启动失败问题

你的app.config里缺少了log4net配置节的声明,这是导致配置加载失败、服务启动报错的关键原因。另外,log4net的初始化时机也需要调整到服务启动后的正确阶段。

1. 完善app.config的配置节声明

在<configuration>节点下首先添加<configSections>,明确声明log4net的配置节类型:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- 新增配置节声明,这是log4net读取配置的前提 -->
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
  <log4net>
    <!-- 保留你原有log4net配置不变 -->
    <appender name="TestAppender" type="log4net.Appender.RollingFileAppender" >
      <file value="C:\log\impersonationlog_JamochaService.log" />
      <encoding value="utf-8" />
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level [%thread] %type.%method - %message%n" />
      </layout>
    </appender>
    <root>
      <level value="All" />
      <appender-ref ref="TestAppender" />
    </root>
  </log4net>
</configuration>

2. 调整log4net初始化时机到OnStart方法

Windows服务的构造函数是在服务实例被创建时调用,此时服务还未正式启动,环境权限和上下文都不适合初始化日志框架。把初始化代码移到OnStart方法中:

public partial class Service1 : ServiceBase
{
    private static readonly ILog _log = LogManager.GetLogger(typeof(Service1));

    public Service1()
    {
        InitializeComponent();
        // 不要在这里初始化log4net
    }

    protected override void OnStart(string[] args)
    {
        // 初始化log4net
        log4net.Config.XmlConfigurator.Configure();
        _log.Info("服务已启动");

        // 关键:把Socket通信放到后台线程,避免阻塞主线程
        Task.Run(() => SocketCommunication());
    }

    // 你的SocketCommunication方法保持不变
}

3. 验证日志目录权限

确保Windows服务运行的账户(默认是Local System)对C:\log目录有读写权限。如果权限不足,日志文件无法创建,也会导致服务启动失败或日志丢失。


二、修复代码初始化Logger后日志时常不生成的问题

如果坚持用代码初始化Logger,需要修正几个关键配置和执行逻辑:

1. 修正Logger.Setup()的配置错误

你的Logger.Setup()里把AppendToFile设为false,这会每次启动服务时覆盖日志文件,且并发场景下容易出问题;另外可以移除不必要的MemoryAppender,避免分散日志输出:

public class Logger
{
    public static void Setup()
    {
        Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
        PatternLayout patternLayout = new PatternLayout();
        patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline";
        patternLayout.ActivateOptions();

        RollingFileAppender roller = new RollingFileAppender();
        roller.AppendToFile = true; // 修改为true,追加日志而非覆盖
        roller.File = "C:\\Logs\\EventLog.txt";
        roller.Layout = patternLayout;
        roller.MaxSizeRollBackups = 5;
        roller.MaximumFileSize = "1GB";
        roller.RollingStyle = RollingFileAppender.RollingMode.Size;
        roller.StaticLogFileName = true;
        roller.ActivateOptions();
        hierarchy.Root.AddAppender(roller);

        // 移除MemoryAppender(除非你需要内存日志功能)
        // MemoryAppender memory = new MemoryAppender();
        // memory.ActivateOptions();
        // hierarchy.Root.AddAppender(memory);

        hierarchy.Root.Level = Level.Info;
        hierarchy.Configured = true;
    }
}

2. 调整Logger初始化和Socket通信的线程逻辑

  • 同样把Logger.Setup()移到OnStart方法中执行,而非构造函数。
  • 必须把SocketCommunication放到后台线程:socket.Accept()是阻塞调用,如果在主线程执行会卡住服务的整个生命周期,包括日志写入线程,导致日志无法及时生成甚至丢失:
protected override void OnStart(string[] args)
{
    Logger.Setup();
    var log = LogManager.GetLogger(typeof(Service1));
    log.Info("服务已启动");

    // 用Task启动Socket通信的后台任务
    Task.Run(() => SocketCommunication());
}

3. 确保日志对象的正确获取

在SocketCommunication方法中,不要用静态的Log.Info,而是通过LogManager.GetLogger获取当前类的日志实例,保证日志上下文正确:

private void SocketCommunication()
{
    var log = LogManager.GetLogger(typeof(Service1)); // 正确获取日志实例
    IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);
    permission = new SocketPermission(NetworkAccess.Accept, TransportType.Tcp, "", SocketPermission.AllPorts);
    IPHostEntry ipHost = Dns.GetHostEntry("");
    IPAddress ipAddr = ipHost.AddressList[0];
    IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 4510);
    socket.Bind(ipEndPoint);
    socket.Listen(10);
    sListener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    log.Info("Waiting for a client...");
    client = socket.Accept();
    IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
    log.Info("Connected with " + clientep.Address + " at port " + clientep.Port);

    while (true)
    {
        byte[] data = new byte[1024];
        int receivedDataLength = client.Receive(data);
        string stringData = Encoding.ASCII.GetString(data, 0, receivedDataLength);
        log.Info("Data recieved :- " + stringData);
        
        int adder = Convert.ToInt32(stringData);
        adder++;
        string input = adder.ToString();
        data = Encoding.ASCII.GetBytes(input);
        client.Send(data, data.Length, SocketFlags.None);
        log.Info("Data sent :- " + input);
    }
}

三、额外排查点

  1. Socket异常捕获:你的SocketCommunication方法没有异常处理,若出现连接中断、数据转换错误等异常,会导致线程崩溃,日志也无法记录。建议添加try-catch块:
private void SocketCommunication()
{
    var log = LogManager.GetLogger(typeof(Service1));
    try
    {
        // 原有Socket逻辑
    }
    catch (Exception ex)
    {
        log.Error("Socket通信异常", ex);
        // 可在这里添加重连逻辑
    }
}
  1. 服务账户权限:如果服务不是用Local System运行,要确保账户对日志目录和Socket端口有足够权限。

按照上面的步骤调整后,应该能恢复正常的日志记录,同时保证服务稳定启动运行。

内容的提问来源于stack exchange,提问作者Raghavendra B Srinidhi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:26:56