在某些系統中,對於一些敏感信息(手機號,身份證號等),不宜直接打印到日誌中,須要對這些敏感信息作打碼處理,這裏提供一個簡單的示例。java
通常狀況,在輸出日誌時,系統會對log框架作一個簡單的封裝(相似對exception封裝),將經常使用的debug,info,error等統一封裝在logUtil中,系通通一調用。因此能夠在這裏作一個擴展,將日誌先行處理,再調用日誌框架輸出,便可實現打碼效果。正則表達式
調用日誌輸出:redis
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");
日誌工具類:spring
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; } }
日誌攔截類:apache
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; } }
日誌攔截實體類:json
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
代碼不難理解,測試輸出以下:測試
後續有其餘的方案或者擴展再優化吧優化