当前位置:首页 > 文章列表 > 文章 > java教程 > 使用正则表达式在java中使用logstash logback屏蔽日志

使用正则表达式在java中使用logstash logback屏蔽日志

来源:dev.to 2024-11-23 20:37:34 0浏览 收藏

“纵有疾风来,人生不言弃”,这句话送给正在学习文章的朋友们,也希望在阅读本文《使用正则表达式在java中使用logstash logback屏蔽日志》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新文章相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!

在当今数据驱动的世界中,数据安全最为重要。日志框架在应用程序监控和调试中发挥着至关重要的作用,但它们可能会无意中暴露不应该暴露的敏感信息。日志屏蔽是一种有效混淆日志消息中敏感数据、保护机密信息的技术。

了解日志回溯

logback 是 java 应用程序中功能强大且最常用的日志框架。它提供灵活的配置选项,包括将日志事件格式化为 json 对象的能力。它是 log4j 框架的继承者,由于其功能和易用性而迅速流行起来。它由 logger、encoders、layout、appender、encoder 组成。

logger: logger 是日志消息的上下文。应用程序将与此类交互以创建日志消息。

编码器: 编码器是在 logback 0.9.91 中引入的,负责将事件转换为字节数组以及将该字节数组写入 outputstream。作为布局引入的编码器只能将事件转换为字符串,这将其范围限制为非二进制输出。

布局: 布局负责根据用户的意愿格式化日志请求,而附加程序负责将格式化的输出发送到其目的地。

appenders: 在 logback 中,输出目的地称为 appender。这会将日志消息放置在其最终目的地中。一个 logger 可以有多个 appender。目前,控制台、文件、远程套接字服务器、mysql、postgresql、oracle 和其他数据库、jms 和远程 unix syslog 守护进程都存在附加程序。

关于 logstash logback 编码器

logstash-logback-encoder 库是增强 spring boot 应用程序日志记录功能的宝贵工具。它提供了一种以结构化 json 格式格式化日志消息的便捷方法,使日志聚合和分析工具(例如 logstash)可以轻松使用它们。 json 格式提供了一种结构化且机器可读的方式来记录信息,使其成为高级日志分析和安全措施的理想选择。 logstash 的好处

  • json 自定义 logstash 允许您自定义 json 输出以包含特定字段和元数据。

  • 动态字段它还允许根据应用程序上下文动态添加字段来记录事件。

  • 提高了可读性 json 格式为日志事件提供了清晰且易于阅读的结构。

  • 增强的搜索和分析日志聚合工具可以轻松解析和查询 json 日志。

  • 机器解析 json 日志非常适合自动分析和警报系统。

屏蔽日志数据的解决方案

这里的主要目标是提供一种解决方案来屏蔽可在运行时定制和配置的数据。

这是我们的简单要求

  1. 在日志中完全屏蔽密码。
  2. 屏蔽电话号码和登录名,日志中最后 5 位除外。

第 1 步
创建 spring boot 应用程序。该解决方案将适用于任何基于 java 的应用程序,只需很少的定制。

第 2 步
配置所有正则表达式以屏蔽数据。请记住,正则表达式在资源利用率方面的成本很高。确保您正在调整正则表达式。正则表达式组将允许我们从字符串中选择所需的子字符串。

使用正则表达式在java中使用logstash logback屏蔽日志

第三步
创建一个类并实现 messagejsonprovider。该接口来自logstash,允许我们在打印到附加程序之前自定义消息。每个日志消息都会调用此接口中的 writeto 方法。

  • 在start()方法中读取所有正则表达式并准备包含所有maskingrule的logmasker。该方法来自 abstractjsonprovider,只是将进程启动标记为 true。

  • maskingrule 将保存正则表达式模式和一个函数。此函数替换日志中识别的字符串。

@data
public class maskingmessagingprovider extends messagejsonprovider {

    public static final string default_rules_delimiter = ",";
    private logmasker logmasker;
    private string rules;

    public maskingmessagingprovider() {
        super();
    }

    @override
    public void start() {
        super.start();
        this.logmasker = logmasker.create(stringutils.tokenizetostringarray(rules, default_rules_delimiter));
    }

    @override
    public void writeto(jsongenerator generator, iloggingevent event) throws ioexception {

        if (isstarted()) {
            jsonwritingutils.writestringfield(generator, getfieldname(), logmasker.mask(event.getformattedmessage()));
        }
    }
}

class logmasker {

    private maskingrule[] masks;

    public logmasker(maskingrule[] masks) {
        super();
        this.masks = masks.clone();
    }

    public static logmasker create(string[] rules) {

        return new logmasker(arrays.stream(rules).map(rule -> maskingrule.create(rule)).toarray(maskingrule[]::new));
    }

    public string mask(string input) {
        string transformed = input;
        for (maskingrule m : masks) {
            transformed = m.mask(transformed);
        }
        return transformed;
    }
}

class maskingrule {
    public static final int reg_ex_default_group_selector = 2;
    public static final string default_replacement = "*";

    private pattern pattern;
    private unaryoperator replacement;

    public maskingrule(pattern maskpattern, unaryoperator replacement) {
        super();
        this.pattern = maskpattern;
        this.replacement = replacement;
    }

    public static maskingrule create(string rule) {
        return new maskingrule(pattern.compile(rule), (in) -> maskingrule.maskdatawithreplacement(in, default_replacement));
    }

    public string mask(string transformed) {
        matcher matcher = pattern.matcher(transformed);
        stringbuffer sb = new stringbuffer();
        while (matcher.find()) {
            matcher.appendreplacement(sb, replacement.apply(getdatatobemasked(matcher)));
        }
        matcher.appendtail(sb);
        return sb.tostring();
    }

    private static string maskdatawithreplacement(string input, string replacement) {
        int repetition = !stringutils.haslength(input) ? 0 : input.length();
        return string.join("", collections.ncopies(repetition, replacement));
    }

    private static string getdatatobemasked(matcher matcher) {
        if (matcher.groupcount() > 1) {
            return matcher.group(reg_ex_default_group_selector);
        }
        return matcher.groupcount() > 0 ? matcher.group(1) : "";
    }
}

步骤 4
在 logback-spring.xml 文件中配置类。


    
    
        
            
                
                    ${rules}
                    ${rulesdelimiter}
                    ${ruledelimiter}
                
                
                
                
                
                
                
                
            
        
    
    
        
    

步骤 5
运行应用程序。为简单起见,我采用了一个保存数据的字符串并在应用程序启动时打印它。

@SpringBootApplication
@Slf4j
public class LogDataMaskingApplication {

    public static void main(String[] args) {
        SpringApplication.run(LogDataMaskingApplication.class, args);
        LogDataMaskingApplication.maskingTest();
    }

    public static void maskingTest() {
        String data = "{\"loginName\":\"maskingtest\",\"phoneNumber\":\"9898981212\",\"password\":\"Masking@123\"}";
        log.info(data);
    }

}

使用正则表达式在java中使用logstash logback屏蔽日志

这是非常基本的解决方案,并且根据消息摘要等要求有很大的增强空间...

您可以在 github 上找到代码。

如有任何问题请留言。

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于文章的相关知识,也可关注golang学习网公众号。

版本声明
本文转载于:dev.to 如有侵犯,请联系study_golang@163.com删除
InputStream 中 read() 和 readNBytes() 的区别:它们如何处理文件末尾和读取字节数?InputStream 中 read() 和 readNBytes() 的区别:它们如何处理文件末尾和读取字节数?
上一篇
InputStream 中 read() 和 readNBytes() 的区别:它们如何处理文件末尾和读取字节数?
揭秘电脑内核:CPU的位置与功能详解
下一篇
揭秘电脑内核:CPU的位置与功能详解
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 笔灵AI生成答辩PPT:高效制作学术与职场PPT的利器
    笔灵AI生成答辩PPT
    探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
    24次使用
  • 知网AIGC检测服务系统:精准识别学术文本中的AI生成内容
    知网AIGC检测服务系统
    知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
    38次使用
  • AIGC检测服务:AIbiye助力确保论文原创性
    AIGC检测-Aibiye
    AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
    38次使用
  • 易笔AI论文平台:快速生成高质量学术论文的利器
    易笔AI论文
    易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
    50次使用
  • 笔启AI论文写作平台:多类型论文生成与多语言支持
    笔启AI论文写作平台
    笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
    41次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码