目录
简介
一般来说Splunk有内置的命令,但有些时候内置的命令无法完成一些特殊操作。
比如,在处理数据的时候需要对接其他系统,或者,处理数据时需要使用递归的方式处理数据等。
而此时自己定制一个符合当前需求的命令来扩展内置命令的功能就再好不过了。
既然是开发自定义命令,首先必然会有多个疑问:
- 自定义命令如何运作的?
- 使用什么语言开发自定义命令?
- 是否有现成的SDK等?
- 开发的过程中有什么主意事项?
- 有什么格式要求?
- 如何获取到系统中的数据?
- 如何将脚本处理好的数据返回给系统?
- 开发好的自定义命令脚本放在什么地方?
- 是否需要做什么配置让Splunk知道开发了自定义命令?
自定义命令如何运作的?
现在假设有如下SPL搜索语句,其中含自定义搜索命令testcmd,该命令接收两个关键参数userinfo和groupinfo,但该脚本不做任何事情,只是接收数据而后原封不动的将数据返回给Splunk:
index=main | table user, group | testcmd userinfo=user groupinfo=group | rename user as “用户”, group as “组” |
---|
其中table和rename是splunk内置命令。
SPL为Splunk搜索处理语言。
该语句运行原理如下图所示:
index=main |
---|
对应图中的最左侧放大镜图标,意为从main索引中获取搜索数据。
| table user, group |
---|
“|”为管道符,用于接收前面的数据并作为后面的命令的输入数据。
table为一个内置SPL命令。
| testcmd userinfo=user groupinfo=group |
---|
testcmd就是自定义搜索命令。
此处的自定义搜索命令由一个外置的python脚本实现。
当代码运行至此,Splunk会调用内置python环境运行该脚本,并将相关参数和数据传递给它,脚本执行完毕后将处理好的数据再返回,等待系统下一步操作。
| rename user as “用户”, group as “组” |
---|
而此时下一步操作是将脚本处理好的数据再次传递给新的SPL命令,继续处理。
rename也是一个内置SPL命令。
使用什么语言开发自定义命令?
根据上面的自定义命令运行原理图不难看出,自定义命令是由外置脚本实现其主要功能的。
至于外置脚本使用什么语言来开发,我推荐使用Python,别问那么多为什么,本人没研究过其他的。
Splunk内置了Python的环境,所以需要注意的地方是有:
- 内置Python所在位置
- 如何在后台使用内置Python
- 内置Python版本
- 内置Python使用的包和库所在位置
内置Python所在位置
$SPLUNK_HOME/bin/python
$SPLUNK_HOME是Splunk安装目录的环境变量。
如何在后台使用内置Python
$SPLUNK_HOME/bin/splunk cmd python xxx.py
此处需要注意,这和Python正常使用方式有所不同。
xxx.py代表自己写的Python脚本,但不是自定义命令脚本(自定义命令脚本有特别的格式)。
这种方式主要用于测试一些其他的需要放在Splunk中运行的Python脚本,在Splunk环境正式运行时是否会出现问题。
- 数据接入的Python脚本
- APP内的Python脚本
- add-on内的Python脚本
- 其他
内置Python版本
$SPLUNK_HOME/bin/splunk cmd python --version
内置Python使用的包和库所在位置
$SPLUNK_HOME/bin/splunk cmd python -c "import sys;print(sys.path)"
是否有现成的SDK等?
一般来说开发扩展功能之类,官方都会提供SDK来简化开发。
Splunk也同样提供了SDK(Python的),放在Splunk自己的官方Github仓库里:https://github.com/splunk/splunk-sdk-python。
该SDK可以用于开发对接Splunk的独立程序,是Splunk官方REST API的封装,可简化REST API的使用。
关于REST API可以详见:https://docs.splunk.com/Documentation/Splunk/8.1.2/RESTREF/RESTprolog。
当然本文主要说明自定义命令开发,不涉及REST API详细的部分。
自定义命令开发同样需要SDK的支持。
接下来肯定会有两个疑问就是:
- SDK去哪下载?
- SDK下载后放在放在哪?
SDK下载
访问https://github.com/splunk/splunk-sdk-python
下载Python SDK的ZIP包
从ZIP中取出要使用的lib
SDK存放位置
因为是开发自定义命令,所以刚刚取出的splunklib文件夹将存放于Splunk服务器上。
理论上来说存放在Splunk内置Python使用的包和库所在位置都可以(没测试过其他位置)。
为了方便,会和自定义命令放在同一目录之下。其中{APP_NAME}为自己的APP名字,如果没有自己的APP,放在search默认APP的目录。
$SPLUNK_HOME/etc/apps/{APP_NAME}/bin/
存放后完整的目录为:
$SPLUNK_HOME/etc/apps/{APP_NAME}/bin/splunklib
而splunklib目录内有:
开发的过程中有什么主意事项?
要说注意事项,毕竟是在Splunk的平台玩耍,主要就是要按照Splunk平台的格式来编写代码即可。
Splunk内置命令有多个不同的类型:
- distributable streaming
- centralized streaming
- transforming
- generating
- orchestrating
- dataset processing
命令类型详见:https://docs.splunk.com/Documentation/Splunk/8.1.2/Search/Typesofcommands
能开发的自定义命令类型有:
- GeneratingCommand
- StreamingCommand
- EventingCommand
- ReportingCommand
自定义命令类型详见lib中源码注释:splunklib/searchcommands/__init__.py
以下依旧使用testcmd作为例子,该自定义命令为流式命令。
流式命令,我个人的理解是:
首先所有数据为一个二维表,一行便是一个记录,每列为记录的各个元素或维度。
而流式命令每次都只处理一个记录,处理完一个记录后就可以把该记录送到下一个命令那里进行处理。
而不需要等待所有记录都在一个命令那处理完后才能送到一个命令那。
类似工厂中的流水线。
此处给出testcmd的完整Python代码示例,后面将会详细讲解:
# coding: utf-8
import sys
from splunklib.searchcommands import dispatch, StreamingCommand, Configuration, Option, validators
from splunklib import six
@Configuration()
class TestCMD(StreamingCommand):
userinfo = Option(require=True, validate=validators.Fieldname())
groupinfo = Option(require=True, validate=validators.Fieldname())
def func(self, field):
return field
def stream(self, records):
for record in records:
record[self.userinfo]
record[self.groupinfo]
for fieldname in self.fieldnames:
record[fieldname] = self.func(record[fieldname])
# record["hello"] = "一个叫hello的新字段"
yield record
dispatch(TestCMD, sys.argv, sys.stdin, sys.stdout, __name__)
有什么格式要求?
在写该脚本前可以把一些固定格式的代码保存起来作为模板,以方便以后开发新的自定义命令脚本,其中包括:
# coding: utf-8
import sys
from splunklib.searchcommands import dispatch, StreamingCommand, Configuration, Option, validators
from splunklib import six
@Configuration()
class 自定义命令的Python类名(StreamingCommand):
def stream(self, records):
for record in records:
yield record
dispatch(自定义命令的Python类名, sys.argv, sys.stdin, sys.stdout, __name__)
其中:
- @Configuration():照着写就行了
- 自定义命令的Python类名:自己定义,不要和其他自定义命令脚本里的相同即可。
- StreamingCommand:用以说明该自定义命令为一个流式命令。
- def stream(self, records):
- stream:这个自定义命令类中必须的一个函数,用来被Splunk平台调用。
- records:该参数是Splunk传递进来的所有数据,即,一个张二维表。
- yield:Python语法,自行查阅。
- dispatch:照着写就行了,注意保持和class后的自定义命令的Python类名一致即可。
如何获取到系统中的数据?
前面已经说明def stream(self, records)的用处,所以records中保存的便是系统传递过来的所有数据。
# coding: utf-8
import sys
from splunklib.searchcommands import dispatch, StreamingCommand, Configuration, Option, validators
from splunklib import six
@Configuration()
class 自定义命令的Python类名(StreamingCommand):
# 参数的类型由validate后面的参数定义,此出为validators.Fieldname(),表示参数1是一个字段名称
参数1 = Option(require=True, validate=validators.Fieldname())
参数2 = Option(require=True, validate=validators.Fieldname())
def stream(self, records):
# records是所有数据,一张二维表,则record代表二维表中的一行数据
for record in records:
# 由于参数1是一个字段名称,所以可以使用record[字段名称]的方式获取到给行数据中,该字段的值
参数1字段在该行数据中的值 = record[self.参数1]
参数2字段在该行数据中的值 = record[self.参数2]
# 如果需要取出该行数据中各个字段的值使用以下方式
# 其中self.fieldnames保存了该行数据中所有字段名称
for fieldname in self.fieldnames:
record[fieldname]
yield record
dispatch(自定义命令的Python类名, sys.argv, sys.stdin, sys.stdout, __name__)
self.参数1:self是Python语法,自行查阅。
如何将脚本处理好的数据返回给系统?
# coding: utf-8
import sys
from splunklib.searchcommands import dispatch, StreamingCommand, Configuration, Option, validators
from splunklib import six
@Configuration()
class 自定义命令的Python类名(StreamingCommand):
# 用于接收返回数据的字段名称存储在result参数中
result = Option(require=True, validate=validators.Fieldname())
def stream(self, records):
for record in records:
record[self.result] = "结果数据"
# record["NewField"] = "在该行数据中插入新的字段NewField"
# yield写在此处(for内)表示处理完一行数据就返回这行数据
yield record
# 如果需要自行定义整行数据可以使用以下格式
# yield {"字段1": "字段1的值", "字段2": "字段2的值", "字段3": "字段3的值"}
dispatch(自定义命令的Python类名, sys.argv, sys.stdin, sys.stdout, __name__)
开发好的自定义命令脚本放在什么地方?
给多个APP使用
$SPLUNK_HOME/etc/searchscripts/
如果开发的自定义命令需要给多个APP使用,放在此处。
给自己的APP使用
$SPLUNK_HOME/etc/apps/{APP_NAME}/bin/
如果开发的自定义命令只需要给自己的APP使用,放在此处即可。
{APP_NAME}:如果没有自己的APP,使用Splunk系统默认的search代替即可。
$SPLUNK_HOME/etc/apps/search/bin/
是否需要做什么配置让Splunk知道开发了自定义命令?
需要在一个叫commands.conf的配置文件中添加三行内容,这个文件在以下位置:
- $SPLUNK_HOME/etc/system/local/commands.conf
- $SPLUNK_HOME/etc/apps/{APP_NAME}/default/commands.conf
- $SPLUNK_HOME/etc/apps/{APP_NAME}/local/commands.conf
如果以上位置没有该文件,按需创建新的即可。
添加的三行内容:
[自定义命令在SPL中的名字] filename = 自定义命令Python脚本名字.py chunked = true |
---|
例如testcmd的Python脚本文件叫test_cmd.py:
[testcmd] filename = test_cmd.py chunked = true |
---|
注意:修改完成之后,在浏览器中访问https://splunk服务器地址/debug/refresh,能看到一个Refresh按钮,点击之后平台配置会重新载入,自定义命令就能使用了。不需要执行重启操作。
注意:修改完成之后,需要重启Splunk平台命令如下:
$SPLUNK_HOME/bin/splunk restart
此处有个小技巧:
如果重启完了,下次需要修改Python脚本的代码,
只要不修改commands.conf和Python脚本名称,
则可以再修改完Python脚本代码后立即生效,而不需要再重启Splunk平台。
给多个APP使用
$SPLUNK_HOME/etc/system/local/commands.conf
第1个位置是Splunk系统全局的自定义命令位置。
如果开发的自定义命令需要给多个APP使用,可以修改该文件。
脚本也要放在对应的$SPLUNK_HOME/etc/searchscripts/位置。
给自己的APP使用
$SPLUNK_HOME/etc/apps/{APP_NAME}/default/commands.conf
如果APP是你自己开发的。修改上述位置的文件。
$SPLUNK_HOME/etc/apps/{APP_NAME}/local/commands.conf
如果APP不是你开发的,你需要扩展该APP的自定义命令,则修改上述文件。
流程总结
- 先把Splunk平台搭好
- 去Github把lib下载下来,放在Splunk平台内置Python能Path到的路径里。
- 写好自定义命令Python脚本,按需放在相应位置。
- 按需在commands.conf中添加相应的内容。
- 访问https://splunk服务器地址/debug/refresh,重新载入配置,使自定义命令可用。
下面给出testcmd的完整示例:
$SPLUNK_HOME/etc/apps/search/bin/test_cmd.py内容:
# coding: utf-8
import sys
from splunklib.searchcommands import dispatch, StreamingCommand, Configuration, Option, validators
from splunklib import six
@Configuration()
class TestCMD(StreamingCommand):
userinfo = Option(require=True, validate=validators.Fieldname())
groupinfo = Option(require=True, validate=validators.Fieldname())
def func(self, field):
return field
def stream(self, records):
for record in records:
record[self.userinfo]
record[self.groupinfo]
for fieldname in self.fieldnames:
record[fieldname] = self.func(record[fieldname])
# record["hello"] = "一个叫hello的新字段"
yield record
dispatch(TestCMD, sys.argv, sys.stdin, sys.stdout, __name__)
$SPLUNK_HOME/etc/apps/search/local/commands.conf内容:
[testcmd] filename = test_cmd.py chunked = true |
---|
testcmd在search APP中的SPL语句:
index=main | table user, group | testcmd userinfo=user groupinfo=group | rename user as “用户”, group as “组” |
---|
其他
由于以上只说明了流式自定义命令的开发,其他类型的自定义命令请移步: