class Segment::Analytics::Client

Public Class Methods

new(opts = {}) click to toggle source

@param [Hash] opts @option opts [String] :write_key Your project's write_key @option opts [FixNum] :max_queue_size Maximum number of calls to be

remain queued.

@option opts [Proc] :on_error Handles error calls from the API.

# File lib/segment/analytics/client.rb, line 20
def initialize(opts = {})
  symbolize_keys!(opts)

  @queue = Queue.new
  @write_key = opts[:write_key]
  @max_queue_size = opts[:max_queue_size] || Defaults::Queue::MAX_SIZE
  @options = opts
  @worker_mutex = Mutex.new
  @worker = Worker.new(@queue, @write_key, @options)

  check_write_key!

  at_exit { @worker_thread && @worker_thread[:should_exit] = true }
end

Public Instance Methods

alias(attrs) click to toggle source

Aliases a user from one id to another

@see segment.com/docs/sources/server/ruby/#alias

@param [Hash] attrs @option attrs [Hash] :context ({}) @option attrs [Hash] :integrations What integrations this must be

sent to (optional)

@option attrs [Hash] :options Options such as user traits (optional) @option attrs [String] :previous_id The ID to alias from @option attrs [Time] :timestamp When the alias occurred (optional) @option attrs [String] :user_id The ID to alias to @option attrs [String] :message_id ID that uniquely identifies a

message across the API. (optional)
# File lib/segment/analytics/client.rb, line 161
def alias(attrs)
  symbolize_keys! attrs

  from = attrs[:previous_id]
  to = attrs[:user_id]
  timestamp = attrs[:timestamp] || Time.new
  context = attrs[:context] || {}
  message_id = attrs[:message_id].to_s if attrs[:message_id]

  check_presence! from, 'previous_id'
  check_presence! to, 'user_id'
  check_timestamp! timestamp
  add_context context

  enqueue({
    :previousId => from,
    :userId => to,
    :integrations => attrs[:integrations],
    :context => context,
    :options => attrs[:options],
    :messageId => message_id,
    :timestamp => datetime_in_iso8601(timestamp),
    :type => 'alias'
  })
end
flush() click to toggle source

Synchronously waits until the worker has flushed the queue.

Use only for scripts which are not long-running, and will specifically exit

# File lib/segment/analytics/client.rb, line 39
def flush
  while !@queue.empty? || @worker.is_requesting?
    ensure_worker_running
    sleep(0.1)
  end
end
group(attrs) click to toggle source

Associates a user identity with a group.

@see segment.com/docs/sources/server/ruby/#group

@param [Hash] attrs @option attrs [String] :anonymous_id ID for a user when you don't know

who they are yet. (optional but you must provide either an
`anonymous_id` or `user_id`)

@option attrs [Hash] :context ({}) @option attrs [String] :group_id The ID of the group @option attrs [Hash] :integrations What integrations this event

goes to (optional)

@option attrs [Hash] :options Options such as user traits (optional) @option attrs [Time] :timestamp When the event occurred (optional) @option attrs [String] :user_id The ID for the user that is part of

the group

@option attrs [String] :message_id ID that uniquely identifies a

message across the API. (optional)
# File lib/segment/analytics/client.rb, line 205
def group(attrs)
  symbolize_keys! attrs
  check_user_id! attrs

  group_id = attrs[:group_id]
  user_id = attrs[:user_id]
  traits = attrs[:traits] || {}
  timestamp = attrs[:timestamp] || Time.new
  context = attrs[:context] || {}
  message_id = attrs[:message_id].to_s if attrs[:message_id]

  raise ArgumentError, '.traits must be a hash' unless traits.is_a? Hash
  isoify_dates! traits

  check_presence! group_id, 'group_id'
  check_timestamp! timestamp
  add_context context

  enqueue({
    :groupId => group_id,
    :userId => user_id,
    :traits => traits,
    :integrations => attrs[:integrations],
    :options => attrs[:options],
    :context => context,
    :messageId => message_id,
    :timestamp => datetime_in_iso8601(timestamp),
    :type => 'group'
  })
end
identify(attrs) click to toggle source

Identifies a user

@see segment.com/docs/sources/server/ruby/#identify

@param [Hash] attrs @option attrs [String] :anonymous_id ID for a user when you don't know

who they are yet. (optional but you must provide either an
`anonymous_id` or `user_id`)

@option attrs [Hash] :context ({}) @option attrs [Hash] :integrations What integrations this event

goes to (optional)

@option attrs [Hash] :options Options such as user traits (optional) @option attrs [Time] :timestamp When the event occurred (optional) @option attrs [Hash] :traits User traits (optional) @option attrs [String] :user_id The ID for this user in your database

