日志过滤(打码)--效率不高,并发异常-待改

在某些系统中,对于一些敏感信息(手机号,身份证号等),不宜直接打印到日志中,需要对这些敏感信息做打码处理,这里提供一个简单的示例。

一般情况,在输出日志时,系统会对log框架做一个简单的封装(类似对exception封装),将常用的debug,info,error等统一封装在logUtil中,系统统一调用。所以可以在这里做一个扩展,将日志先行处理,再调用日志框架输出,即可实现打码效果。

调用日志输出:

CmsLogger.audit("my mobile is : 18575541234 xxxxxxxx");
CmsLogger.error("my phone1 is : 3462777 xxxxxxxx");
CmsLogger.trace("my phone2 is : 0111-3462777 xxxxxxxx");
CmsLogger.audit("my phone3 is : 0111-3462777-011 xxxxxxxx");
CmsLogger.audit("my idNo is : 420611199111110655 xxxxxxxx");
CmsLogger.audit("my email is : zuangaaabbb@xxx.com.cn xxxxxxxx");
CmsLogger.audit("my passport is : 141234567 xxxxxxxx");
CmsLogger.audit("my soldier is : 3462745222222222 xxxxxxxx");

日志工具类:

package com.xxx.elis.elis_smp_cms.common.logging;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import com.xxx.elis.elis_smp_cms.common.util.PropertiesUtils;

@Component("CmsLogger")
public class CmsLogger {
	private static final String COLON = ":";
	private static Log tracerLogger;
	private static Log auditLogger;
	private static Log errorLogger;
	private static Log taskLogger;
	private static Log performanceLogger;
	private static Log breakdownLogger;
	private static Log redisLogger;
 
	private static String tracerLoggerName="tracer";
	private static String auditLoggerName="auditLogger";
	private static String errorLoggerName="errorLogger";
	private static String taskLoggerName="tasklog";
	private static String breakdownLoggerName="breakdown";
	private static String performanceLoggerName="performance";
	private static String redisLoggerName="redislog";
	private static boolean ouputClassAndMethodMsg=true;
	
	private static boolean isFilter = Boolean.parseBoolean(PropertiesUtils.getPropertyValues("log.filter.open","false"));
	public static ExecutorService executorService = Executors.newFixedThreadPool(5);
	
	static{try {
		afterPropertiesSet();
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}}

	private static int stackDeepth = 3;

	public static void trace(Object message) {
		message = generateMsg(message);
		tracerLogger.debug(message);
	}

	public static void audit(Object message) {
		message = generateMsg(message);
		auditLogger.info(message);
	}

	public static void error(Object message) {
		error(message,null);
//		message = generateMsg(message);
//		errorLogger.error(message);
	}

	public static void tasklog(Object message) {
		message = generateMsg(message);
		taskLogger.info(message);
	}

	public static void permlog(Object message) {
		message = generateMsg(message);
		performanceLogger.info(message);
	}

	public static void redislog(Object message) {
		message = generateMsg(message);
		redisLogger.info(message);
	}

	public static void breakdownlog(Object message) {
		message = generateMsg(message);
		breakdownLogger.info(message);
	}

	public static void afterPropertiesSet() throws Exception {
		tracerLogger = LogFactory.getLog(tracerLoggerName);
		auditLogger = LogFactory.getLog(auditLoggerName);
		errorLogger = LogFactory.getLog(errorLoggerName);
		taskLogger = LogFactory.getLog(taskLoggerName);
		performanceLogger = LogFactory.getLog(performanceLoggerName);
		breakdownLogger = LogFactory.getLog(breakdownLoggerName);
		redisLogger = LogFactory.getLog(redisLoggerName);
	}

	public static void error(final Object message, Throwable t) {
       Object msg = generateMsg(message);
       errorLogger.error(msg, t);
	}

