使用Aop的方式实现自动日志记录的方式详细介绍

目录
  • 34、使用Aop的方式实现自动日志记录
  • 采用第一种方式:
    • 1、第一步、定义一个注解:
    • 2、第二步、编写一个切面
    • 3、使用自定义注解

34、使用Aop的方式实现自动日志记录

自动日志记录的实现的两种方式:

①通过监听器去监听,当访问到具体的类方法,通过aop切面去获取访问的方法,然后将日志记录下来
②通过拦截器,编写一个类去继承HandlerInterceptorAdapter,重写preHandle,postHandle,然后在里面进行日志记录,编写的类加到spring容器里

采用第一种方式:

1、第一步、定义一个注解:

Annotation 注解的作用:

@interface 表示这是一个注解类, 不是interface,是注解类 定义注解用的,是jdk1.5之后加入的,java没有给它新的关键字,所以就用@interface 这么个东西表示了

@Inherited //这个Annotation 可以被继承

@Documented //这个Annotation可以被写入javadoc

@Target:注解的作用目标

@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包

@Retention(RetentionPolicy.RUNTIME) //可以用来修饰注解,是注解的注解,称为元注解。

public enum RetentionPolicy {
    SOURCE, // 编译器处理完Annotation后不存储在class中
    CLASS, // 编译器把Annotation存储在class中,这是默认值
    RUNTIME // 编译器把Annotation存储在class中,可以由虚拟机读取,反射需要
}

创建一个注解:

default 0 相当于set和get方法,添加一个默认值

/**
 * 系统日志注解
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoLog {

	/**
	 * 日志内容
	 *
	 * @return
	 */
	String value() default "";
	 * 日志类型
	 * @return 1:登录日志;2:操作日志;3:访问日志;4:异常日志;5:定时任务;
	int logType() default CommonConstant.LOG_TYPE_2;

	 * 操作日志类型
	 * @return (1查询,2添加,3修改,4删除)
	int operateType() default 0;
}

CommonConstant 相关的配置

public interface CommonConstant {

	/**
	 * 正常状态
	 */
	public static final Integer STATUS_NORMAL = 0;
	 * 禁用状态
	public static final Integer STATUS_DISABLE = -1;
	 * 删除标志
	public static final Integer DEL_FLAG_DELETED = 1;
	 * 未删除
	public static final Integer DEL_FLAG_UNDELETED = 0;
	 * 系统日志类型: 登录
	public static final int LOG_TYPE_1 = 1;

	 * 系统日志类型: 操作
	public static final int LOG_TYPE_2 = 2;
    /**
     * 系统日志类型: 访问
     */
	public static final int LOG_TYPE_3 = 3;
     * 系统日志类型: 异常
    public static final int LOG_TYPE_4 = 4;
     * 系统日志类型: 定时任务
    public static final int LOG_TYPE_5 = 5;
     * 系统日志类型: 用户管理
    public static final int LOG_TYPE_6 = 6;
     * 系统登陆日志:正常账户密码登录
    public static final int OPERATE_TYPE_LT1_1 = 1;
     * 系统登陆日志:二维码登陆
    public static final int OPERATE_TYPE_LT1_2 = 2;
     * 系统登陆日志:单点登陆
    public static final int OPERATE_TYPE_LT1_3 = 3;
     * 系统登陆日志:登出
    public static final int OPERATE_TYPE_LT1_4 = 4;
     * 系统登陆日志:模拟登陆
    public static final int OPERATE_TYPE_LT1_5 = 5;
	 * 操作日志类型: 查询
	public static final int OPERATE_TYPE_LT2_1 = 1;
	 * 操作日志类型: 添加
	public static final int OPERATE_TYPE_LT2_2 = 2;
	 * 操作日志类型: 更新
	public static final int OPERATE_TYPE_LT2_3 = 3;
	 * 操作日志类型: 删除
	public static final int OPERATE_TYPE_LT2_4 = 4;
	 * 操作日志类型: 导入
	public static final int OPERATE_TYPE_LT2_5 = 5;
	 * 操作日志类型: 导出
	public static final int OPERATE_TYPE_LT2_6 = 6;
     * 访问日志类型: 进入
    public static final int OPERATE_TYPE_LT3_1 = 1;
     * 异常日志类型: 普通操作即代码错误
    public static final int OPERATE_TYPE_LT4_1 = 1;
     * 异常日志类型: 非法操作即越权操作
    public static final int OPERATE_TYPE_LT4_2 = 2;
	public static final String CLIENT_TYPE_PC="0";
	public static final String CLIENT_TYPE_MOBILE="1";
	/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
    public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
    /** {@code 200 OK} (HTTP/1.0 - RFC 1945) */
    public static final Integer SC_OK_200 = 200;

    /**访问权限认证未通过 510*/
    public static final Integer SC_JEECG_NO_AUTHZ=510;
    /** 登录用户Shiro权限缓存KEY前缀 */
    public static String PREFIX_USER_SHIRO_CACHE  = "shiro:cache:org.jeecg.modules.shiro.authc.ShiroRealm.authorizationCache:";
    /** 登录用户Token令牌缓存KEY前缀 */
    public static final String PREFIX_USER_TOKEN  = "prefix_user_token_";
    /** Token缓存时间:3600秒即一小时 */
    public static final int  TOKEN_EXPIRE_TIME  = 3600;
     *  0:一级菜单
    public static final Integer MENU_TYPE_0  = 0;
   /**
    *  1:子菜单
    */
    public static final Integer MENU_TYPE_1  = 1;
     *  2:按钮权限
    public static final Integer MENU_TYPE_2  = 2;
    /**通告对象类型(USER:指定用户,ALL:全体用户)*/
    public static final String MSG_TYPE_UESR  = "USER";
    public static final String MSG_TYPE_ALL  = "ALL";
    /**发布状态(0未发布,1已发布,2已撤销)*/
    public static final String NO_SEND  = "0";
    public static final String HAS_SEND  = "1";
    public static final String HAS_CANCLE  = "2";
    /**阅读状态(0未读,1已读)*/
    public static final String HAS_READ_FLAG  = "1";
    public static final String NO_READ_FLAG  = "0";
    /**优先级(L低,M中,H高)*/
    public static final String PRIORITY_L  = "L";
    public static final String PRIORITY_M  = "M";
    public static final String PRIORITY_H  = "H";
     * 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
    public static final String SMS_TPL_TYPE_0  = "0";
    public static final String SMS_TPL_TYPE_1  = "1";
    public static final String SMS_TPL_TYPE_2  = "2";
     * 状态(0无效1有效)
    public static final String STATUS_0 = "0";
    public static final String STATUS_1 = "1";
     * 同步工作流引擎1同步0不同步
    public static final String ACT_SYNC_0 = "0";
    public static final String ACT_SYNC_1 = "1";
     * 消息类型1:通知公告2:系统消息
    public static final String MSG_CATEGORY_1 = "1";
    public static final String MSG_CATEGORY_2 = "2";
     * 是否配置菜单的数据权限 1是0否
    public static final Integer RULE_FLAG_0 = 0;
    public static final Integer RULE_FLAG_1 = 1;
     * 用户状态 0冻结 1正常 2待定
    public static final Integer USER_FREEZE = 0;
    public static final Integer USER_NORMAL = 1;
     * 用户删除标志位 0未删 1已删
    public static final Integer USER_DELETE_NO=0;
    public static final Integer USER_DELETE_YES=1;
    /**字典翻译文本后缀*/
    public static final String DICT_TEXT_SUFFIX = "_dictText";
    public static final String ITEM_DISPLAY = "_display";
     * 表单设计器主表类型
    public static final Integer DESIGN_FORM_TYPE_MAIN = 1;
     * 表单设计器子表表类型
    public static final Integer DESIGN_FORM_TYPE_SUB = 2;
     * 表单设计器URL授权通过
    public static final Integer DESIGN_FORM_URL_STATUS_PASSED = 1;
     * 表单设计器URL授权未通过
    public static final Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2;
     * 表单设计器新增 Flag
    public static final String DESIGN_FORM_URL_TYPE_ADD = "add";
     * 表单设计器修改 Flag
    public static final String DESIGN_FORM_URL_TYPE_EDIT = "edit";
     * 表单设计器详情 Flag
    public static final String DESIGN_FORM_URL_TYPE_DETAIL = "detail";
     * 表单设计器复用数据 Flag
    public static final String DESIGN_FORM_URL_TYPE_REUSE = "reuse";
     * 表单设计器编辑 Flag (已弃用)
    public static final String DESIGN_FORM_URL_TYPE_VIEW = "view";
     * online参数值设置(是:Y, 否:N)
    public static final String ONLINE_PARAM_VAL_IS_TURE = "Y";
    public static final String ONLINE_PARAM_VAL_IS_FALSE = "N";
     * 文件上传类型(本地:local,Minio:minio,阿里云:alioss)
    public static final String UPLOAD_TYPE_LOCAL = "local";
    public static final String UPLOAD_TYPE_MINIO = "minio";
    public static final String UPLOAD_TYPE_OSS = "alioss";
     * 员工身份 (1:普通员工  2:上级)
    public static final Integer USER_IDENTITY_1 = 1;
    public static final Integer USER_IDENTITY_2 = 2;
     * 日期格式
    public static final String TIME_FORMAT_YMD = "yyyy-MM-dd";
    public static final String TIME_FORMAT_YMDHMS = "yyyy-MM-dd HH:mm:ss";
    public static final String TIME_FORMAT_YMDHMSSZ = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
}