(optional but you must provide either an `anonymous_id` or `user_id`)

@option attrs [String] :message_id ID that uniquely identifies a

message across the API. (optional)
# File lib/segment/analytics/client.rb, line 118
def identify(attrs)
  symbolize_keys! attrs
  check_user_id! attrs

  traits = attrs[:traits] || {}
  timestamp = attrs[:timestamp] || Time.new
  context = attrs[:context] || {}
  message_id = attrs[:message_id].to_s if attrs[:message_id]

  check_timestamp! timestamp

  raise ArgumentError, 'Must supply traits as a hash' unless traits.is_a? Hash
  isoify_dates! traits

  add_context context

  enqueue({
    :userId => attrs[:user_id],
    :anonymousId => attrs[:anonymous_id],
    :integrations => attrs[:integrations],
    :context => context,
    :traits => traits,
    :options => attrs[:options],
    :messageId => message_id,
    :timestamp => datetime_in_iso8601(timestamp),
    :type => 'identify'
  })
end
page(attrs) click to toggle source

Records a page view

@see segment.com/docs/sources/server/ruby/#page

@param [Hash] attrs @option attrs [String] :anonymous_id ID for a user when you don't know

who they are yet. (optional but you must provide either an
`anonymous_id` or `user_id`)

@option attrs [String] :category The page category (optional) @option attrs [Hash] :context ({}) @option attrs [Hash] :integrations What integrations this event

goes to (optional)

@option attrs [String] :name Name of the page @option attrs [Hash] :options Options such as user traits (optional) @option attrs [Hash] :properties Page properties (optional) @option attrs [Time] :timestamp When the pageview occurred (optional) @option attrs [String] :user_id The ID of the user viewing the page @option attrs [String] :message_id ID that uniquely identifies a

message across the API. (optional)
# File lib/segment/analytics/client.rb, line 255
def page(attrs)
  symbolize_keys! attrs
  check_user_id! attrs

  name = attrs[:name].to_s
  properties = attrs[:properties] || {}
  timestamp = attrs[:timestamp] || Time.new
  context = attrs[:context] || {}
  message_id = attrs[:message_id].to_s if attrs[:message_id]

  raise ArgumentError, '.properties must be a hash' unless properties.is_a? Hash
  isoify_dates! properties

  check_timestamp! timestamp
  add_context context

  enqueue({
    :userId => attrs[:user_id],
    :anonymousId => attrs[:anonymous_id],
    :name => name,
    :category => attrs[:category],
    :properties => properties,
    :integrations => attrs[:integrations],
    :options => attrs[:options],
    :context => context,
    :messageId => message_id,
    :timestamp => datetime_in_iso8601(timestamp),
    :type => 'page'
  })
end
queued_messages() click to toggle source

@return [Fixnum] number of messages in the queue

# File lib/segment/analytics/client.rb, line 335
def queued_messages
  @queue.length
end
screen(attrs) click to toggle source

Records a screen view (for a mobile app)

@param [Hash] attrs @option attrs [String] :anonymous_id ID for a user when you don't know

who they are yet. (optional but you must provide either an
`anonymous_id` or `user_id`)

@option attrs [String] :category The screen category (optional) @option attrs [Hash] :context ({}) @option attrs [Hash] :integrations What integrations this event

goes to (optional)

@option attrs [String] :name Name of the screen @option attrs [Hash] :options Options such as user traits (optional) @option attrs [Hash] :properties Page properties (optional) @option attrs [Time] :timestamp When the pageview occurred (optional) @option attrs [String] :user_id The ID of the user viewing the screen @option attrs [String] :message_id ID that uniquely identifies a

message across the API. (optional)
# File lib/segment/analytics/client.rb, line 303
def screen(attrs)
  symbolize_keys! attrs
  check_user_id! attrs

  name = attrs[:name].to_s
  properties = attrs[:properties] || {}
  timestamp = attrs[:timestamp] || Time.new
  context = attrs[:context] || {}
  message_id = attrs[:message_id].to_s if attrs[:message_id]

  raise ArgumentError, '.properties must be a hash' unless properties.is_a? Hash
  isoify_dates! properties

  check_timestamp! timestamp
  add_context context

  enqueue({
    :userId => attrs[:user_id],
    :anonymousId => attrs[:anonymous_id],
    :name => name,
    :properties => properties,
    :category => attrs[:category],
    :options => attrs[:options],
    :integrations => attrs[:integrations],
    :context => context,
    :messageId => message_id,
    :timestamp => timestamp.iso8601,
    :type => 'screen'
  })
