在使用开源 ELK 堆栈时,我们遇到了一个问题,其中一个 Logstash 输入 snmptrap 以我们无法使用的方式格式化数据。在SNMPv1_Trap类中,有一个名为agent_address
的实例变量,它存储为SNMP::IpAddress。对于熟悉 SNMP 工作方式的任何人来说,在网络上使用陷阱中继时,代理地址对于确定 SNMP 陷阱的来源非常重要。
当您查看 Logstash 在收到陷阱时生成的事件时,可以看到问题。主要是,agent_address
变量的inspect
方法是转储与任何有效数据不匹配的数据。
示例事件如下所示:
#<SNMP::SNMPv1_Trap:0x2db53346 @enterprise=[1.3.6.1.4.1.6827.10.17.3.1.1.1], @timestamp=#<SNMP::TimeTicks:0x2a643dd1 @value=0>, @varbind_list=[#<SNMP::VarBind:0x2d5043a5 @name=[1.0], @value=#<SNMP::Integer:0x29fb6a4a @value=1>>], @specific_trap=1000, @source_ip="192.168.87.228", @agent_addr=#<SNMP::IpAddress:0x227a4011 @value="\xC0\xA8V\xFE">, @generic_trap=6>
但是,我们知道,SNMP::SNMPv1_Trap中使用的 IpAddress 对象能够向我们返回一个格式良好的字符串,表示它存储的 IPv4 地址。
例如:
require 'snmp'
include SNMP
address = IpAddress.new(192.168.86.254)
puts address
将产生192.168.86.254
而
require 'snmp'
include SNMP
address = IpAddress.new(192.168.86.254)
puts address.inspect
将产生:
#<SNMP::IpAddress:0x0000000168ae88 @value="xC0xA8VxFE">
这是其.inspect
方法尚未重写的对象的预期行为。
显然,@value中的IPv4地址对我们没有用,它只有三个有效的十六进制序列(xC0 = 192,xA8 = 168,xFE= 254),并且还包含一个无效的十六进制序列("V")。每当表示IPv4地址的八位字节字符串也作为变量绑定发送时,都会发生同样的事情,这表明了一些奇怪的编码。
不幸的是,除了编写我们自己的SNMP输入之外,没有接口级访问这个对象。我们通过"event"接收的对象包含检查字符串,而不是对象本身。因此,获取所需信息的最简单方法是重建SNMPv1_Trap对象,然后通过Object.#send
对其进行自己的调用。
如果我有 Object.#inspect
返回的原始、未格式化和默认字符串转储,有没有办法在物理上重新创建用于即时进行此检查转储的对象?
例如,给定字符串转储:
#<Integer:0x2737476 @value=1>
是否可以使用值为 1 的字段重新创建 Integer 对象?如果这是可能的,有没有办法以相同的方式重新创建嵌套对象?例如,给定字符串:
#<SNMP::SNMPv1_Trap:0x2ef73621 @value=1, @agent_address=#<SNMP::IpAddress:0x0000000168ae88 @value="xC0xA8VxFE">>
是否有可能有一个如下所示的对象?
SNMP::SNMPv1_Trap{
@value : 1
@agent_address : SNMP::IpAddress{
@value : 1
}
}
如果我有
Object#inspect
返回的原始、未格式化和默认字符串转储,有没有办法在物理上重新创建用于动态进行此检查转储的对象?
不。 inspect
用于调试目的,以供人类读取。
它不保证是机器可读的。不能保证在不同的 Ruby 版本中是相同的。不能保证在不同的 Ruby 实现中是相同的。它甚至不能保证在实现相同 Ruby 版本的同一 Ruby 实现的不同版本之间是相同的。哎呀,我什至不认为两次运行保证相同!
它不是序列化格式。
有很多专门针对Ruby(Marshal
)或通用(XML,YAML,JSON,当然还有ASN.1)的序列化格式,但inspect
不是。