	//统一处理日志生成的方法
	private static Object generateMsg(Object message) {
		if (ouputClassAndMethodMsg) {
			StackTraceElement[] stackTraceElement = Thread.currentThread()
					.getStackTrace();
			if ((stackTraceElement.length > getStackDeepth())
					&& (stackTraceElement[getStackDeepth()] != null)) {
				StackTraceElement stack = stackTraceElement[getStackDeepth()];
				String clazzName = stack.getClassName();
				message = clazzName.substring(clazzName.lastIndexOf(".") + 1,
						clazzName.length())
						+ COLON
						+ stack.getMethodName()
						+ COLON + stack.getLineNumber() + COLON + message;
			}
		}
		//这里添加开关
		if(isFilter) {
			message = LogFilter.filter(message.toString());
		}
		return message;
	}

	
	
	public static boolean isTracerEnabled() {
		return tracerLogger.isDebugEnabled();
	}

	public static boolean isAuditEnabled() {
		return auditLogger.isInfoEnabled();
	}

	public static boolean isErrorEnabled() {
		return errorLogger.isErrorEnabled();
	}

	public static boolean isOuputClassAndMethodMsg() {
		return ouputClassAndMethodMsg;
	}

	public static void setOuputClassAndMethodMsg(boolean ouputClassAndMethodMsg) {
		CmsLogger.ouputClassAndMethodMsg = ouputClassAndMethodMsg;
	}

	public static int getStackDeepth() {
		return stackDeepth;
	}

	public static void setStackDeepth(int stackDeepth) {
		CmsLogger.stackDeepth = stackDeepth;
	}

	public static void setTracerLoggerName(String tracerLoggerName) {
		CmsLogger.tracerLoggerName = tracerLoggerName;
	}

	public static void setAuditLoggerName(String auditLoggerName) {
		CmsLogger.auditLoggerName = auditLoggerName;
	}

	public static void setErrorLoggerName(String errorLoggerName) {
		CmsLogger.errorLoggerName = errorLoggerName;
	}

	public static void setTaskLoggerName(String taskLoggerName) {
		CmsLogger.taskLoggerName = taskLoggerName;
	}

	public static void setPerformanceLoggerName(String performanceLoggerName) {
		CmsLogger.performanceLoggerName = performanceLoggerName;
	}

	public static void setBreakdownLoggerName(String breakdownLoggerName) {
		CmsLogger.breakdownLoggerName = breakdownLoggerName;
	}

	public static void setRedisLoggerName(String redisLoggerName) {
		CmsLogger.redisLoggerName = redisLoggerName;
	}

}

日志拦截类:

package com.xxx.elis.elis_smp_cms.common.logging;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import com.xxx.elis.elis_smp_cms.common.util.PropertiesUtils;

//日志过滤器,最多支持可配置100个正则
public class LogFilter {

	private static List<LogReg> LOG_REG_LIST;
	private static Object lock = new Object();

	private static void init() {
		if (LOG_REG_LIST != null) {
			return;
		}
		synchronized (lock) {
			List<LogReg> temp = new ArrayList<LogReg>();
			for (int i = 0; i < 100; i++) {
				String val = PropertiesUtils.getPropertyValues("log.filter.list_" + i);
				if (StringUtils.isEmpty(val)) {
					break;
				}
				String[] reg = val.split(":");
				String rank[] = reg[1].split("-");
				int start = Integer.parseInt(rank[0]), end = Integer.parseInt(rank[1]);
				LogReg logReg = new LogReg();
				logReg.setReg(reg[0]);
				logReg.setStart(start);
				logReg.setEnd(end);
				logReg.setType(reg[2]);
				temp.add(logReg);
			}
			LOG_REG_LIST = temp;
		}

	}

	public static String filter(String message) {
		if (LOG_REG_LIST == null) {
			init();
		}
		for (LogReg reg : LOG_REG_LIST) {
			message = reg.filter(message);
		}
		return message;
	}

}

日志拦截实体类:

package com.xxx.elis.elis_smp_cms.common.logging;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * log过滤的正则表达式
 *
 */
public class LogReg {

	private String reg;
	private int start;
	private int end;
	private String type;
	private Pattern pattern;

	public String getReg() {
		return reg;
	}

