log4j 日志脱敏处理 + java properties文件加载
Java 加载Properties 配置文件:
ResourceBundle bundle = ResourceBundle.getBundle("log4j_filter"); // 不要写扩展名 .properties
LOG_FILTER_SWITH = bundle.getString("log4j.filter.swith");
LOG_FILTER_KEYS = bundle.getString("log4j.filter.keys");
// 直接在本类中使用main调用时用 Properties.class.getResourceAsStream("/log4j_filter.properties");
//Properties p = new Properties();
//p.load(in);
//LOG_FILTER_SWITH = p.getProperty("log4j.filter.swith");
//LOG_FILTER_KEYS = p.getProperty("log4j.filter.keys");
日志脱敏实现: 因为只修改了一个log4j类的调用,故日志必须是
private final static Logger logger = LogManager.getLogger(SeqConfControl.class);
20:25:02,0197 [INFO ][ ][connect to SFTP . ip:10.0.26.36; port:22;uppath:null;downpath:home/selfftp/selffile/20161209/;username:selfftp;password:********][ :][hulk.frame.sftp.SFtpTools]
21:06:16,0907 [INFO ][ ][接收到一个纯文本消息并开始传入数据库:{"data":"{\"state\":\"0\",\"hostName\":\"termfrontapp\",\"policyName\":\"check_SSPM_101\",\"stateName\":null,\"program\":null,\"entryId\":null,\"agentId\":null,\"msg\":\"{\\\"account_num\\\":\\\"62294785200****0034\\\",\\\"amount\\\":\\\"2.00\\\",\\\"channel_id\\\":\\\"01I\\\",\\\"p_trans_code\\\":\\\"1017006\\\",\\\"card_type\\\":\\\"\\\",\\\"start_time\\\":\\\"1481634017288\\\",\\\"end_time\\\":\\\"1481634017526\\\",\\\"term_id\\\":\\\"01159206\\\",\\\"ret_code\\\":\\\"ZZ\\\",\\\"ret_msg\\\":\\\"交易失败,请联系发卡方|Transaction failed, please contact the issuser\\\",\\\"trans_date_sspm\\\":\\\"20161213210017\\\",\\\"term_install_addr\\\":\\\"10.0.66.8-->10.0.54.198\\\",\\\"term_inst_id\\\":\\\"238\\\",\\\"p_trans_describe\\\":\\\"贷款还息\\\",\\\"account_id2\\\":\\\"\\\"}\",\"ip\":\"10.0.26.71\",\"policyId\":null}","taskClass":"stateAlarm"}][ :][hulk.sspm.trandataMonitor.util.ConsumerMessageListener]
21:06:16,0907 [INFO ][ ][the message to decode: {"account_num":"62294785200****0034","amount":"2.00","channel_id":"01I","p_trans_code":"1017006","card_type":"","start_time":"1481634017288","end_time":"1481634017526","term_id":"01159206","ret_code":"ZZ","ret_msg":"交易失败,请联系发卡方|Transaction failed, please contact the issuser","trans_date_sspm":"20161213210017","term_install_addr":"10.0.66.8-->10.0.54.198","term_inst_id":"238","p_trans_describe":"贷款还息","account_id2":""}]
log4j_filter.properties:
# log4j 过滤器配置文件,主要用于系统中敏感字段的脱敏 # true表示打开 false表示关闭 log4j.filter.swith=true # 要脱敏的关键字 log4j.filter.keys=password,passwd,password1,password2,account_num
自定义解析类:org.apache.logging.log4j.spi.Log4jFilter.java
package org.apache.logging.log4j.spi;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 自定义处理 日志中的敏感信息
* @author yangw1006@163.com
*
*/
public class Log4jFilter {
/**
* 日志脱敏 开关
*/
private static String LOG_FILTER_SWITH = "false";
/**
* 日志脱敏关键字
*/
private static String LOG_FILTER_KEYS = null;
static{
// 加载配置文件
try {
// 直接在本类中使用main调用时用 Properties.class.getResourceAsStream("/log4j_filter.properties");
//InputStream in =Properties.class.getClassLoader().getResourceAsStream("log4j_filter.properties");
//Properties p = new Properties();
//p.load(in);
//LOG_FILTER_SWITH = p.getProperty("log4j.filter.swith");
//LOG_FILTER_KEYS = p.getProperty("log4j.filter.keys");
ResourceBundle bundle = ResourceBundle.getBundle("log4j_filter");
LOG_FILTER_SWITH = bundle.getString("log4j.filter.swith");
LOG_FILTER_KEYS = bundle.getString("log4j.filter.keys");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 处理日志字符串,返回脱敏后的字符串
* @param msg
* @return
*/
public static String invokeMsg(final String message){
String msg = new String(message);
if("true".equals(LOG_FILTER_SWITH)){
//处理字符串
if(LOG_FILTER_KEYS!=null && LOG_FILTER_KEYS.length()>0){
String[] keyArr = LOG_FILTER_KEYS.split(",");
for(String key: keyArr){
// 找key
int index= -1;
do{
index = msg.indexOf(key, index+1);
if(index!=-1){
// 判断key是否为单词字符
if(isWordChar(msg,key,index)){
continue;
}
// 确定是单词无疑....................................
// 寻找值的开始位置.................................
int valueStart = getValueStartIndex(msg,index + key.length());
//查找值的结束位置(逗号,分号)........................
int valueEnd = getValuEndEIndex(msg,valueStart);
// 对获取的值进行脱敏
String subStr = msg.substring(valueStart, valueEnd);
subStr = tuomin(subStr);
///////////////////////////
msg = msg.substring(0,valueStart) + subStr + msg.substring(valueEnd);
}
}while(index!=-1);
}
}
}
return msg;
}
private static Pattern pattern = Pattern.compile("[0-9a-zA-Z]");
/**
* 判断从字符串msg获取的key值是否为单词 , index为key在msg中的索引值
* @return
*/
private static boolean isWordChar(String msg,String key, int index){
// 必须确定key是一个单词............................
if(index!=0){ //判断key前面一个字符
char preCh = msg.charAt(index-1);
Matcher match = pattern.matcher(preCh+"");
if(match.matches()){
return true;
}
}
//判断key后面一个字符
char nextCh = msg.charAt(index+key.length());
Matcher match = pattern.matcher(nextCh+"");
if(match.matches()){
return true;
}
return false;
}
/**
* 获取value值的开始位置
* @param msg 要查找的字符串
* @param valueStart 查找的开始位置
* @return
*/
private static int getValueStartIndex(String msg, int valueStart ){
// 寻找值的开始位置.................................
do{
char ch = msg.charAt(valueStart);
if(ch == ':' || ch == '='){ // key 与 value的分隔符
valueStart ++;
ch = msg.charAt(valueStart);
if(ch == '"'){
valueStart ++;
}
break; //找到值的开始位置
}else{
valueStart ++;
}
}while(true);
return valueStart;
}
/**
* 获取value值的结束位置
* @return
*/
private static int getValuEndEIndex(String msg,int valueEnd){
do{
if(valueEnd == msg.length()){
break;
}
char ch = msg.charAt(valueEnd);
if(ch == '"'){ // 引号时,判断下一个值是结束,分号还是逗号决定是否为值的结束
if(valueEnd+1 == msg.length()){
break;
}
char nextCh = msg.charAt(valueEnd+1);
if(nextCh ==';' || nextCh == ','){
// 去掉前面的 \ 处理这种形式的数据 "account_num\\\":\\\"6230958600001008\\\"
while(valueEnd>0 ){
char preCh = msg.charAt(valueEnd-1);
if(preCh != '\\'){
break;
}
valueEnd--;
}
break;
}else{
valueEnd ++;
}
}else if (ch ==';' || ch == ','){
break;
}else{
valueEnd ++;
}
}while(true);
return valueEnd;
}
private static String tuomin(String submsg){
StringBuffer sbResult = new StringBuffer();
if(submsg!=null && submsg.length()>0){
int len = submsg.length();
if(len > 8){ //8位以上的 隐掉中间4位
for(int i = len-1;i>=0;i--){
if(len-i<5 || len-i>8){
sbResult.insert(0, submsg.charAt(i));
}else{
sbResult.insert(0, '*');
}
}
}else{ //8位以下的全部使用 *
for(int i =0;i<len;i++){
sbResult.append('*');
}
}
}
return sbResult.toString();
}
public static void main (String[] args) {
//{\\\"account_num\\\":\\\"6230958600001008\\\",\\\"amount\\\":\\\"\\\"
String msg = "\\\"account_num\\\":\\\"6230958600001008\\\",\\\"amount\\\":\\\"\\\"";
System.out.println(invokeMsg(msg));
}
}
log4j原生类 org.apache.logging.log4j.spi.AbstractLogger.java 修改的地方
# 代码 725行左右的方法
protected void logMessage(final String fqcn, final Level level, final Marker marker, final String message, final Throwable t) {
// by yangw
String invokeMsg = Log4jFilter.invokeMsg(message);
logMessage(fqcn, level, marker, messageFactory.newMessage(invokeMsg), t);
}
log4j 日志脱敏处理 + java properties文件加载的更多相关文章
- 161216、使用spring的DefaultResourceLoader自定义properties文件加载工具类
import java.io.IOException; import java.io.InputStream; import java.util.NoSuchElementException; imp ...
- 使用spring的DefaultResourceLoader自定义properties文件加载工具类
转自:https://www.cnblogs.com/zrbfree/p/6230957.html import java.io.IOException; import java.io.InputSt ...
- Java实现配置加载机制
前言 现如今几乎大多数Java应用,例如我们耳熟能详的tomcat, struts2, netty…等等数都数不过来的软件,要满足通用性,都会提供配置文件供使用者定制功能. 甚至有一些例如Netty这 ...
- jdbc.properties不能加载到tomcat项目下面
javaweb项目的一个坑,每次重启tomcat都不能将项目中的jdbc.properties文件加载到tomcat项目对应的classes目录下面,得手动粘贴到该目录下.
- Java基础之Throwable,文件加载
Java中的异常与错误都继承自Throwable,Exception又分为运行时异常(RuntimeException)和编译时异常. 运行时异常是程序的逻辑不够严谨或者特定条件下程序出现了错误,例如 ...
- Java 使用properties配置文件加载配置
一般我们不把数据库的配置信息写死在代码中. 写好代码后,编译.调试,成功后只把输出目录中的东西(jar包..class文件.资源文件等)拷贝到服务器上,由运维来管理.服务器上是没有源文件的(.java ...
- Java中的资源文件加载方式
文件加载方式有两种: 使用文件系统自带的路径机制,一个应用程序只能有一个当前目录,但可以有Path变量来访问多个目录 使用ClassPath路径机制,类路径跟Path全局变量一样也是有多个值 在Jav ...
- Android 的 so 文件加载机制
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 最近碰到一些 so 文件问题,顺便将相关知识点梳理一下. 提问 本文的结论是跟着 System.loadlibrary() 一层层源 ...
- 插件化框架解读之so 文件加载机制(四)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 提问 本文的结论是跟着 System.loadlibrary() ...
随机推荐
- 利用css实现页面加载时旋转动画
有时浏览一些网站时在刚加载页面时候会出现一个滚动动画如下图,特别是对于一些移动端的站点或者混合应用来说应该用户体验会好很多,扒了下页面发现是用css样式控制的,于是把页面以及css样式赋值了下来, h ...
- Myeclipse和windows调节成护眼色
作为程序员,对着电脑屏幕久了,眼睛难免疲劳,下面相信对我们每个 人都很有帮助. windows xp:桌面空白处右键,属性,外观-高级,然后在项目那栏选窗口,再点颜色-其它,然后把色调设为85(默认是 ...
- C# 实例练习——字符串处理(第三天)
1. 编写程序将IP地址分解后输出(将IP地址中的点(.)去掉,替换成空格符),如:132.123.4替换后为132 123 4. Console.WriteLine("请输入您电脑 ...
- Cell
首先需要创建一个model类,继承于NSObject: 定义两个属性: @property(nonatomic,retain)NSString imageName; @property(nonatom ...
- Pyinstaller(python打包为exe文件)
需求分析: python脚本如果在没有安装python的机器上不能运行,所以将脚本打包成exe文件,降低脚本对环境的依赖性,同时运行更加迅速. 当然打包的脚本似乎不是在所有的win平台下都能使用, ...
- <经验杂谈>前端form提交导出数据
之前在做列表的是总会遇到一些导出的功能,而在做导出的时候总是习惯于用get的方法将参数放在url上,这样一来就会有很多的弊端,一是url的参数长度有限,遇到有的参数很长的时候就会报错,二是也不太安全. ...
- 2015苏州大学ACM-ICPC集训队选拔赛(3)题解
第三次校赛链接:快戳我 1001 考虑前半组数,我们只需要标记每个数出现的次数,再加上这个数之前的数出现的次数,即为这个数在m次操作中总共需要翻转的次数(即求前缀和),再根据翻转的奇偶性判断最后这个位 ...
- mysql语句的一个问题
刚才在群里有个同学提出了这么一个问题 在Mybatis的mapper文件中有一条语句这么写 说是系统不报错,也没返回,我一看句子应该没什么问题.执行的时候应该是PreparedStatement 执行 ...
- python专题-异常处理(基础)
之前在学习python的时候有整理过python异常处理的文章,不够简单也不够完整,所以决定再整理一篇,算做补充. http://www.cnblogs.com/cmt110/p/7464748.ht ...
- Android studio一些常见技巧(不断更新)
一.Android studio取消默认每次打开时打开最后一个项目 二.as添加jar包 新建一个libs目录,在java下 进行手动gragle同步或者如下图 三.代码边上的小图标 1.布局文件中存 ...