基于AOP+Log4Net+AutoFac日志框架

发布于:2025-04-13 ⋅ 阅读:(23) ⋅ 点赞:(0)

1.项目概述

这是一个基于 C# 的 WPF 项目 WpfApp12log4net,它综合运用了依赖注入、日志记录和接口实现等多种技术,同时使用了 AutofacCastle.Core 和 log4net 等第三方库。

2.配置log4net 

 新建一个Log4Net.config,配置需要记录的日志信息,主要该文件在编译后要生成到debug或者release文件夹下。

配置文件如下:

<?xml version="1.0" encoding="utf-8"?>
    <log4net>
    <!--错误日志类-->
    <logger name="logerror">
      <!--日志类的名字-->
      <level value="ALL" />
      <!--定义记录的日志级别-->
      <appender-ref ref="ErrorAppender" />
      <!--记录到哪个介质中去-->
    </logger>
    <!--信息日志类-->
    <logger name="loginfo">
      <level value="ALL" />
      <appender-ref ref="InfoAppender" />
    </logger>

	<!--MES日志类-->
	<logger name="Mesinfo">
	  <level value="ALL" />
	  <appender-ref ref="MesAppender" />
	</logger>


		<!--错误日志附加介质-->
    <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
      <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
      <param name="File" value="Log\\LogError2\\" />
      <!--日志输出到exe程序这个相对目录下-->
      <param name="AppendToFile" value="true" />
      <!--输出的日志不会覆盖以前的信息-->
      <param name="MaxSizeRollBackups" value="100" />
      <!--备份文件的个数-->
      <param name="MaxFileSize" value="1024" />
      <!--当个日志文件的最大大小-->
      <param name="StaticLogFileName" value="false" />
      <!--是否使用静态文件名-->
      <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
      <!--日志文件名-->
      <param name="RollingStyle" value="Date" />
      <!--文件创建的方式,这里是以Date方式创建-->
      <!--错误日志布局-->
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%n异常时间:%d [%t]  %n异常级别:%-5p  %n异 常 类:%c [%x]  %n%m  %n "  />
      </layout>
    </appender>
 
		
		<!--信息日志附加介质-->
    <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="Log\\LogInfo\\"/>
      <param name="AppendToFile" value="true"/>
      <param name="MaxFileSize" value="10240"/>
      <param name="MaxSizeRollBackups" value="100" />
      <param name="StaticLogFileName" value="false" />  
      <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
      <param name="RollingStyle" value="Date" />
      <!--信息日志布局-->
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="[时间] %d [%t] [信息] %m%n"  />
      </layout>
    </appender>


		<!--信息日志附加介质-->
		<appender name="MesAppender" type="log4net.Appender.RollingFileAppender">
			<param name="File" value="Log\\MesInfo\\"/>
			<param name="AppendToFile" value="true"/>
			<param name="MaxFileSize" value="10240"/>
			<param name="MaxSizeRollBackups" value="100" />
			<param name="StaticLogFileName" value="false" />
			<param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
			<param name="RollingStyle" value="Date" />
			<!--信息日志布局-->
			<layout type="log4net.Layout.PatternLayout">
				<param name="ConversionPattern" value="[时间] %d [%t] [信息] %m%n"  />
			</layout>
		</appender>
		
  </log4net>

3.加载配置文件

要在代码启动的时候加载,以下是涉及到其他配置,所以是动态路径的案例。

  string configFilePath = "Log4Net.config";
  var fileInfo = new FileInfo(configFilePath);
  if (!fileInfo.Exists)
  {
      throw new FileNotFoundException($"配置文件 {configFilePath} 不存在!");
  }
  XmlConfigurator.Configure(fileInfo);

  string path = @"C:\\Log4NetTestFile\\";
  string[] fileName = { "InfoAppender", "ErrorAppender", "MesAppender" };
  ILoggerRepository repository = LogManager.GetRepository(Assembly.GetEntryAssembly());
  for (int i = 0; i < fileName.Length; i++)
  {
      log4net.Appender.RollingFileAppender appender = repository.GetAppenders().OfType<log4net.Appender.RollingFileAppender>().FirstOrDefault(a => a.Name == fileName[i]);
      if (appender != null)
      {
          appender.File = path + fileName[i] + "\\";
          appender.ActivateOptions();
      }
  }

4.搭建日志方法类LogHelp

日志存储的方法写在里面。

using log4net;
using log4net.Config;
using System;
using System.IO;

namespace WpfApp12log4net
{
    public class LogHelp
    {
        private  readonly ILog log_info = LogManager.GetLogger("loginfo");
        private  readonly ILog log_error = LogManager.GetLogger("logerror");
        private  readonly ILog mes_info = LogManager.GetLogger("Mesinfo");

        public  void Info(string info)
        {
            if (log_info.IsInfoEnabled)
            {
                log_info.Info(info);
            }
        }

        public  void mesinfo(string info)
        {
            if (mes_info.IsInfoEnabled)
            {
                mes_info.Info(info);
            }
        }

        public  void Error(string error, Exception ex)
        {
            if (log_error.IsErrorEnabled)
            {
                log_error.Error(error, ex);
            }
        }

        public  void Error(string error)
        {
            if (log_error.IsErrorEnabled)
            {
                log_error.Error(error);
            }
        }
    }
}

4.拦截器搭建LoggingInterceptor

using Castle.DynamicProxy;
using log4net;
using System;
using System.Reflection;

