class TDAnalytics::Tracker

TDAnalytics::Tracker 是数据上报的核心类,使用此类上报事件数据和更新用户属性. 创建 Tracker 类需要传入 consumer 对象,consumer 决定了如何处理格式化的数据(存储在本地日志文件还是上传到服务端).

ta = TDAnalytics::Tracker.new(consumer)
ta.track('your_event', distinct_id: 'distinct_id_of_user')

TDAnalytics 提供了三种 consumer 实现:

LoggerConsumer: 数据写入本地文件
DebugConsumer: 数据逐条、同步的发送到服务端,并返回详细的报错信息
BatchConsumer: 数据批量、同步的发送到服务端

您也可以传入自己实现的 Consumer,只需实现以下接口:

add(message): 接受 hash 类型的数据对象
flush: (可选) 将缓冲区的数据发送到指定地址
close: (可选) 程序退出时用户可以主动调用此接口以保证安全退出

Constants

LIB_PROPERTIES

Public Class Methods

new(consumer, error_handler = nil, uuid: false) click to toggle source

SDK 构造函数,传入 consumer 对象

默认情况下,除参数不合法外,其他 Error 会被忽略,如果您希望自己处理接口调用中的 Error,可以传入自定义的 error handler. ErrorHandler 的定义可以参考 thinkingdata-ruby/errors.rb

uuid 如果为 true,每条数据都会被带上随机 UUID 作为 uuid 属性的值上报,该值不会入库,仅仅用于后台做数据重复检测

# File lib/thinkingdata-ruby/tracker.rb, line 34
def initialize(consumer, error_handler = nil, uuid: false)
  @error_handler = error_handler || ErrorHandler.new
  @consumer = consumer
  @super_properties = {}
  @uuid = uuid
end

Public Instance Methods

clear_super_properties() click to toggle source

清除公共事件属性

# File lib/thinkingdata-ruby/tracker.rb, line 58
def clear_super_properties
  @super_properties = {}
end
close() click to toggle source

退出前调用,保证 Consumer 安全退出

# File lib/thinkingdata-ruby/tracker.rb, line 293
def close
  return true unless defined? @consumer.close
  ret = true
  begin
    @consumer.close
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    ret = false
  end
  ret
end
flush() click to toggle source

立即上报数据,对于 BatchConsumer 会触发上报

# File lib/thinkingdata-ruby/tracker.rb, line 280
def flush
  return true unless defined? @consumer.flush
  ret = true
  begin
    @consumer.flush
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    ret = false
  end
  ret
end
set_super_properties(properties, skip_local_check = false) click to toggle source

设置公共事件属性,公共事件属性是所有事件都会带上的属性. 此方法会将传入的属性与当前公共属性合并. 如果希望跳过本地格式校验,可以传入值为 true 的 skip_local_check 参数

# File lib/thinkingdata-ruby/tracker.rb, line 43
def set_super_properties(properties, skip_local_check = false)
  unless skip_local_check || _check_properties(:track, properties)
    @error_handler.handle(IllegalParameterError.new("Invalid super properties"))
    return false
  end
  properties.each do |k, v|
    if v.is_a?(Time)
      @super_properties[k] = _format_time(v)
    else
      @super_properties[k] = v
    end
  end
end
track(event_name: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil,first_check_id:nil, skip_local_check: false) click to toggle source

上报事件. 每个事件都包含一个事件名和 Hash 对象的时间属性. 其参数说明如下:

event_name: (必须) 事件名 必须是英文字母开头,可以包含字母、数字和 _, 长度不超过 50 个字符.
distinct_id: (可选) 访客 ID
account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
properties: (可选) Hash 事件属性。支持四种类型的值:字符串、数值、Time、boolean
time: (可选)Time 事件发生时间,如果不传默认为系统当前时间
ip: (可选) 事件 IP,如果传入 IP 地址,后端可以通过 IP 地址解析事件发生地点
skip_local_check: (可选) boolean 表示是否跳过本地检测
# File lib/thinkingdata-ruby/tracker.rb, line 70
def track(event_name: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil,first_check_id:nil, skip_local_check: false)
  begin
    _check_name event_name
    _check_id(distinct_id, account_id)
    unless skip_local_check
      _check_properties(:track, properties)
    end
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  data = {}
  data[:event_name] = event_name
  data[:distinct_id] = distinct_id if distinct_id
  data[:account_id] = account_id if account_id
  data[:time] = time if time
  data[:ip] = ip if ip
  data[:first_check_id] = first_check_id if first_check_id
  data[:properties] = properties

  _internal_track(:track, data)
end
track_overwrite(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false) click to toggle source