2、第二步、编写一个切面

@Aspect 表示这是一个切面

@Component 告诉spring 这是一个bean ,注入

@annotation 获取定义的注解

@Pointcut 切点,

@Pointcut("@annotation(xx.AutoLog)") 表示,使用了这个注解的,就是切入点

@Around的作用

既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;
可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;
可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回值; 当需要改变目标方法的返回值时,只能使用Around方法;
虽然Around功能强大,但通常需要在线程安全的环境下使用。因此,如果使用普通的Before、AfterReturing增强方法就可以解决的事情,就没有必要使用Around增强处理了。

ProceedingJoinPoint 环绕通知,主要作用找到程序执行中的可识别的点,当aop的切入点

  1. 环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。
  2. 简单理解,环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的.
/**
 * 系统日志,切面处理类
 *
 */
@Aspect
@Component
public class AutoLogAspect {
    @Autowired
    private ISysLogService sysLogService;

    @Pointcut("@annotation(xx.AutoLog)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //执行方法
        Object result = point.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;

        //保存日志
        saveSysLog(point, time);

        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SysLog sysLog = new SysLog();
        AutoLog syslog = method.getAnnotation(AutoLog.class);
        if (syslog != null) {
            //注解上的描述,操作日志内容
            sysLog.setLogContent(syslog.value());
            sysLog.setLogType(syslog.logType());

        }

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");

        //设置操作类型
        if (sysLog.getLogType() == CommonConstant.LOG_TYPE_2) {
            sysLog.setOperateType(getOperateType(methodName, syslog.operateType()));
        }

        //请求的参数
        Object[] args = joinPoint.getArgs();
        try {
            String params = JSONObject.toJSONString(args);
            sysLog.setRequestParam(params);
        } catch (Exception e) {

        }
        try {
            //获取request
            HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
            //设置IP地址
            sysLog.setIp(IPUtils.getIpAddr(request));
        } catch (Exception e) {

        }
        //获取登录用户信息
        LoginUser sysUser = null;
        try {
            sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        } catch (Exception e) {

        }
        if (sysUser != null) {
            sysLog.setUserId(sysUser.getId());
            sysLog.setUserName(sysUser.getUserName());
            sysLog.setRealName(sysUser.getRealName());
            sysLog.setOrgId(sysUser.getNowOrgId());
            sysLog.setOrgName(sysUser.getNowOrgName());
        }
        //耗时
        sysLog.setCostTime(time);
        sysLog.setCreateTime(new Date());
        //保存系统日志
        sysLogService.save(sysLog);
    }

    /**
     * 获取操作类型
     */
    private int getOperateType(String methodName, int operateType) {
        if (operateType > 0) {
            return operateType;
        }
        if (methodName.startsWith("list")) {
            return CommonConstant.OPERATE_TYPE_LT2_1;
        }
        if (methodName.startsWith("add")) {
            return CommonConstant.OPERATE_TYPE_LT2_2;
        }
        if (methodName.startsWith("edit")) {
            return CommonConstant.OPERATE_TYPE_LT2_3;
        }
        if (methodName.startsWith("delete")) {
            return CommonConstant.OPERATE_TYPE_LT2_4;
        }
        if (methodName.startsWith("import")) {
            return CommonConstant.OPERATE_TYPE_LT2_5;
        }
        if (methodName.startsWith("export")) {
            return CommonConstant.OPERATE_TYPE_LT2_6;
        }
        return CommonConstant.OPERATE_TYPE_LT2_1;
    }

    @AfterThrowing(pointcut = "logPointCut()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        SysLog sysLog = new SysLog();

        StackTraceElement[] stackTraceElements = ex.getStackTrace();
        String rootExceptionName = ex.getClass().getName();

        StringBuilder resultContent = new StringBuilder("异常类:" + rootExceptionName);

        int count = 0;
        int maxTrace = 3;
        for (StackTraceElement stackTraceElement : stackTraceElements) {
            if (stackTraceElement.getClassName().contains("com.lingxu") && count < maxTrace) {
                resultContent.append("\n出现于").append(stackTraceElement.getClassName())
                        .append("类中的").append(stackTraceElement.getMethodName())
                        .append("方法中 位于该类文件的第").append(stackTraceElement.getLineNumber())
                        .append("行)");
                count++;
                if (count == maxTrace) {
                    break;
                }
            }
        }

        sysLog.setExceptionContent(resultContent.toString());

        AutoLog syslog = method.getAnnotation(AutoLog.class);

        if (syslog != null) {
            //注解上的描述,操作日志内容
            sysLog.setLogContent(syslog.value() + "出现异常");
            sysLog.setLogType(CommonConstant.LOG_TYPE_4);
        }

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");

        //设置操作类型
        sysLog.setOperateType(CommonConstant.OPERATE_TYPE_LT4_1);

        //请求的参数
        Object[] args = joinPoint.getArgs();
        try {
            String params = JSONObject.toJSONString(args);
            sysLog.setRequestParam(params);
        } catch (Exception e) {

        }
        try {
            //获取request
            HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
            //设置IP地址
            sysLog.setIp(IPUtils.getIpAddr(request));
        } catch (Exception e) {

        }
        try {
            //获取登录用户信息
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            if (sysUser != null) {
                sysLog.setUserId(sysUser.getId());
                sysLog.setUserName(sysUser.getUserName());
                sysLog.setRealName(sysUser.getRealName());
                sysLog.setOrgId(sysUser.getNowOrgId());
                sysLog.setOrgName(sysUser.getNowOrgName());

            }
        } catch (Exception e) {
        }
        //保存系统日志
        sysLogService.save(sysLog);
    }
}

3、使用自定义注解