namespace WpfApp12log4net
{
    public class LoggingInterceptor : IInterceptor
    {

        private readonly LogHelp logHelp;

        public LoggingInterceptor(LogHelp logHelp)
        {
            this.logHelp = logHelp;
        }

        public void Intercept(IInvocation invocation)
        {
            try
            {
                logHelp.Info($"开始执行方法: {invocation.Method.Name}");
                logHelp.Info($"参数: {string.Join(", ", invocation.Arguments)}");

                // 执行方法并获取返回值
                invocation.Proceed();
                object result = invocation.ReturnValue;

                // 记录返回值(如果方法不是 void)s
                if (invocation.Method.ReturnType != typeof(void))
                {
                    logHelp.Info($"方法 {invocation.Method.Name} 返回值: {result ?? "null"}");
                }

                logHelp.Info($"方法 {invocation.Method.Name} 执行完毕");
            }
            catch (Exception ex)
            {
                // 记录完整的异常信息(包括堆栈跟踪)
                logHelp.Error($"方法 {invocation.Method.Name} 执行出错: {ex.ToString()}", ex);
                throw; // 重新抛出异常,确保调用方能够捕获
            }
        }
    }
}

5.创建服务类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace WpfApp12log4net
    {
        public class Service : IService
        {

            public string methodservice11(string ttt)
            {
                try
                {
                    string[] str = null;
                    if (str[1] == "1")
                    {
                        // 此部分代码会触发异常
                    }
                    else
                    {
                        // 此部分代码会触发异常
                    }
                }
                catch (Exception ex)
                {
                    //LogHelp.Error(ex.Message);
                    //LogHelp.Error("异常", ex);
                }
                return "这是参数返回........的内容";
            }


            public string methodservice12(string ttt)
            {
                try
                {
                    //string[] str = null;
                    //if (str[1] == "1")
                    //{
                    //    // 此部分代码会触发异常
                    //}
                    //else
                    //{
                    //    // 此部分代码会触发异常
                    //}
                }
                catch (Exception ex)
                {
                    //LogHelp.Error(ex.Message);
                    //LogHelp.Error("异常", ex);
                }
                return "这是参数返回........的内容";
            }
        }
    }









using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfApp12log4net
{
    public class Service2 : IService2
    {

        public string methodservice21(string ttt)
        {
            try
            {
                string[] str = null;
                if (str[1] == "1")
                {
                    // 此部分代码会触发异常
                }
                else
                {
                    // 此部分代码会触发异常
                }
            }
            catch (Exception ex)
            {
                //LogHelp.Error(ex.Message);
                //LogHelp.Error("异常", ex);
            }
            return "这是参数返回........的内容";
        }
    }
}

6.创建服务接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfApp12log4net
{
    public interface IService
    {
     
        string methodservice11(string ttt);


        string methodservice12(string ttt);

    }
}






using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfApp12log4net
{
    public interface IService2
    {
   
        string methodservice21(string ttt);
    }
}
  

7.依赖注入

          var builder = new ContainerBuilder();
          var proxyGenerator = new ProxyGenerator();

          // 先注册 LogHelp
          builder.RegisterType<LogHelp>().AsSelf();
          // 注册 LoggingInterceptor
          builder.RegisterType<LoggingInterceptor>().AsSelf();

          // 注册 IService 接口及其实现类 Service
          builder.Register(c =>
          {
              var service = new Service();
              var interceptor = c.Resolve<LoggingInterceptor>();
              return proxyGenerator.CreateInterfaceProxyWithTarget(typeof(IService), service, interceptor) as IService;
          }).As<IService>();

          // 注册 IService2 接口及其实现类 Service2
          builder.Register(c =>
          {
              var service = new Service2();
              var interceptor = c.Resolve<LoggingInterceptor>();
              return proxyGenerator.CreateInterfaceProxyWithTarget(typeof(IService2), service, interceptor) as IService2;
          }).As<IService2>();

          // 注册 MainWindow
          builder.RegisterType<MainWindow>().AsSelf();

          Container = builder.Build();

8.总结

1. 依赖注入(Dependency Injection,DI)

使用 Autofac 库实现依赖注入。通过 ContainerBuilder 构建容器,注册接口及其实现类(如 IService 与 ServiceIService2 与 Service2 )以及窗口类(MainWindow )等,在程序运行时由容器负责创建对象并注入依赖关系,降低组件间耦合度。

2. 动态代理(Dynamic Proxy)

借助 Castle.DynamicProxy 库实现动态代理。定义了 LoggingInterceptor 类实现 IInterceptor 接口,在方法执行前后进行日志记录等操作。在注册服务时,利用 ProxyGenerator 创建代理对象,将拦截器应用到目标服务(ServiceService2 )上,实现对服务方法调用的拦截和增强 。

3. 日志记录

运用 log4net 日志框架进行日志记录。通过配置文件(log4net.config )设置不同类型日志(错误日志、信息日志、MES 日志 )的记录方式,包括日志级别、日志存储路径、文件滚动策略、日志格式等。在代码中通过 LogHelp 类封装的方法,在不同业务场景(方法执行、异常处理等 )下记录日志。

4. WPF(Windows Presentation Foundation)

这是一个 WPF 项目,使用 WPF 技术构建桌面应用程序界面。定义了 MainWindow 类继承自 Window,实现窗口相关功能,如按钮点击事件处理等,利用 WPF 的特性来呈现用户界面和交互逻辑。