class OpenCensus::Stats::Exporters::Stackdriver

The Stackdriver exporter for OpenCensus Stats exports captured stats to a Google Monitoring project. It calls the Monitoring API in a background thread pool.

Constants

CUSTOM_OPENCENSUS_DOMAIN

Default custom opencensus domain name @return [String]

GLOBAL_RESOURCE_TYPE

Default metric resouce type. @return [String]

Attributes

metric_prefix[R]

Metric prefix @return [String]

project_id[R]

The project ID @return [String]

resource_labels[R]

Metric resource labels @return [Hash<String,String>]

resource_type[R]

Metric resource type @return [String]

Public Class Methods

new(\ project_id: nil, credentials: nil, scope: nil, timeout: nil, client_config: nil, max_queue: 1000, max_threads: 1, auto_terminate_time: 10, mock_client: nil, metric_prefix: nil, resource_type: nil, resource_labels: nil, gcm_service_address: nil) click to toggle source

Create a Stackdriver exporter.

@param [String] project_id The project identifier for the Stackdriver

Monitoring service you are connecting to. If you are running on
Google
Cloud hosting (e.g. Compute Engine, Kubernetes Engine, or App
Engine), this parameter is optional and will default to the
hosting project. Otherwise, it is required.

@param [String, Hash, Google::Auth::Credentials] credentials The

Stackdriver API credentials, which can be a path to a keyfile as
a String, the contents of a keyfile as a Hash, or a
Google::Auth::Credentials object. If you are running on Google
Cloud hosting (e.g. Compute Engine, Kubernetes Engine, or App
Engine), this parameter is optional and will default to the
credentials provided by the hosting project. Otherwise, it is
required.

@param [String, Array<String>] scope The OAuth 2.0 scopes controlling

the set of resources and operations the API client can access.
Optional. Most applications can leave this set to the default.

@param [Integer] timeout The default timeout for API requests, in

seconds. Optional.

@param [Hash] client_config An optional set of additional

configuration values for the API connection.

@param [Integer] max_queue The maximum number of API requests that

can be queued for background operation. If the queue exceeds this
value, additional requests will be run in the calling thread
rather than in the background. Set to 0 to allow the queue to
grow indefinitely. Default is 1000.

@param [Integer] max_threads The maximum number of threads that can

be spun up to handle API requests. Default is 1. If set to 0,
backgrounding will be disabled and all requests will run in the
calling thread.

@param [Integer] auto_terminate_time The time in seconds allotted to

complete any pending background requests when Ruby is exiting.

@param [String] metric_prefix Prefix for stackdriver metric.

Default value set to {CUSTOM_OPENCENSUS_DOMAIN}

@param [String] resource_type Metric resource type.

Default value set to {GLOBAL_RESOURCE_TYPE}

@param [Hash<String,String>] resource_labels Metric resource labels.

Default value set to { "project_id" => project_id }

@param [String] gcm_service_address Override for the Google

Cloud Monitoring service hostname, or `nil` to leave as
the default.
# File lib/opencensus/stats/exporters/stackdriver.rb, line 110
def initialize \
    project_id: nil,
    credentials: nil,
    scope: nil,
    timeout: nil,
    client_config: nil, # rubocop:disable Lint/UnusedMethodArgument
    max_queue: 1000,
    max_threads: 1,
    auto_terminate_time: 10,
    mock_client: nil,
    metric_prefix: nil,
    resource_type: nil,
    resource_labels: nil,
    gcm_service_address: nil
  @project_id = project_id ||
                ENV["GOOGLE_CLOUD_PROJECT"] ||
                Google::Cloud.env.project_id
  @metric_prefix = metric_prefix || CUSTOM_OPENCENSUS_DOMAIN
  @resource_type = resource_type || GLOBAL_RESOURCE_TYPE
  @resource_labels = resource_labels || {
    "project_id" => @project_id
  }
  @executor = create_executor max_threads, max_queue

  if auto_terminate_time
    terminate_at_exit! @executor, auto_terminate_time
  end

  if mock_client
    @client_promise =
      Concurrent::Promise.fulfill mock_client, executor: @executor
  else
    @client_promise = create_client_promise \
      @executor, credentials, scope, timeout, gcm_service_address
  end

  @converter = Converter.new @project_id
  paths = Google::Cloud::Monitoring::V3::MetricService::Paths
  @project_path = paths.project_path project: @project_id
end

Public Instance Methods

create_metric_descriptor(view) click to toggle source

Create a metric descriptor

An error will be raised if there is already a metric descriptor created with the same name but it has a different aggregation or keys.

@param [OpenCensus::Stats::View] view @return [Google::Api::MetricDescriptor]

