activejob参数写入opentelemetry的attribute
取值策略
- 基本类型都转成String吧
- activerecord对象,键取model名,值取主键值([[activerecord的id]])
- Hash要展平
- Array内如果都是同一类型,不需展开,否则展开
使用case..when..
- 优点:可以自定义优先级
- 缺点:条件判断不太优雅
调用方式
before_perform do |job|
IndexedArgs.create({ 'job.args' => job.arguments })
::Tracer.add_attrs(attrs) if attrs.present?
end
实现
module IndexedArgs
class << self
def create(arg)
case arg
when nil
{}
when String, Integer, Float, BigDecimal, TrueClass, FalseClass
{ nil => arg.to_s }
when ActiveRecord::Base
{ arg.class.name.underscore.gsub('/', '.') => arg.id }
# when GlobalID::Identification
# { nil => arg.to_global_id.to_s }
when Array
create_from_hash(arg.each_with_index.to_h.invert)
when Hash
create_from_hash(arg)
else
{}
end
end
AVAILABLE_KEY_TYPES = [String, Symbol, Integer]
def create_from_hash(h)
h.each_with_object({}) do |(k, v), hash|
next unless AVAILABLE_KEY_TYPES.any?{ |t| k.is_a?(t) }
create(v).each_pair do |sub_k, sub_v|
key = sub_k.present? ? "#{k}.#{sub_k}" : k.to_s
hash[key] = sub_v
end
end
end
end
end
使用duck-typing
- 优点:符合ruby玩法,比较优雅
- 缺点:优先级不明确
调用方式
before_perform do |job|
attrs = { 'job.args' => job.arguments }.indexed_args
::Tracer.add_attrs(attrs) if attrs.present?
end
实现
module IndexedArgs
PRIMITIVE_TYPES = [String, Integer, Float, BigDecimal, TrueClass, FalseClass]
PRIMITIVE_TYPES.each do |k|
k.define_method(:indexed_args){ { nil => to_s } }
end
module ::ActiveRecord
class Base
def indexed_args
{ self.class.name.underscore.gsub('/', '.') => id }
end
end
end
class ::Array
def indexed_args
if all?{ |e| PRIMITIVE_TYPES.any?{ |t| e.is_a?(t) } }
{ nil => map(&:to_s) }
else
each_with_index.to_h.invert.indexed_args
end
end
end
class ::Hash
INDEXABLE_KEY_TYPES = [String, Symbol, Integer]
def indexed_args
each_with_object({}) do |(k, v), hash|
next unless INDEXABLE_KEY_TYPES.any?{ |t| k.is_a?(t) }
v.indexed_args.each_pair do |sub_k, sub_v|
key = sub_k.present? ? "#{k}.#{sub_k}" : k.to_s
hash[key] = sub_v
end
end
end
end
class ::Object
def indexed_args
{}
end
end
end
写入时机
在
after_enqueue
和before_perform
都写入,这样就能根据job_id和参数查到入队和出队的足迹class ApplicationJob < ActiveJob::Base
[:after_enqueue, :before_perform].each do |callback|
send(callback) do |job|
if job.arguments.present?
attrs = { 'messaging.active_job.args' => job.arguments }.indexed_args
::Tracer.add_attrs(attrs) if attrs.present?
end
end
end
end