可以在controller或者实现类上进行注解的加入

	@AutoLog(value = "sss",logType = CommonConstant.LOG_TYPE_3, operateType = 2)
	@ApiOperation(value="记录查询日志-分页列表查询", notes="记录查询日志-分页列表查询")
	@PostMapping(value = "/queryPage")
	public Result<?> queryPage(@RequestBody SysSelectLog sysSelectLog){
		Page<SysSelectLog> page = new Page<>(sysSelectLog.getPageNo(),sysSelectLog.getPageSize());
		IPage<SysSelectLog> sysSelectLogIPage = sysSelectLogService.queryPage(page,sysSelectLog);
		return Result.ok(sysSelectLogIPage);
	}

到此这篇关于使用Aop的方式实现自动日志记录的文章就介绍到这了,更多相关Aop自动日志记录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 运用Spring Aop+注解实现日志记录

    目录 1. 介绍 2. 实践 2.1 定义注解 2.2 切面类 2.3 编写测试方法 2.4 运行结果 3. 总结 4. 参考文章 1. 介绍 我们都知道Spring框架的两大特性分别是 IOC (控制反转)和 AOP (面向切面),这个是每一个Spring学习视频里面一开始都会提到的.在日常项目中,我们也会经常使用IOC控制反转,但是却感觉AOP很少会运用到.其实AOP大有用处,甚至可以让你偷偷懒. 举一个例子,假如现在要让你记录每一个请求的请求IP,请求的方法,请求路径,请求的参数,返回参数

  • Spring AOP实现复杂的日志记录操作(自定义注解)

    目录 Spring AOP复杂的日志记录(自定义注解) 第一步 第二步 第三步 第四步 多个注解可以合并成一个,包括自定义注解 比如说SpringMVC的注解 Spring AOP复杂的日志记录(自定义注解) 做项目中,业务逻辑要求只要对数据库数据进行改动的都需要记录日志(增删改),记录的内容有操作者.操作的表名及表名称.具体的操作,以及操作对应的数据. 首先想到的就是Spring 的AOP功能.可是经过一番了解过后,发现一般的日志记录,只能记录一些简单的操作,例如表名.表名称等记录不到. 于是

  • 在springboot中使用AOP进行全局日志记录

    目录 前言 1. spring AOP 是什么? 2.spring AOP 能做什么? 3.spring AOP 我能用 AOP 解决什么问题? 一.引入依赖,增加自定义注解 1.引入 maven 依赖 2.增加自定义注解 OperationLog 二.为自定义注解编写切面实现 三.使用自定义日志注解 前言 此前项目上需要对用户的操作进行日志记录,以便后续追踪问题,所以就学习了使用 spring AOP 来进行日志记录. 1. spring AOP 是什么? spring 的两大核心就是 IOC

  • 使用Aop的方式实现自动日志记录的方式详细介绍

    目录 34.使用Aop的方式实现自动日志记录 采用第一种方式: 1.第一步.定义一个注解: 2.第二步.编写一个切面 3.使用自定义注解 34.使用Aop的方式实现自动日志记录 自动日志记录的实现的两种方式: ①通过监听器去监听,当访问到具体的类方法,通过aop切面去获取访问的方法,然后将日志记录下来②通过拦截器,编写一个类去继承HandlerInterceptorAdapter,重写preHandle,postHandle,然后在里面进行日志记录,编写的类加到spring容器里 采用第一种方式

  • Android 日志系统Logger源代码详细介绍

    我们知道,在Android系统中,提供了一个轻量级的日志系统,这个日志系统是以驱动程序的形式实现在内核空间的,而在用户空间分别提供了Java接口和C/C++接口来使用这个日志系统,取决于你编写的是Android应用程序还是系统组件.在前面的文章浅谈Android系统开发中LOG的使用中,已经简要地介绍了在Android应用程序开发中Log的使用方法,在这一篇文章中,我们将更进一步地分析Logger驱动程序的源代码,使得我们对Android日志系统有一个深刻的认识. 既然Android 日志系统是

  • Spring AOP结合注解实现接口层操作日志记录

    目录 1.表和实体设计 1.实体设计 2.表结构设计 2.日志注解 3.核心AOP类 4.用到的工具类 5.测试类 6.测试结果 1.表和实体设计 1.实体设计 实体基类 @Data //映射将仅应用于其子类 @MappedSuperclass //指定要用于实体或映射超类的回调侦听器类.此注释可以应用于实体类或映射的超类. @EntityListeners(AuditingEntityListener.class) public class BaseEntity implements Seri

  • 使用Log4net进行日志记录

    首先说说为什么要进行日志记录.在一个完整的程序系统里面,日志系统是一个非常重要的功能组成部分.它可以记录下系统所产生的所有行为,并按照某种规范表达出来.我们可以使用日志系统所记录的信息为系统进行排错,优化系统的性能,或者根据这些信息调整系统的行为. Log4net是一个很著名的开源的日志记录组件.官方网址为:http://logging.apache.org/log4net/ ,使用Log4net能够很简单的为我们的程序添加日志记录功能.下面我们先通过一个网站例子来说明如何在.net中使用log

  • Java SpringBoot项目如何优雅的实现操作日志记录

    目录 前言 一.AOP是什么? 二.AOP做了什么? 三.实现步骤 1. 添加AOP依赖 2. 自定义一个日志注解 3. 切面声明 4. 标注在接口上 5. 实现的效果 总结 前言 在实际开发当中,对于某些关键业务,我们通常需要记录该操作的内容,一个操作调一次记录方法,每次还得去收集参数等等,会造成大量代码重复. 我们希望代码中只有业务相关的操作,在项目中使用注解来完成此项功能. 通常就是使用Spring中的AOP特性来实现的,那么在SpringBoot项目当中应该如何来实现呢? 一.AOP是什

  • PHP中错误与异常的日志记录用法分析

    本文分析了PHP中错误与异常的日志记录用法.分享给大家供大家参考,具体如下: 提到 Nginx + PHP 服务的错误日志,我们通常能想到的有 Nginx 的 access 日志.error 日志以及 PHP 的 error 日志.虽然看起来是个很简单的问题,但里面其实又牵扯到应用配置以及日志记录位置的问题,如果是在 ubuntu 等系统下使用 apt-get 的方式来安装,其自有一套较为合理的的配置文件可用.再者运行的应用程序中的配置也会影响到日志记录的方式及内容. 错误与异常的区别 关于错误

  • Python loguru日志库之高效输出控制台日志和日志记录

    1安装loguru loguru的PyPI地址为:https://pypi.org/project/loguru/ GitHub仓库地址为:https://github.com/Delgan/loguru 我们可以直接使用pip命令对其进行安装 pip install loguru 或者下载其源码,使用Python命令进行安装. |2loguru简单使用 from loguru import logger logger.info("中文loguru") logger.debug(&qu

  • Java使用JDK与Cglib动态代理技术统一管理日志记录

    Java中动态代理主要有JDK和CGLIB两种方式. 区别主要是jdk是代理接口,而cglib是代理类. 优点:这种方式已经解决我们前面所有日记需要的问题.非常的灵活.而且可以方便的在后期进行维护和升级. 缺点:当然使用jdk动态代理,必需要有接口.如果没有接口.就无法使用jdk动态代理技术. 计算接口 Calculate.java public interface Calculate { /** * 加法运算 * @param num1 参数 1 * @param num2 参数 2 * @r

  • .Net Core日志记录之自定义日志组件

    一.前言 回顾:日志记录之日志核心要素揭秘 在上一篇中,我们通过学习了解在.net core 中内置的日志记录中的几大核心要素,在日志工厂记录器(ILoggerFactory)中实现将日志记录提供器(ILoggerProvider)对象都可以集成到Logger对象组合中,这样的话,我们就可以通过基于ILoggerProvider自定义日志记录程序集成到Logger中,再创建写日志定义Ilogger,自定义日志记录器实现日志的输出方式,这样实现自定义日志记录工具. 在这个过程中,日志记录器ILog

随机推荐