# File lib/opencensus/stats/exporters/stackdriver.rb, line 245
def create_metric_descriptor view
  metric_descriptor = @converter.convert_metric_descriptor(
    view,
    metric_prefix
  )
  paths = Google::Cloud::Monitoring::V3::MetricService::Paths
  metric_name = paths.metric_descriptor_path(
    project: project_id,
    metric_descriptor: metric_descriptor.type
  )

  @client_promise.execute
  descriptor_create_promise = @client_promise.then do |client|
    client.create_metric_descriptor name: metric_name,
                                    metric_descriptor: metric_descriptor
  end
  descriptor_create_promise.value!
end
export(views_data) click to toggle source

Export stats to Monitoring service asynchronously.

@param [Array<OpenCensus::Stats::ViewData>] views_data The captured

stats data
# File lib/opencensus/stats/exporters/stackdriver.rb, line 156
def export views_data
  raise "Exporter is no longer running" unless @executor.running?

  return if views_data.nil? || views_data.empty?

  @client_promise.execute
  export_promise = @client_promise.then do |client|
    export_as_batch(client, views_data)
  end
  export_promise.on_error do |reason|
    warn "Unable to export to Monitoring service because: #{reason}"
  end

  nil
end
kill() click to toggle source

Begin shutting down the exporter forcefully. After this operation is performed, the exporter will no longer accept export requests, and will finish any currently running export requests, but will cancel all requests that are still pending in the queue.

# File lib/opencensus/stats/exporters/stackdriver.rb, line 219
def kill
  @executor.kill
  self
end
running?() click to toggle source

Returns true if this exporter is running and will accept further export requests. Returns false once the exporter begins shutting down.

@return [boolean]

# File lib/opencensus/stats/exporters/stackdriver.rb, line 178
def running?
  @executor.running?
end
shutdown() click to toggle source

Begin shutting down the exporter gracefully. After this operation is performed, the exporter will no longer accept export requests, but will finish any pending requests in the background.

# File lib/opencensus/stats/exporters/stackdriver.rb, line 208
def shutdown
  @executor.shutdown
  self
end
shutdown?() click to toggle source

Returns true if this exporter has finished shutting down and all pending stats have been sent.

@return [boolean]

# File lib/opencensus/stats/exporters/stackdriver.rb, line 188
def shutdown?
  @executor.shutdown?
end
shuttingdown?() click to toggle source

Returns true if this exporter has begun shutting down and is no longer accepting export requests, but is still running queued requests in the background.

@return [boolean]

# File lib/opencensus/stats/exporters/stackdriver.rb, line 199
def shuttingdown?
  @executor.shuttingdown?
end
wait_for_termination(timeout = nil) click to toggle source

Wait for the exporter to finish shutting down.

@param [Integer, nil] timeout A timeout in seconds, or nil for no

timeout.

@return [boolean] true if the exporter is shut down, or false if the

wait timed out.
# File lib/opencensus/stats/exporters/stackdriver.rb, line 232
def wait_for_termination timeout = nil
  @executor.wait_for_termination timeout
end

Private Instance Methods

create_client_promise(executor, credentials, scopes, timeout, service_address) click to toggle source

Create the client promise. We create the client lazily so grpc doesn't get initialized until we actually need it. This is important because if it is intialized too early, before a fork, it can go into a bad state.

# File lib/opencensus/stats/exporters/stackdriver.rb, line 282
def create_client_promise executor, credentials, scopes,
                          timeout, service_address
  Concurrent::Promise.new executor: executor do
    Google::Cloud::Monitoring::V3::MetricService::Client.new do |config|
      config.credentials = credentials if credentials
      config.scope = scopes if scopes
      config.timeout = timeout if timeout
      config.endpoint = service_address if service_address
      config.lib_name = "opencensus"
      config.lib_version = OpenCensus::Stackdriver::VERSION
    end
  end
end
create_executor(max_threads, max_queue) click to toggle source

Create the executor

# File lib/opencensus/stats/exporters/stackdriver.rb, line 267
def create_executor max_threads, max_queue
  if max_threads >= 1
    Concurrent::ThreadPoolExecutor.new \
      min_threads: 1, max_threads: max_threads,
      max_queue: max_queue, fallback_policy: :caller_runs,
      auto_terminate: false
  else
    Concurrent::ImmediateExecutor.new
  end
end
export_as_batch(client, views_data) click to toggle source

Export a list of stats in the current thread

# File lib/opencensus/stats/exporters/stackdriver.rb, line 308
def export_as_batch client, views_data
  time_series = views_data.map do |view_data|
    @converter.convert_time_series(
      metric_prefix,
      resource_type,
      resource_labels,
      view_data
    )
  end

  client.create_time_series name: @project_path,
                            time_series: time_series.flatten
end
terminate_at_exit!(executor, timeout) click to toggle source

Set up an at_exit hook that shuts the exporter down.

# File lib/opencensus/stats/exporters/stackdriver.rb, line 297
def terminate_at_exit! executor, timeout
  at_exit do
    executor.shutdown
    unless executor.wait_for_termination timeout
      executor.kill
      executor.wait_for_termination timeout
    end
  end
end