有没有办法从其 Object.inspect 方法的输出重新创建对象



在使用开源 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不是。

最新更新