草庐IT

用几行脚本解决了困扰了客户一周的需求

bellengao 2023-03-28 原文

背景

近日云上Elasticsearch的客户,提过来了一个需求,期望把上游业务的日志中的一些无用字段从ES中删除掉,这些字段的名称是固定位数的随机字符串,期望能够通过一些过滤规则删除掉这些字段。

实现方案

日志内容的示例如下:

 {
    "req":{
        "headers":{
            "host":"x.x.x.x",
            "connection":"keep-alive",
            "x-forwarded-for":"x.x.x.x",
            "x-forwarded-proto":"http",
            "x-forwarded-host":"x.com",
            "x-forwarded-port":"0000",
            "x-forwarded-path":"x",
            "x-forwarded-prefix":"y",
            "et55ouqyzettcs070zr6fq74yknotwz":"abc",
            "uuid":"xxxxx",
            "vn4qhj6ienxegvhxyf56u8wq4w6icc9":"abc"
        }
    }
}
        

客户的需求是要删除上述示例中字段名为一串随机字符串的字段,示例中有两个,实际会有更多,并且不同类型的文档,字段名还不一样。

为了实现客户的需求,首先想到的就是是使用ES的Remove Ingest Processor去删除字段,但是发现Remove Ingest Processor中的field字段不支持正则表达式,只好作罢。

通过跟客户沟通,了解到要保留的字段是确定的,因此想到可以使用Set Ingest Processor通过复制原Object字段中需要保留的字段内容到一个新的Object类型的字段中,之后再删除原Object字段。

{
    "processors":[
        {
            "set":{
                "field":"req.newHeaders.host",
                "copy_from":"req.headers.host"
            }
        },
        {
            "set":{
                "field":"req.newHeaders.connection",
                "copy_from":"req.headers.connection"
            }
        },
        {
            "remove":{
                "field":"req.headers"
            }
        },
        {
            "set":{
                "field":"req.headers",
                "copy_from":"req.newHeaders"
            }
        },
        {
            "remove":{
                "field":"req.newHeaders"
            }
        }
    ]
}

实际应用中,客户表示要保留的字段有几十个,把所有要保留的字段都set一遍会比较麻烦,后面有新增的字段,还需要再次修改ingest pipeline,期望能够比较简单易用的方式解决这个问题。

另外客户表示,要删除的字段不会太多,并且字段名称都是由31个随机字符串组成,且值都为"abc",看能不能根据这个条件删除掉不需要的字段。

在寻找解决方案的过程中,发现Logstash有类似的filter: Prune Filter Plugin, 可以直接根据字段值删除字段或者根据字段名的正则表达式删除字段:

filter {
      prune {
        blacklist_values => [ "abc"]
      }
    }
filter {
      prune {
        blacklist_names => [ "^([a-z]|[0-9]){31}$"]
      }
    }

然而客户因为没有用到Logstash,不希望单单为了去除一些无用的字段而新增一个组件,因此只能从ES的ingest pipeline入手解决。

既然ES的Remove Processor不支持通过正则表达式删除字段,也不支持通过字段的值来删除字段,那就只能使用Script Processor,通过脚本来删除了:

"processors": [
      {
        "script": {
          "description": "Remove useless fields from 'req.headers' field",
          "lang": "painless",
          "source": """
            Map map = (HashMap)ctx['req']['headers'];
            Map headersMap = new HashMap();
            for (entry in map.entrySet()){
              if (entry.getValue()!= params.value){
                headersMap.put(entry.getKey(), entry.getValue());
              }
            }
            ctx['req']['headers'] = headersMap
          """,
          "params": {
            "value": "abc"
          }
        }
      }
    ]

使用Painless脚本,把每个文档中的req.headers字段解析成map,然后遍历,使用一个新的map保存值不是"abc"的字段,然后再赋值给req.headers。经过验证,实际是可行的。

通过使用上述Script Processor, 最终实现了使用较少的配置,实现了通过字段的值来删除字段的功能,满足了客户的需求。

有关用几行脚本解决了困扰了客户一周的需求的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  3. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  4. 【高数】用拉格朗日中值定理解决极限问题 - 2

    首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

  5. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  6. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  7. ruby - 确定 ruby​​ 脚本是否已经在运行 - 2

    有没有一种简单的方法可以判断ruby​​脚本是否已经在运行,然后适本地处理它?例如:我有一个名为really_long_script.rb的脚本。我让它每5分钟运行一次。当它运行时,我想看看之前运行的是否还在运行,然后停止第二个脚本的执行。有什么想法吗? 最佳答案 ps是一种非常糟糕的方法,并且可能会出现竞争条件。传统的Unix/Linux方法是将PID写入文件(通常在/var/run中)并在启动时检查该文件是否存在。例如pid文件位于/var/run/myscript.pid然后你会在运行程序之前检查它是否存在。有一些技巧可以避免

  8. ruby - ruby 脚本可以预编译成二进制文件吗? - 2

    我正在开发一个Ruby脚本,需要在没有Ruby解释器的情况下部署到系统上。它将需要在使用ELF格式的FreeBSD系统上运行。我知道有一个ruby​​2exe项目可以编译在Windows上运行的ruby​​脚本,但是在其他操作系统上这样做容易吗?甚至可能吗? 最佳答案 您是否检查过Rubinius或JRuby是否允许您预编译您的代码? 关于ruby-ruby脚本可以预编译成二进制文件吗?,我们在StackOverflow上找到一个类似的问题: https://

  9. ruby - 如何更快地解决 project euler #21? - 2

    原始问题Letd(n)bedefinedasthesumofproperdivisorsofn(numberslessthannwhichdivideevenlyinton).Ifd(a)=bandd(b)=a,whereab,thenaandbareanamicablepairandeachofaandbarecalledamicablenumbers.Forexample,theproperdivisorsof220are1,2,4,5,10,11,20,22,44,55and110;therefored(220)=284.Theproperdivisorsof284are1,2,

  10. ruby-on-rails - Ruby 从 bash 脚本执行中捕获 stderr 输出 - 2

    我目前可以将stdout重定向到ruby​​/rails中的字符串变量,只需在bash中运行命令并将结果设置为我的字符串变量,如下所示。val=%x[#{cmd}]其中cmd是表示bash命令的字符串。但是,这仅捕获stdout,因为我想捕获stderr并将其设置为ruby​​中的字符串——有什么想法吗? 最佳答案 简单地重定向它:val=%x[#{cmd}2>&1]如果您只想从stderr捕获输出,请在将其复制到fd2后关闭stdout的文件描述符。val=%x[#{cmd}2>&1>/dev/null]

随机推荐