	public void setReg(String reg) {
		this.reg = reg;
		pattern = Pattern.compile(reg);
	}

	public int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public int getEnd() {
		return end;
	}

	public void setEnd(int end) {
		this.end = end;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String filter(String msg) {
		Matcher result = pattern.matcher(msg);
		while (result.find()) {
			String ret = result.group();
			if(type.equals("email")) {
				end = ret.indexOf("@");
			} else if(type.equals("phone") || type.equals("passport") || type.equals("soldier")) {
				start = ret.length() - 4;
				end = ret.length();
			}
			String replace = getStars(start,end);
			String value = ret.substring(start, end);
			msg = msg.replaceAll(value, replace);
		}
		return msg;
	}
	
	private static String getStars(int start ,int end) {
		String stars = "";
		for(int i = 0 ; i < (end - start) ; i++) {
			stars += "*";
		}
		return stars;
	}

}

配置文件读取类:

package com.xxx.elis.elis_smp_cms.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;

public class PropertiesUtils {
    private PropertiesUtils() {
    }

    // 属性文件名称
    public static String propertiesFileName = "context-elis_smp_cms.properties";

    private static Properties properties = null;

    private static long lastModifed = 0;// 文件最后修改时间

    private static long lastReadTime = 0;// 最后读取时间

	
    private static void initProperties() {

        if (System.currentTimeMillis() - lastReadTime > 60000) {// 间隔60秒检查文件是否被修改(修改配置项最多60秒后生效)
            synchronized (PropertiesUtils.class) {
                if (System.currentTimeMillis() - 60000 > lastReadTime) {

                    File file = null;
                    FileInputStream fis = null;
                    try {
                        URI uri = PropertiesUtils.class.getClassLoader().getResource(propertiesFileName).toURI();
                        file = new File(uri);
                        if (file.lastModified() > lastModifed) {
                            lastModifed = file.lastModified();
                            fis = new FileInputStream(file);
                            properties = new Properties();
                            properties.load(fis); // 从输入流中读取属性文件的内容
                        }
                        lastReadTime = System.currentTimeMillis();
                    } catch (Exception e) {
                        e.printStackTrace();
                        // CoreLogger.logError(null,"ConfigRead.init","UM2加载配置文件um-client-migrate.properties异常",e);
                    } finally {
                        if (fis != null) {
                            try {
                                fis.close();
                            } catch (IOException e) {
                            }
                        }
                    }
                }
            }
        }
    }

    static {
        initProperties();
    }

    /**
     * 根据配置文件键获取其值
     * 
     * @param key
     *            属性名称
     * @return 属性值
     */
    public static String getPropertyValues(String key, String defaultVal) {
        String result = getPropertyValues(key);
        if (StringUtils.isBlank(result)) {
            return defaultVal;
        }
        return result;
    }

    public static String getPropertyValues(String key) {
        initProperties();
        return StringUtils.trim((String) properties.get(key));
    }
}

配置文件:

log.filter.open=true
#telphone
log.filter.list_0=(\\D1|$)(3|4|5|6|7|8|9)\\d{9}(\\D|$):4-8:mobile
#phone
log.filter.list_1=\\D((0\\d{2,3})-)?(\\d{7,8})(-(\\d{1,}))?:3-10:phone
#idNo
log.filter.list_2=\\D(\\d{14}|\\d{17})(\\d|[xX])(\\D|$):2-18:idNo
#email
log.filter.list_3=[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+:1-10:email
#soldier
log.filter.list_4=\\D[1-9]{1}(\\d{15}|\\d{18})(\\D|$):3-15:soldier
#passport
log.filter.list_5=\\D1[45][0-9]{7}|([PpSs]\\d{7})|([SsGg]\\d{8})|([GgTtSsLlQqDdAaFf]\\d{8})|([HhMm]\\d{8,10}):3-12:passport

  代码不难理解,测试输出如下:

143307_kFG7_1474131.png

后续有其他的方案或者扩展再优化吧

转载于:https://my.oschina.net/u/1474131/blog/1808154

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值