上报事件数据可进行更新. 每个事件都包含一个事件名和事件ID以及 Hash 对象的时间属性. 其参数说明如下: event_name: (必须) 事件名 必须是英文字母开头,可以包含字母、数字和 _, 长度不超过 50 个字符. event_id:(必须) event_name + event_id 会作为一条事件的唯一键 distinct_id: (可选) 访客 ID account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空 properties: (可选) Hash 事件属性。支持四种类型的值:字符串、数值、Time、boolean time: (可选)Time 事件发生时间,如果不传默认为系统当前时间 ip: (可选) 事件 IP,如果传入 IP 地址,后端可以通过 IP 地址解析事件发生地点 skip_local_check: (可选) boolean 表示是否跳过本地检测

# File lib/thinkingdata-ruby/tracker.rb, line 103
def track_overwrite(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
  begin
    _check_name event_name
    _check_event_id event_id
    _check_id(distinct_id, account_id)
    unless skip_local_check
      _check_properties(:track_overwrite, properties)
    end
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  data = {}
  data[:event_name] = event_name
  data[:event_id] = event_id
  data[:distinct_id] = distinct_id if distinct_id
  data[:account_id] = account_id if account_id
  data[:time] = time if time
  data[:ip] = ip if ip
  data[:properties] = properties
  _internal_track(:track_overwrite, data)
end
track_update(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false) click to toggle source

上报事件数据可进行覆盖. 每个事件都包含一个事件名和事件ID以及 Hash 对象的时间属性. 其参数说明如下: event_name: (必须) 事件名 必须是英文字母开头,可以包含字母、数字和 _, 长度不超过 50 个字符. event_id:(必须) event_name + event_id 会作为一条事件的唯一键 distinct_id: (可选) 访客 ID account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空 properties: (可选) Hash 事件属性。支持四种类型的值:字符串、数值、Time、boolean time: (可选)Time 事件发生时间,如果不传默认为系统当前时间 ip: (可选) 事件 IP,如果传入 IP 地址,后端可以通过 IP 地址解析事件发生地点 skip_local_check: (可选) boolean 表示是否跳过本地检测

# File lib/thinkingdata-ruby/tracker.rb, line 138
def track_update(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
  begin
    _check_name event_name
    _check_event_id event_id
    _check_id(distinct_id, account_id)
    unless skip_local_check
      _check_properties(:track_update, properties)
    end
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  data = {}
  data[:event_name] = event_name
  data[:event_id] = event_id
  data[:distinct_id] = distinct_id if distinct_id
  data[:account_id] = account_id if account_id
  data[:time] = time if time
  data[:ip] = ip if ip
  data[:properties] = properties
  _internal_track(:track_update, data)
end
user_add(distinct_id: nil, account_id: nil, properties: {}) click to toggle source

累加用户属性, 如果用户属性不存在,则会设置为 0,然后再累加

distinct_id: (可选) 访客 ID
account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
properties: (可选) Hash 数值类型的用户属性
# File lib/thinkingdata-ruby/tracker.rb, line 248
def user_add(distinct_id: nil, account_id: nil, properties: {})
  begin
    _check_id(distinct_id, account_id)
    _check_properties(:user_add, properties)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  _internal_track(:user_add,
                  distinct_id: distinct_id,
                  account_id: account_id,
                  properties: properties,
  )
end
user_append(distinct_id: nil, account_id: nil, properties: {}) click to toggle source

追加用户的一个或多个列表类型的属性

# File lib/thinkingdata-ruby/tracker.rb, line 202
def user_append(distinct_id: nil, account_id: nil, properties: {})
  begin
    _check_id(distinct_id, account_id)
    _check_properties(:user_append, properties)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  _internal_track(:user_append,
                  distinct_id: distinct_id,
                  account_id: account_id,
                  properties: properties,
                  )
end
user_del(distinct_id: nil, account_id: nil) click to toggle source

删除用户,用户之前的事件数据不会被删除

# File lib/thinkingdata-ruby/tracker.rb, line 265
def user_del(distinct_id: nil, account_id: nil)
  begin
    _check_id(distinct_id, account_id)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  _internal_track(:user_del,
                  distinct_id: distinct_id,
                  account_id: account_id,
  )
end
user_set(distinct_id: nil, account_id: nil, properties: {}, ip: nil) click to toggle source

设置用户属性. 如果出现同名属性,则会覆盖之前的值.

distinct_id: (可选) 访客 ID
account_id: (可选) 账号ID distinct_id 和 account_id 不能同时为空
properties: (可选) Hash 用户属性。支持四种类型的值:字符串、数值、Time、boolean
# File lib/thinkingdata-ruby/tracker.rb, line 166
def user_set(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
  begin
    _check_id(distinct_id, account_id)
    _check_properties(:user_set, properties)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  _internal_track(:user_set,
                  distinct_id: distinct_id,
                  account_id: account_id,
                  properties: properties,
                  ip: ip,
  )
end
user_set_once(distinct_id: nil, account_id: nil, properties: {}, ip: nil) click to toggle source

设置用户属性. 如果有重名属性,则丢弃, 参数与 user_set 相同

# File lib/thinkingdata-ruby/tracker.rb, line 184
def user_set_once(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
  begin
    _check_id(distinct_id, account_id)
    _check_properties(:user_setOnce, properties)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  _internal_track(:user_setOnce,
                  distinct_id: distinct_id,
                  account_id: account_id,
                  properties: properties,
                  ip: ip,
  )
end
user_unset(distinct_id: nil, account_id: nil, property: nil) click to toggle source

删除用户属性, property 可以传入需要删除的用户属性的 key 值,或者 key 值数组

# File lib/thinkingdata-ruby/tracker.rb, line 219
def user_unset(distinct_id: nil, account_id: nil, property: nil)
  properties = {}
  if property.is_a?(Array)
    property.each do |k|
      properties[k] = 0
    end
  else
    properties[property] = 0
  end

  begin
    _check_id(distinct_id, account_id)
    _check_properties(:user_unset, properties)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    return false
  end

  _internal_track(:user_unset,
                  distinct_id: distinct_id,
                  account_id: account_id,
                  properties: properties,
  )
end

Private Instance Methods

_check_event_id(event_id) click to toggle source
# File lib/thinkingdata-ruby/tracker.rb, line 355
def _check_event_id(event_id)
  raise IllegalParameterError.new("the event_id or property cannot be nil") if event_id.nil?
  true
end
_check_id(distinct_id, account_id) click to toggle source

检查用户 ID 合法性

# File lib/thinkingdata-ruby/tracker.rb, line 398
def _check_id(distinct_id, account_id)
  raise IllegalParameterError.new("account id or distinct id must be provided.") if distinct_id.nil? && account_id.nil?
end
_check_name(name) click to toggle source

属性名或者事件名检查

# File lib/thinkingdata-ruby/tracker.rb, line 361
def _check_name(name)
  raise IllegalParameterError.new("the name of event or property cannot be nil") if name.nil?

  unless name.instance_of?(String) || name.instance_of?(Symbol)
    raise IllegalParameterError.new("#{name} is invalid. It must be String or Symbol")
  end
  true
end
_check_properties(type, properties) click to toggle source

属性类型检查

# File lib/thinkingdata-ruby/tracker.rb, line 371
def _check_properties(type, properties)
  unless properties.instance_of? Hash
    return false
  end

  properties.each do |k, v|
    _check_name k
    next if v.nil?
    unless v.is_a?(Integer) || v.is_a?(Float) || v.is_a?(Symbol) || v.is_a?(String) || v.is_a?(Time) || !!v == v || v.is_a?(Array)
      raise IllegalParameterError.new("The value of properties must be type in Integer, Float, Symbol, String, Array,and Time")
    end

    if type == :user_add
      raise IllegalParameterError.new("Property value for user add must be numbers") unless v.is_a?(Integer) || v.is_a?(Float)
    end
    if v.is_a?(Array)
      v.each_index do |i|
        if v[i].is_a?(Time)
          v[i] = _format_time(v[i])
        end
      end
    end
  end
  true
end
_format_time(time) click to toggle source

将 Time 类型格式化为数数指定格式的字符串

# File lib/thinkingdata-ruby/tracker.rb, line 351
def _format_time(time)
  time.strftime("%Y-%m-%d %H:%M:%S.#{((time.to_f * 1000.0).to_i % 1000).to_s.rjust(3, "0")}")
end
_internal_track(type, properties: {}, event_name: nil, event_id:nil, account_id: nil, distinct_id: nil, ip: nil,first_check_id: nil, time: Time.now) click to toggle source

出现异常的时候返回 false, 否则 true

# File lib/thinkingdata-ruby/tracker.rb, line 308
def _internal_track(type, properties: {}, event_name: nil, event_id:nil, account_id: nil, distinct_id: nil, ip: nil,first_check_id: nil, time: Time.now)
  if account_id == nil && distinct_id == nil
    raise IllegalParameterError.new('account id or distinct id must be provided.')
  end

  if type == :track || type == :track_update || type == :track_overwrite
    raise IllegalParameterError.new('event name is empty') if event_name == nil
    properties = {'#zone_offset': time.utc_offset / 3600.0}.merge(LIB_PROPERTIES).merge(@super_properties).merge(properties)
  end

  # 格式化 Time 类型
  properties.each do |k, v|
    if v.is_a?(Time)
      properties[k] = _format_time(v)
    end
  end

  data = {
      '#type' => type,
      '#time' => _format_time(time),
      'properties' => properties,
  }

  data['#event_name'] = event_name if (type == :track || type == :track_update || :track_overwrite)
  data['#event_id'] = event_id if (type == :track_update || type == :track_overwrite)
  data['#account_id'] = account_id if account_id
  data['#distinct_id'] = distinct_id if distinct_id
  data['#ip'] = ip if ip
  data['#first_check_id'] = first_check_id if first_check_id
  data['#uuid'] = SecureRandom.uuid if @uuid

  ret = true
  begin
    @consumer.add(data)
  rescue TDAnalyticsError => e
    @error_handler.handle(e)
    ret = false
  end

  ret
end