end
track(attrs) click to toggle source

Tracks an event

@see segment.com/docs/sources/server/ruby/#track

@param [Hash] attrs @option attrs [String] :anonymous_id ID for a user when you don't know

who they are yet. (optional but you must provide either an
`anonymous_id` or `user_id`)

@option attrs [Hash] :context ({}) @option attrs [String] :event Event name @option attrs [Hash] :integrations What integrations this event

goes to (optional)

@option attrs [Hash] :options Options such as user traits (optional) @option attrs [Hash] :properties Event properties (optional) @option attrs [Time] :timestamp When the event occurred (optional) @option attrs [String] :user_id The ID for this user in your database

(optional but you must provide either an `anonymous_id` or `user_id`)

@option attrs [String] :message_id ID that uniquely

identifies a message across the API. (optional)
# File lib/segment/analytics/client.rb, line 65
def track(attrs)
  symbolize_keys! attrs
  check_user_id! attrs

  event = attrs[:event]
  properties = attrs[:properties] || {}
  timestamp = attrs[:timestamp] || Time.new
  context = attrs[:context] || {}
  message_id = attrs[:message_id].to_s if attrs[:message_id]

  check_timestamp! timestamp

  if event.nil? || event.empty?
    raise ArgumentError, 'Must supply event as a non-empty string'
  end

  raise ArgumentError, 'Properties must be a Hash' unless properties.is_a? Hash
  isoify_dates! properties

  add_context context

  enqueue({
    :event => event,
    :userId => attrs[:user_id],
    :anonymousId => attrs[:anonymous_id],
    :context => context,
    :options => attrs[:options],
    :integrations => attrs[:integrations],
    :properties => properties,
    :messageId => message_id,
    :timestamp => datetime_in_iso8601(timestamp),
    :type => 'track'
  })
end

Private Instance Methods

add_context(context) click to toggle source

private: Adds contextual information to the call

context - Hash of call context

# File lib/segment/analytics/client.rb, line 377
def add_context(context)
  context[:library] = { :name => 'analytics-ruby', :version => Segment::Analytics::VERSION.to_s }
end
check_presence!(obj, name) click to toggle source

private: Ensures that a string is non-empty

obj - String|Number that must be non-blank name - Name of the validated value

# File lib/segment/analytics/client.rb, line 368
def check_presence!(obj, name)
  if obj.nil? || (obj.is_a?(String) && obj.empty?)
    raise ArgumentError, "#{name} must be given"
  end
end
check_timestamp!(timestamp) click to toggle source

private: Checks the timstamp option to make sure it is a Time.

# File lib/segment/analytics/client.rb, line 387
def check_timestamp!(timestamp)
  raise ArgumentError, 'Timestamp must be a Time' unless timestamp.is_a? Time
end
check_user_id!(attrs) click to toggle source
# File lib/segment/analytics/client.rb, line 404
def check_user_id!(attrs)
  unless attrs[:user_id] || attrs[:anonymous_id]
    raise ArgumentError, 'Must supply either user_id or anonymous_id'
  end
end
check_write_key!() click to toggle source

private: Checks that the write_key is properly initialized

# File lib/segment/analytics/client.rb, line 382
def check_write_key!
  raise ArgumentError, 'Write key must be initialized' if @write_key.nil?
end
enqueue(action) click to toggle source

private: Enqueues the action.

returns Boolean of whether the item was added to the queue.

# File lib/segment/analytics/client.rb, line 344
def enqueue(action)
  # add our request id for tracing purposes
  action[:messageId] ||= uid

  if @queue.length < @max_queue_size
    @queue << action
    ensure_worker_running

    true
  else
    logger.warn(
      'Queue is full, dropping events. The :max_queue_size ' \
      'configuration parameter can be increased to prevent this from ' \
      'happening.'
    )
    false
  end
end
ensure_worker_running() click to toggle source
# File lib/segment/analytics/client.rb, line 410
def ensure_worker_running
  return if worker_running?
  @worker_mutex.synchronize do
    return if worker_running?
    @worker_thread = Thread.new do
      @worker.run
    end
  end
end
event(attrs) click to toggle source
# File lib/segment/analytics/client.rb, line 391
def event(attrs)
  symbolize_keys! attrs

  {
    :userId => user_id,
    :name => name,
    :properties => properties,
    :context => context,
    :timestamp => datetime_in_iso8601(timestamp),
    :type => 'screen'
  }
end
worker_running?() click to toggle source
# File lib/segment/analytics/client.rb, line 420
def worker_running?
  @worker_thread && @worker_thread.alive?
end