diff --git a/.gitignore b/.gitignore index fca840b..42584df 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ /docs/_site /docs/Gemfile.lock /docs/api/ +.ruby-version diff --git a/.rubocop.yml b/.rubocop.yml index 75c853c..ab3fe17 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,6 +8,7 @@ AllCops: - "test/**/*" - "docs/**/*" - "tmp/**/*" + - "lib/opencensus/proto/**/*" TargetRubyVersion: 2.3 Documentation: Enabled: false diff --git a/.yardopts b/.yardopts index e6cfe66..c03a32f 100644 --- a/.yardopts +++ b/.yardopts @@ -3,6 +3,7 @@ --markup markdown --markup-provider redcarpet --main=README.md +--exclude _pb\.rb$ ./lib/**/*.rb - diff --git a/Rakefile b/Rakefile index 6c5d28e..e8aec54 100644 --- a/Rakefile +++ b/Rakefile @@ -34,4 +34,18 @@ YARD::Rake::YardocTask.new do |t| t.stats_options = ['--list-undoc'] # optional end +desc "Start an interactive shell." +task :console do + require "irb" + require "irb/completion" + require "pp" + + $LOAD_PATH.unshift "lib" + + require "opencensus-ocagent" + + ARGV.clear + IRB.start +end + task :default => [:test, :rubocop, :yard] diff --git a/lib/opencensus/ocagent.rb b/lib/opencensus/ocagent.rb index 77945fb..df9201d 100644 --- a/lib/opencensus/ocagent.rb +++ b/lib/opencensus/ocagent.rb @@ -26,3 +26,4 @@ module OCAgent require "opencensus/ocagent/version" require "opencensus/trace/exporters/ocagent" +require "opencensus/trace/exporters/ocagent/sampler" diff --git a/lib/opencensus/proto/agent/common/v1/common_pb.rb b/lib/opencensus/proto/agent/common/v1/common_pb.rb new file mode 100644 index 0000000..1f9db05 --- /dev/null +++ b/lib/opencensus/proto/agent/common/v1/common_pb.rb @@ -0,0 +1,55 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/agent/common/v1/common.proto + +require 'google/protobuf' + +require 'google/protobuf/timestamp_pb' +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.agent.common.v1.Node" do + optional :identifier, :message, 1, "opencensus.proto.agent.common.v1.ProcessIdentifier" + optional :library_info, :message, 2, "opencensus.proto.agent.common.v1.LibraryInfo" + optional :service_info, :message, 3, "opencensus.proto.agent.common.v1.ServiceInfo" + map :attributes, :string, :string, 4 + end + add_message "opencensus.proto.agent.common.v1.ProcessIdentifier" do + optional :host_name, :string, 1 + optional :pid, :uint32, 2 + optional :start_timestamp, :message, 3, "google.protobuf.Timestamp" + end + add_message "opencensus.proto.agent.common.v1.LibraryInfo" do + optional :language, :enum, 1, "opencensus.proto.agent.common.v1.LibraryInfo.Language" + optional :exporter_version, :string, 2 + optional :core_library_version, :string, 3 + end + add_enum "opencensus.proto.agent.common.v1.LibraryInfo.Language" do + value :LANGUAGE_UNSPECIFIED, 0 + value :CPP, 1 + value :C_SHARP, 2 + value :ERLANG, 3 + value :GO_LANG, 4 + value :JAVA, 5 + value :NODE_JS, 6 + value :PHP, 7 + value :PYTHON, 8 + value :RUBY, 9 + end + add_message "opencensus.proto.agent.common.v1.ServiceInfo" do + optional :name, :string, 1 + end +end + +module OpenCensus + module Proto + module Agent + module Common + module V1 + Node = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.common.v1.Node").msgclass + ProcessIdentifier = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.common.v1.ProcessIdentifier").msgclass + LibraryInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.common.v1.LibraryInfo").msgclass + LibraryInfo::Language = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.common.v1.LibraryInfo.Language").enummodule + ServiceInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.common.v1.ServiceInfo").msgclass + end + end + end + end +end diff --git a/lib/opencensus/proto/agent/metrics/v1/metrics_service_pb.rb b/lib/opencensus/proto/agent/metrics/v1/metrics_service_pb.rb new file mode 100644 index 0000000..ca03539 --- /dev/null +++ b/lib/opencensus/proto/agent/metrics/v1/metrics_service_pb.rb @@ -0,0 +1,30 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/agent/metrics/v1/metrics_service.proto + +require 'google/protobuf' + +require 'opencensus/proto/agent/common/v1/common_pb' +require 'opencensus/proto/metrics/v1/metrics_pb' +require 'opencensus/proto/resource/v1/resource_pb' +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.agent.metrics.v1.ExportMetricsServiceRequest" do + optional :node, :message, 1, "opencensus.proto.agent.common.v1.Node" + repeated :metrics, :message, 2, "opencensus.proto.metrics.v1.Metric" + optional :resource, :message, 3, "opencensus.proto.resource.v1.Resource" + end + add_message "opencensus.proto.agent.metrics.v1.ExportMetricsServiceResponse" do + end +end + +module OpenCensus + module Proto + module Agent + module Metrics + module V1 + ExportMetricsServiceRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.metrics.v1.ExportMetricsServiceRequest").msgclass + ExportMetricsServiceResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.metrics.v1.ExportMetricsServiceResponse").msgclass + end + end + end + end +end diff --git a/lib/opencensus/proto/agent/metrics/v1/metrics_service_services_pb.rb b/lib/opencensus/proto/agent/metrics/v1/metrics_service_services_pb.rb new file mode 100644 index 0000000..eb20806 --- /dev/null +++ b/lib/opencensus/proto/agent/metrics/v1/metrics_service_services_pb.rb @@ -0,0 +1,50 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: opencensus/proto/agent/metrics/v1/metrics_service.proto for package 'OpenCensus.Proto.Agent.Metrics.V1' +# Original file comments: +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'grpc' +require 'opencensus/proto/agent/metrics/v1/metrics_service_pb' + +module OpenCensus + module Proto + module Agent + module Metrics + module V1 + module MetricsService + # Service that can be used to push metrics between one Application + # instrumented with OpenCensus and an agent, or between an agent and a + # central collector. + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'opencensus.proto.agent.metrics.v1.MetricsService' + + # For performance reasons, it is recommended to keep this RPC + # alive for the entire life of the application. + rpc :Export, stream(ExportMetricsServiceRequest), stream(ExportMetricsServiceResponse) + end + + Stub = Service.rpc_stub_class + end + end + end + end + end +end diff --git a/lib/opencensus/proto/agent/trace/v1/trace_service_pb.rb b/lib/opencensus/proto/agent/trace/v1/trace_service_pb.rb new file mode 100644 index 0000000..3499fe0 --- /dev/null +++ b/lib/opencensus/proto/agent/trace/v1/trace_service_pb.rb @@ -0,0 +1,41 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/agent/trace/v1/trace_service.proto + +require 'google/protobuf' + +require 'opencensus/proto/agent/common/v1/common_pb' +require 'opencensus/proto/resource/v1/resource_pb' +require 'opencensus/proto/trace/v1/trace_pb' +require 'opencensus/proto/trace/v1/trace_config_pb' +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.agent.trace.v1.CurrentLibraryConfig" do + optional :node, :message, 1, "opencensus.proto.agent.common.v1.Node" + optional :config, :message, 2, "opencensus.proto.trace.v1.TraceConfig" + end + add_message "opencensus.proto.agent.trace.v1.UpdatedLibraryConfig" do + optional :node, :message, 1, "opencensus.proto.agent.common.v1.Node" + optional :config, :message, 2, "opencensus.proto.trace.v1.TraceConfig" + end + add_message "opencensus.proto.agent.trace.v1.ExportTraceServiceRequest" do + optional :node, :message, 1, "opencensus.proto.agent.common.v1.Node" + repeated :spans, :message, 2, "opencensus.proto.trace.v1.Span" + optional :resource, :message, 3, "opencensus.proto.resource.v1.Resource" + end + add_message "opencensus.proto.agent.trace.v1.ExportTraceServiceResponse" do + end +end + +module OpenCensus + module Proto + module Agent + module Trace + module V1 + CurrentLibraryConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.trace.v1.CurrentLibraryConfig").msgclass + UpdatedLibraryConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.trace.v1.UpdatedLibraryConfig").msgclass + ExportTraceServiceRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.trace.v1.ExportTraceServiceRequest").msgclass + ExportTraceServiceResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.agent.trace.v1.ExportTraceServiceResponse").msgclass + end + end + end + end +end diff --git a/lib/opencensus/proto/agent/trace/v1/trace_service_services_pb.rb b/lib/opencensus/proto/agent/trace/v1/trace_service_services_pb.rb new file mode 100644 index 0000000..b5b1c30 --- /dev/null +++ b/lib/opencensus/proto/agent/trace/v1/trace_service_services_pb.rb @@ -0,0 +1,55 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: opencensus/proto/agent/trace/v1/trace_service.proto for package 'OpenCensus.Proto.Agent.Trace.V1' +# Original file comments: +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'grpc' +require 'opencensus/proto/agent/trace/v1/trace_service_pb' + +module OpenCensus + module Proto + module Agent + module Trace + module V1 + module TraceService + # Service that can be used to push spans and configs between one Application + # instrumented with OpenCensus and an agent, or between an agent and a + # central collector or config service (in this case spans and configs are + # sent/received to/from multiple Applications). + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'opencensus.proto.agent.trace.v1.TraceService' + + # After initialization, this RPC must be kept alive for the entire life of + # the application. The agent pushes configs down to applications via a + # stream. + rpc :Config, stream(CurrentLibraryConfig), stream(UpdatedLibraryConfig) + # For performance reasons, it is recommended to keep this RPC + # alive for the entire life of the application. + rpc :Export, stream(ExportTraceServiceRequest), stream(ExportTraceServiceResponse) + end + + Stub = Service.rpc_stub_class + end + end + end + end + end +end diff --git a/lib/opencensus/proto/metrics/v1/metrics_pb.rb b/lib/opencensus/proto/metrics/v1/metrics_pb.rb new file mode 100644 index 0000000..7f80b87 --- /dev/null +++ b/lib/opencensus/proto/metrics/v1/metrics_pb.rb @@ -0,0 +1,116 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/metrics/v1/metrics.proto + +require 'google/protobuf' + +require 'google/protobuf/timestamp_pb' +require 'google/protobuf/wrappers_pb' +require 'opencensus/proto/resource/v1/resource_pb' +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.metrics.v1.Metric" do + optional :metric_descriptor, :message, 1, "opencensus.proto.metrics.v1.MetricDescriptor" + repeated :timeseries, :message, 2, "opencensus.proto.metrics.v1.TimeSeries" + optional :resource, :message, 3, "opencensus.proto.resource.v1.Resource" + end + add_message "opencensus.proto.metrics.v1.MetricDescriptor" do + optional :name, :string, 1 + optional :description, :string, 2 + optional :unit, :string, 3 + optional :type, :enum, 4, "opencensus.proto.metrics.v1.MetricDescriptor.Type" + repeated :label_keys, :message, 5, "opencensus.proto.metrics.v1.LabelKey" + end + add_enum "opencensus.proto.metrics.v1.MetricDescriptor.Type" do + value :UNSPECIFIED, 0 + value :GAUGE_INT64, 1 + value :GAUGE_DOUBLE, 2 + value :GAUGE_DISTRIBUTION, 3 + value :CUMULATIVE_INT64, 4 + value :CUMULATIVE_DOUBLE, 5 + value :CUMULATIVE_DISTRIBUTION, 6 + value :SUMMARY, 7 + end + add_message "opencensus.proto.metrics.v1.LabelKey" do + optional :key, :string, 1 + optional :description, :string, 2 + end + add_message "opencensus.proto.metrics.v1.TimeSeries" do + optional :start_timestamp, :message, 1, "google.protobuf.Timestamp" + repeated :label_values, :message, 2, "opencensus.proto.metrics.v1.LabelValue" + repeated :points, :message, 3, "opencensus.proto.metrics.v1.Point" + end + add_message "opencensus.proto.metrics.v1.LabelValue" do + optional :value, :string, 1 + optional :has_value, :bool, 2 + end + add_message "opencensus.proto.metrics.v1.Point" do + optional :timestamp, :message, 1, "google.protobuf.Timestamp" + oneof :value do + optional :int64_value, :int64, 2 + optional :double_value, :double, 3 + optional :distribution_value, :message, 4, "opencensus.proto.metrics.v1.DistributionValue" + optional :summary_value, :message, 5, "opencensus.proto.metrics.v1.SummaryValue" + end + end + add_message "opencensus.proto.metrics.v1.DistributionValue" do + optional :count, :int64, 1 + optional :sum, :double, 2 + optional :sum_of_squared_deviation, :double, 3 + optional :bucket_options, :message, 4, "opencensus.proto.metrics.v1.DistributionValue.BucketOptions" + repeated :buckets, :message, 5, "opencensus.proto.metrics.v1.DistributionValue.Bucket" + end + add_message "opencensus.proto.metrics.v1.DistributionValue.BucketOptions" do + oneof :type do + optional :explicit, :message, 1, "opencensus.proto.metrics.v1.DistributionValue.BucketOptions.Explicit" + end + end + add_message "opencensus.proto.metrics.v1.DistributionValue.BucketOptions.Explicit" do + repeated :bounds, :double, 1 + end + add_message "opencensus.proto.metrics.v1.DistributionValue.Bucket" do + optional :count, :int64, 1 + optional :exemplar, :message, 2, "opencensus.proto.metrics.v1.DistributionValue.Exemplar" + end + add_message "opencensus.proto.metrics.v1.DistributionValue.Exemplar" do + optional :value, :double, 1 + optional :timestamp, :message, 2, "google.protobuf.Timestamp" + map :attachments, :string, :string, 3 + end + add_message "opencensus.proto.metrics.v1.SummaryValue" do + optional :count, :message, 1, "google.protobuf.Int64Value" + optional :sum, :message, 2, "google.protobuf.DoubleValue" + optional :snapshot, :message, 3, "opencensus.proto.metrics.v1.SummaryValue.Snapshot" + end + add_message "opencensus.proto.metrics.v1.SummaryValue.Snapshot" do + optional :count, :message, 1, "google.protobuf.Int64Value" + optional :sum, :message, 2, "google.protobuf.DoubleValue" + repeated :percentile_values, :message, 3, "opencensus.proto.metrics.v1.SummaryValue.Snapshot.ValueAtPercentile" + end + add_message "opencensus.proto.metrics.v1.SummaryValue.Snapshot.ValueAtPercentile" do + optional :percentile, :double, 1 + optional :value, :double, 2 + end +end + +module OpenCensus + module Proto + module Metrics + module V1 + Metric = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.Metric").msgclass + MetricDescriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.MetricDescriptor").msgclass + MetricDescriptor::Type = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.MetricDescriptor.Type").enummodule + LabelKey = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.LabelKey").msgclass + TimeSeries = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.TimeSeries").msgclass + LabelValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.LabelValue").msgclass + Point = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.Point").msgclass + DistributionValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.DistributionValue").msgclass + DistributionValue::BucketOptions = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.DistributionValue.BucketOptions").msgclass + DistributionValue::BucketOptions::Explicit = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.DistributionValue.BucketOptions.Explicit").msgclass + DistributionValue::Bucket = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.DistributionValue.Bucket").msgclass + DistributionValue::Exemplar = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.DistributionValue.Exemplar").msgclass + SummaryValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.SummaryValue").msgclass + SummaryValue::Snapshot = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.SummaryValue.Snapshot").msgclass + SummaryValue::Snapshot::ValueAtPercentile = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.metrics.v1.SummaryValue.Snapshot.ValueAtPercentile").msgclass + end + end + end +end diff --git a/lib/opencensus/proto/resource/v1/resource_pb.rb b/lib/opencensus/proto/resource/v1/resource_pb.rb new file mode 100644 index 0000000..7c9ccd1 --- /dev/null +++ b/lib/opencensus/proto/resource/v1/resource_pb.rb @@ -0,0 +1,21 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/resource/v1/resource.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.resource.v1.Resource" do + optional :type, :string, 1 + map :labels, :string, :string, 2 + end +end + +module OpenCensus + module Proto + module Resource + module V1 + Resource = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.resource.v1.Resource").msgclass + end + end + end +end diff --git a/lib/opencensus/proto/stats/v1/stats_pb.rb b/lib/opencensus/proto/stats/v1/stats_pb.rb new file mode 100644 index 0000000..4142199 --- /dev/null +++ b/lib/opencensus/proto/stats/v1/stats_pb.rb @@ -0,0 +1,71 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/stats/v1/stats.proto + +require 'google/protobuf' + +require 'google/protobuf/timestamp_pb' +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.stats.v1.Tag" do + optional :key, :string, 1 + optional :value, :string, 2 + end + add_message "opencensus.proto.stats.v1.Measure" do + optional :name, :string, 1 + optional :description, :string, 2 + optional :unit, :string, 3 + optional :type, :enum, 4, "opencensus.proto.stats.v1.Measure.Type" + end + add_enum "opencensus.proto.stats.v1.Measure.Type" do + value :TYPE_UNSPECIFIED, 0 + value :INT64, 1 + value :DOUBLE, 2 + end + add_message "opencensus.proto.stats.v1.View" do + optional :name, :string, 1 + optional :description, :string, 2 + optional :measure, :message, 3, "opencensus.proto.stats.v1.Measure" + repeated :columns, :string, 4 + oneof :aggregation do + optional :count_aggregation, :message, 5, "opencensus.proto.stats.v1.CountAggregation" + optional :sum_aggregation, :message, 6, "opencensus.proto.stats.v1.SumAggregation" + optional :last_value_aggregation, :message, 7, "opencensus.proto.stats.v1.LastValueAggregation" + optional :distribution_aggregation, :message, 8, "opencensus.proto.stats.v1.DistributionAggregation" + end + end + add_message "opencensus.proto.stats.v1.CountAggregation" do + end + add_message "opencensus.proto.stats.v1.SumAggregation" do + end + add_message "opencensus.proto.stats.v1.LastValueAggregation" do + end + add_message "opencensus.proto.stats.v1.DistributionAggregation" do + repeated :bucket_bounds, :double, 1 + end + add_message "opencensus.proto.stats.v1.Measurement" do + repeated :tags, :message, 1, "opencensus.proto.stats.v1.Tag" + optional :measure_name, :string, 2 + optional :time, :message, 5, "google.protobuf.Timestamp" + oneof :value do + optional :double_value, :double, 3 + optional :int_value, :int64, 4 + end + end +end + +module OpenCensus + module Proto + module Stats + module V1 + Tag = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.Tag").msgclass + Measure = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.Measure").msgclass + Measure::Type = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.Measure.Type").enummodule + View = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.View").msgclass + CountAggregation = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.CountAggregation").msgclass + SumAggregation = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.SumAggregation").msgclass + LastValueAggregation = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.LastValueAggregation").msgclass + DistributionAggregation = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.DistributionAggregation").msgclass + Measurement = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.stats.v1.Measurement").msgclass + end + end + end +end diff --git a/lib/opencensus/proto/trace/v1/trace_config_pb.rb b/lib/opencensus/proto/trace/v1/trace_config_pb.rb new file mode 100644 index 0000000..d47af9b --- /dev/null +++ b/lib/opencensus/proto/trace/v1/trace_config_pb.rb @@ -0,0 +1,46 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/trace/v1/trace_config.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.trace.v1.TraceConfig" do + optional :max_number_of_attributes, :int64, 4 + optional :max_number_of_annotations, :int64, 5 + optional :max_number_of_message_events, :int64, 6 + optional :max_number_of_links, :int64, 7 + oneof :sampler do + optional :probability_sampler, :message, 1, "opencensus.proto.trace.v1.ProbabilitySampler" + optional :constant_sampler, :message, 2, "opencensus.proto.trace.v1.ConstantSampler" + optional :rate_limiting_sampler, :message, 3, "opencensus.proto.trace.v1.RateLimitingSampler" + end + end + add_message "opencensus.proto.trace.v1.ProbabilitySampler" do + optional :samplingProbability, :double, 1 + end + add_message "opencensus.proto.trace.v1.ConstantSampler" do + optional :decision, :enum, 1, "opencensus.proto.trace.v1.ConstantSampler.ConstantDecision" + end + add_enum "opencensus.proto.trace.v1.ConstantSampler.ConstantDecision" do + value :ALWAYS_OFF, 0 + value :ALWAYS_ON, 1 + value :ALWAYS_PARENT, 2 + end + add_message "opencensus.proto.trace.v1.RateLimitingSampler" do + optional :qps, :int64, 1 + end +end + +module OpenCensus + module Proto + module Trace + module V1 + TraceConfig = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.TraceConfig").msgclass + ProbabilitySampler = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.ProbabilitySampler").msgclass + ConstantSampler = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.ConstantSampler").msgclass + ConstantSampler::ConstantDecision = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.ConstantSampler.ConstantDecision").enummodule + RateLimitingSampler = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.RateLimitingSampler").msgclass + end + end + end +end diff --git a/lib/opencensus/proto/trace/v1/trace_pb.rb b/lib/opencensus/proto/trace/v1/trace_pb.rb new file mode 100644 index 0000000..59afedc --- /dev/null +++ b/lib/opencensus/proto/trace/v1/trace_pb.rb @@ -0,0 +1,152 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: opencensus/proto/trace/v1/trace.proto + +require 'google/protobuf' + +require 'opencensus/proto/resource/v1/resource_pb' +require 'google/protobuf/timestamp_pb' +require 'google/protobuf/wrappers_pb' +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "opencensus.proto.trace.v1.Span" do + optional :trace_id, :bytes, 1 + optional :span_id, :bytes, 2 + optional :tracestate, :message, 15, "opencensus.proto.trace.v1.Span.Tracestate" + optional :parent_span_id, :bytes, 3 + optional :name, :message, 4, "opencensus.proto.trace.v1.TruncatableString" + optional :kind, :enum, 14, "opencensus.proto.trace.v1.Span.SpanKind" + optional :start_time, :message, 5, "google.protobuf.Timestamp" + optional :end_time, :message, 6, "google.protobuf.Timestamp" + optional :attributes, :message, 7, "opencensus.proto.trace.v1.Span.Attributes" + optional :stack_trace, :message, 8, "opencensus.proto.trace.v1.StackTrace" + optional :time_events, :message, 9, "opencensus.proto.trace.v1.Span.TimeEvents" + optional :links, :message, 10, "opencensus.proto.trace.v1.Span.Links" + optional :status, :message, 11, "opencensus.proto.trace.v1.Status" + optional :resource, :message, 16, "opencensus.proto.resource.v1.Resource" + optional :same_process_as_parent_span, :message, 12, "google.protobuf.BoolValue" + optional :child_span_count, :message, 13, "google.protobuf.UInt32Value" + end + add_message "opencensus.proto.trace.v1.Span.Tracestate" do + repeated :entries, :message, 1, "opencensus.proto.trace.v1.Span.Tracestate.Entry" + end + add_message "opencensus.proto.trace.v1.Span.Tracestate.Entry" do + optional :key, :string, 1 + optional :value, :string, 2 + end + add_message "opencensus.proto.trace.v1.Span.Attributes" do + map :attribute_map, :string, :message, 1, "opencensus.proto.trace.v1.AttributeValue" + optional :dropped_attributes_count, :int32, 2 + end + add_message "opencensus.proto.trace.v1.Span.TimeEvent" do + optional :time, :message, 1, "google.protobuf.Timestamp" + oneof :value do + optional :annotation, :message, 2, "opencensus.proto.trace.v1.Span.TimeEvent.Annotation" + optional :message_event, :message, 3, "opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent" + end + end + add_message "opencensus.proto.trace.v1.Span.TimeEvent.Annotation" do + optional :description, :message, 1, "opencensus.proto.trace.v1.TruncatableString" + optional :attributes, :message, 2, "opencensus.proto.trace.v1.Span.Attributes" + end + add_message "opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent" do + optional :type, :enum, 1, "opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type" + optional :id, :uint64, 2 + optional :uncompressed_size, :uint64, 3 + optional :compressed_size, :uint64, 4 + end + add_enum "opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type" do + value :TYPE_UNSPECIFIED, 0 + value :SENT, 1 + value :RECEIVED, 2 + end + add_message "opencensus.proto.trace.v1.Span.TimeEvents" do + repeated :time_event, :message, 1, "opencensus.proto.trace.v1.Span.TimeEvent" + optional :dropped_annotations_count, :int32, 2 + optional :dropped_message_events_count, :int32, 3 + end + add_message "opencensus.proto.trace.v1.Span.Link" do + optional :trace_id, :bytes, 1 + optional :span_id, :bytes, 2 + optional :type, :enum, 3, "opencensus.proto.trace.v1.Span.Link.Type" + optional :attributes, :message, 4, "opencensus.proto.trace.v1.Span.Attributes" + end + add_enum "opencensus.proto.trace.v1.Span.Link.Type" do + value :TYPE_UNSPECIFIED, 0 + value :CHILD_LINKED_SPAN, 1 + value :PARENT_LINKED_SPAN, 2 + end + add_message "opencensus.proto.trace.v1.Span.Links" do + repeated :link, :message, 1, "opencensus.proto.trace.v1.Span.Link" + optional :dropped_links_count, :int32, 2 + end + add_enum "opencensus.proto.trace.v1.Span.SpanKind" do + value :SPAN_KIND_UNSPECIFIED, 0 + value :SERVER, 1 + value :CLIENT, 2 + end + add_message "opencensus.proto.trace.v1.Status" do + optional :code, :int32, 1 + optional :message, :string, 2 + end + add_message "opencensus.proto.trace.v1.AttributeValue" do + oneof :value do + optional :string_value, :message, 1, "opencensus.proto.trace.v1.TruncatableString" + optional :int_value, :int64, 2 + optional :bool_value, :bool, 3 + optional :double_value, :double, 4 + end + end + add_message "opencensus.proto.trace.v1.StackTrace" do + optional :stack_frames, :message, 1, "opencensus.proto.trace.v1.StackTrace.StackFrames" + optional :stack_trace_hash_id, :uint64, 2 + end + add_message "opencensus.proto.trace.v1.StackTrace.StackFrame" do + optional :function_name, :message, 1, "opencensus.proto.trace.v1.TruncatableString" + optional :original_function_name, :message, 2, "opencensus.proto.trace.v1.TruncatableString" + optional :file_name, :message, 3, "opencensus.proto.trace.v1.TruncatableString" + optional :line_number, :int64, 4 + optional :column_number, :int64, 5 + optional :load_module, :message, 6, "opencensus.proto.trace.v1.Module" + optional :source_version, :message, 7, "opencensus.proto.trace.v1.TruncatableString" + end + add_message "opencensus.proto.trace.v1.StackTrace.StackFrames" do + repeated :frame, :message, 1, "opencensus.proto.trace.v1.StackTrace.StackFrame" + optional :dropped_frames_count, :int32, 2 + end + add_message "opencensus.proto.trace.v1.Module" do + optional :module, :message, 1, "opencensus.proto.trace.v1.TruncatableString" + optional :build_id, :message, 2, "opencensus.proto.trace.v1.TruncatableString" + end + add_message "opencensus.proto.trace.v1.TruncatableString" do + optional :value, :string, 1 + optional :truncated_byte_count, :int32, 2 + end +end + +module OpenCensus + module Proto + module Trace + module V1 + Span = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span").msgclass + Span::Tracestate = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.Tracestate").msgclass + Span::Tracestate::Entry = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.Tracestate.Entry").msgclass + Span::Attributes = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.Attributes").msgclass + Span::TimeEvent = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.TimeEvent").msgclass + Span::TimeEvent::Annotation = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.TimeEvent.Annotation").msgclass + Span::TimeEvent::MessageEvent = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent").msgclass + Span::TimeEvent::MessageEvent::Type = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.TimeEvent.MessageEvent.Type").enummodule + Span::TimeEvents = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.TimeEvents").msgclass + Span::Link = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.Link").msgclass + Span::Link::Type = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.Link.Type").enummodule + Span::Links = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.Links").msgclass + Span::SpanKind = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Span.SpanKind").enummodule + Status = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Status").msgclass + AttributeValue = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.AttributeValue").msgclass + StackTrace = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.StackTrace").msgclass + StackTrace::StackFrame = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.StackTrace.StackFrame").msgclass + StackTrace::StackFrames = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.StackTrace.StackFrames").msgclass + Module = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.Module").msgclass + TruncatableString = Google::Protobuf::DescriptorPool.generated_pool.lookup("opencensus.proto.trace.v1.TruncatableString").msgclass + end + end + end +end diff --git a/lib/opencensus/trace/exporters/ocagent.rb b/lib/opencensus/trace/exporters/ocagent.rb index f71839e..5d31c93 100644 --- a/lib/opencensus/trace/exporters/ocagent.rb +++ b/lib/opencensus/trace/exporters/ocagent.rb @@ -15,14 +15,270 @@ # limitations under the License. +require "socket" +require "opencensus/proto/agent/trace/v1/trace_service_services_pb" +require "opencensus/trace/exporters/ocagent/trace_enumerator_queue" +require "opencensus/trace/exporters/ocagent/converter" + module OpenCensus ## OpenCensus Trace collects distributed traces module Trace - ## Exporters for OpenCensus Trace + ## Exporters for OpenCensus Trace. module Exporters - ## OpenCensus Agent exporter for Trace + # OpenCensus Agent exporter for Trace + # + # The OpenCensus Agent exporter exports captured OpenCensus Trace span to + # OpenCensus Agent service. + # class OCAgent - # TODO + # Default agent address + # @return [String] + DEFAULT_AGENT_SERVICE_ADDRESS = "localhost:55678" + + # Default metric resouce type. + # @return [String] + DEFAULT_GLOBAL_RESOURCE_TYPE = "global" + + # Default trace stream sleep delay time + # @return [Float] + DEFAULT_TRACE_STREAM_SLEEP_DELAY = 0.5 + + # @private + # Namespce alias for agent protobufs. + AgentProto = OpenCensus::Proto::Agent + + # @return [String] + attr_reader :service_name + + # OpenCensus Agent service network address. + # @return [String] + attr_reader :agent_service_address + + # gRPC channel auth credentials + # @return [Symbol, GRPC::Core::ChannelCredentials] + attr_reader :credentials + + # Node info. It contains process env info i.e PID, hostname + # @return [OpenCensus::Proto::Agent::Common::V1::Node] + attr_reader :node_info + + # Resource object with resource type and lables. + # @return OpenCensus::Proto::Resource::V1::Resource + attr_reader :resource + + # Trace stream sleep dealy if no item available in queue. + # @return [Float] + attr_reader :trace_stream_sleep_delay + + # @param [String] service_name Name of the service. + # @param [String] agent_service_address OpenCensus Agent address. + # Default value is {DEFAULT_AGENT_SERVICE_ADDRESS} + # @param [String | GRPC::Core::ChannelCredentials| nil] credentials + # The gRPC channel credentials PEM file path or channel credentials + # object. Default value is `:this_channel_is_insecure`, + # which explicitly indicates that the client should be created with + # an insecure connection. + # @param [String] resource_type Resource type. Optional. + # Resource that is associated with each span which is going to export + # Default value is {DEFAULT_GLOBAL_RESOURCE_TYPE} + # @param [Hash] resource_labels + # Optional. Set of labels that describe the resource + # @param [Integer] trace_stream_sleep_delay Time in seconds. + # Default value {DEFAULT_TRACE_STREAM_SLEEP_DELAY} + # Thread sleep time if no span available for export. + def initialize \ + service_name:, + agent_service_address: nil, + credentials: nil, + resource_type: nil, + resource_labels: nil, + trace_stream_sleep_delay: nil + @service_name = service_name + @agent_service_address = + agent_service_address || DEFAULT_AGENT_SERVICE_ADDRESS + + if credentials.nil? + @credentials = :this_channel_is_insecure + elsif credentials.is_a? GRPC::Core::ChannelCredentials + @credentials = credentials + elsif credentials.is_a? String + @credentials = GRPC::Core::ChannelCredentials.new credentials + end + + @node_info = create_node_info + @resource = create_resource( + resource_type || DEFAULT_GLOBAL_RESOURCE_TYPE, + labels: resource_labels + ) + @trace_stream_sleep_delay = + trace_stream_sleep_delay || DEFAULT_TRACE_STREAM_SLEEP_DELAY + @stopped = true + @trace_req_queue = nil + end + + # Create the OpenCensus Agent trace service grpc client. + # @return [OpenCensus::Proto::Agent::Trace::V1::TraceService::Stub] + def client + @client ||= AgentProto::Trace::V1::TraceService::Stub.new( + agent_service_address, + credentials + ) + end + + # Create trace config proto. + # Global configuration of the trace service. + # + # @param [Integer] max_attributes The max number of + # attributes per span. Optional + # @param [Integer] max_annotations The max number of + # annotation events per span. Optional + # @param [Integer] max_message_events The max number of + # message events per span. Optional + # @param [Integer] max_linnks The global max number of link + # entries per span. Optional + # @param [OpenCensus::Trace::Exporters::Sampler, nil] sampler + # The sampler used to make decisions on span sampling. + # See {Sampler} for different type of samplers. + # @return [OpenCensus::Proto::Trace::V1::TraceConfig] + # + def create_trace_config \ + max_attributes: nil, + max_annotations: nil, + max_message_events: nil, + max_linnks: nil, + sampler: nil + options = { + max_number_of_attributes: max_attributes, + max_number_of_annotations: max_annotations, + max_number_of_message_events: max_message_events, + max_number_of_links: max_linnks + } + + sampler_proto = sampler ? sampler.to_proto : nil + + case sampler_proto + when OpenCensus::Proto::Trace::V1::ProbabilitySampler + options[:probability_sampler] = sampler_proto + when OpenCensus::Proto::Trace::V1::ConstantSampler + options[:constant_sampler] = sampler_proto + when OpenCensus::Proto::Trace::V1::RateLimitingSampler + options[:rate_limiting_sampler] = sampler_proto + end + + options.delete_if!(&:nil?) + OpenCensus::Proto::Trace::V1::TraceConfig.new options + end + + # Stop the trace export stream. + def stop + @stopped = true + @trace_req_queue&.push TraceEnumeratorQueue::SENTINEL + end + + # Check exporter is stopped. + # + # @return [Boolean] + def stopped? + @stopped + end + + # Start trace export stream. + # + # @return [Boolean] If steam is not started or stop returns true. + # If trace export stream alreay running return false. + def start + return false unless @stopped + + @trace_req_queue = TraceEnumeratorQueue.new @trace_stream_sleep_delay + Thread.new { background_export_run } + @stopped = false + true + end + + # Export spans to OpenCensus Agent service. + # + # @param [Array] spans The captured spans to + # export to OpenCensus Agent service + # + def export spans + return nil if spans.nil? || spans.empty? + + start unless @trace_req_queue + + return if stopped? + + converter = Converter.new @resource + req = AgentProto::Trace::V1::ExportTraceServiceRequest.new( + node: node_info, + resource: resource, + spans: spans.map { |span| converter.convert_span span } + ) + @trace_req_queue.push req + + nil + end + + private + + # rubocop:disable Metrics/MethodLength + + # Create node info proto. + # @return [OpenCensus::Proto::Agent::Common::V1::Node] + # + def create_node_info + time = Time.now.utc + timestamp = Google::Protobuf::Timestamp.new( + seconds: time.to_i, + nanos: time.nsec + ) + + identifier = AgentProto::Common::V1::ProcessIdentifier.new( + host_name: Socket.gethostname, + pid: Process.pid, + start_timestamp: timestamp + ) + + library_info = AgentProto::Common::V1::LibraryInfo.new( + language: AgentProto::Common::V1::LibraryInfo::Language::RUBY, + exporter_version: OpenCensus::OCAgent::VERSION, + core_library_version: OpenCensus::VERSION + ) + + service_info = AgentProto::Common::V1::ServiceInfo.new( + name: @service_name + ) + + OpenCensus::Proto::Agent::Common::V1::Node.new( + identifier: identifier, + library_info: library_info, + service_info: service_info + ) + end + + # rubocop:enable Metrics/MethodLength + + # Create resouce proto object. + # + # @param [String] type Resource type. + # Resource that is associated with each span which is going to export + # @param [Hash] labels Set of labels that describe the + # resource. Optional. + # @return [OpenCensus::Proto::Resource::V1::Resource] + # + def create_resource type, labels: nil + options = { type: type } + options[:labels] = labels if labels + OpenCensus::Proto::Resource::V1::Resource.new options + end + + # Run exporter stream. + def background_export_run + client.export(@trace_req_queue.each_item).each {} + rescue StandardError => err + warn "Unable to export to OCAgent service: #{err.class} #{err}" + ensure + Thread.pass + end end end end diff --git a/lib/opencensus/trace/exporters/ocagent/converter.rb b/lib/opencensus/trace/exporters/ocagent/converter.rb new file mode 100644 index 0000000..15af4b0 --- /dev/null +++ b/lib/opencensus/trace/exporters/ocagent/converter.rb @@ -0,0 +1,346 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +module OpenCensus + module Trace + module Exporters + class OCAgent + # An object that converts OpenCensus span data objects to OpenCensus + # Agent Trace V1 protos + # + # @private + # + class Converter + # OCAgent span protobuf alias. + TraceProtos = OpenCensus::Proto::Trace::V1 + + # Maximum integer value + MAX_UINT64 = 0xffffffffffffffff + + # Create a converter + # + # @param [OpenCensus::Proto::Resource::V1::Resource] resource + def initialize resource + @resource = resource + end + + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + + # Convert OpenCensus span object to OpenCensus Agent span proto object + # + # @param [OpenCensus::Trace::Span] obj OpenCensus span object + # @return [OpenCensus::Proto::Trace::V1::Span] The generated proto + # + def convert_span obj + TraceProtos::Span.new( + trace_id: obj.trace_id, + span_id: obj.span_id, + parent_span_id: obj.parent_span_id || "", + name: convert_truncatable_string(obj.name), + kind: obj.kind, + start_time: convert_time(obj.start_time), + end_time: convert_time(obj.end_time), + attributes: convert_attributes( + obj.attributes, + obj.dropped_attributes_count + ), + stack_trace: convert_stack_trace( + obj.stack_trace, + obj.dropped_frames_count, + obj.stack_trace_hash_id + ), + time_events: convert_time_events( + obj.time_events, + obj.dropped_annotations_count, + obj.dropped_message_events_count + ), + links: convert_links(obj.links, obj.dropped_links_count), + status: convert_status(obj.status), + same_process_as_parent_span: convert_bool( + obj.same_process_as_parent_span + ), + child_span_count: convert_int32(obj.child_span_count), + resource: @resource + ) + end + + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength + + # Create a truncatable string proto. + # + # @param [String] str The string + # @param [Integer] truncated_byte_count The number of bytes omitted. + # Defaults to 0. + # @return [OpenCensus::Proto::Trace::V1::TruncatableStringg] The + # generated proto + # + def make_truncatable_string str, truncated_byte_count = 0 + TraceProtos::TruncatableString.new( + value: str, + truncated_byte_count: truncated_byte_count + ) + end + + # Convert a truncatable string object. + # + # @param [OpenCensus::Trace::TruncatableString] obj OpenCensus + # truncatable string object + # @return [OpenCensus::Proto::Trace::V1::TruncatableString] The + # generated proto + # + def convert_truncatable_string obj + make_truncatable_string obj.value, obj.truncated_byte_count + end + + # Convert a time object. + # + # @param [Time] time Ruby Time object + # @return [Google::Protobuf::Timestamp] The generated proto + def convert_time time + Google::Protobuf::Timestamp.new seconds: time.to_i, nanos: time.nsec + end + + # Convert a value that can be used for an attribute. + # + # @param [OpenCensus::Trace::TruncatableString, Integer, boolean] + # obj Object to convert + # @return [OpenCensus::Proto::Trace::V1::AttributeValue] The + # generated proto + # + def convert_attribute_value obj + case obj + when OpenCensus::Trace::TruncatableString + TraceProtos::AttributeValue.new( + string_value: convert_truncatable_string(obj) + ) + when Integer + TraceProtos::AttributeValue.new int_value: obj + when Float + TraceProtos::AttributeValue.new double_value: obj + when true, false + TraceProtos::AttributeValue.new bool_value: obj + end + end + + # Convert an attributes proto + # + # @param [Hash] attributes The map of attribute values to convert + # @param [Integer] dropped_attributes_count Number of dropped + # @return [OpenCensus::Proto::Trace::V1::Span::Attributes] The + # generated proto + # + def convert_attributes attributes, dropped_attributes_count + attribute_map = attributes.each_with_object({}) do |(k, v), r| + r[k] = convert_attribute_value(v) + end + + TraceProtos::Span::Attributes.new( + attribute_map: attribute_map, + dropped_attributes_count: dropped_attributes_count + ) + end + + # Convert a single stack frame as a Thread::Backtrace::Location + # + # @param [Thread::Backtrace::Location] frame The backtrace element to + # convert + # @return [OpenCensus::Proto::Trace::V1::StackTrace::StackFrame] + # The generated proto + # + def convert_stack_frame frame + TraceProtos::StackTrace::StackFrame.new( + function_name: make_truncatable_string(frame.label), + file_name: make_truncatable_string(frame.path), + line_number: frame.lineno + ) + end + + # Convert backtrace to stack trace proto object. + # + # @param [Array] backtrace The backtrace + # elements + # @param [Integer] dropped_frames_count Frames that were dropped + # @param [Integer] stack_trace_hash_id Hash of the data + # @return [OpenCensus::Proto::Trace::V1::StackTrace] The generated + # proto + # + def convert_stack_trace \ + backtrace, + dropped_frames_count, + stack_trace_hash_id + frame_protos = backtrace.map { |frame| convert_stack_frame(frame) } + frames_proto = TraceProtos::StackTrace::StackFrames.new( + frame: frame_protos, + dropped_frames_count: dropped_frames_count + ) + + TraceProtos::StackTrace.new( + stack_frames: frames_proto, + stack_trace_hash_id: stack_trace_hash_id & MAX_UINT64 + ) + end + + # Convert an annotation object + # + # @param [OpenCensus::Trace::Annotation] annotation The annotation + # object to convert + # @return [OpenCensus::Proto::Trace::V1::Span::TimeEvent::Annotation] + # The generated proto + # + def convert_annotation annotation + annotation_proto = TraceProtos::Span::TimeEvent::Annotation.new( + description: convert_truncatable_string(annotation.description), + attributes: convert_attributes( + annotation.attributes, + annotation.dropped_attributes_count + ) + ) + TraceProtos::Span::TimeEvent.new( + time: convert_time(annotation.time), + annotation: annotation_proto + ) + end + + # Convert a message event object + # + # @param [OpenCensus::Trace::MessageEvent] message_event The message + # event object to convert + # @return [ + # OpenCensus::Proto::Trace::V1::Span::TimeEvent::MessageEvent + # ] The generated proto + # + def convert_message_event message_event + msg_event_proto = TraceProtos::Span::TimeEvent::MessageEvent.new( + type: message_event.type, + id: message_event.id, + uncompressed_size: message_event.uncompressed_size, + compressed_size: message_event.compressed_size + ) + TraceProtos::Span::TimeEvent.new( + time: convert_time(message_event.time), + message_event: msg_event_proto + ) + end + + # Convert a list of time event objects + # + # @param [Array] time_events The time + # event objects to convert + # @param [Integer] dropped_annotations_count Number of dropped + # annotations + # @param [Integer] dropped_message_events_count Number of dropped + # message events + # @return [OpenCensus::Proto::Trace::V1::Span::TimeEvents] The + # generated proto + # + def convert_time_events \ + time_events, + dropped_annotations_count, + dropped_message_events_count + time_event_protos = time_events.map do |time_event| + case time_event + when OpenCensus::Trace::Annotation + convert_annotation time_event + when OpenCensus::Trace::MessageEvent + convert_message_event time_event + else + nil + end + end + + TraceProtos::Span::TimeEvents.new( + time_event: time_event_protos.compact, + dropped_annotations_count: dropped_annotations_count, + dropped_message_events_count: dropped_message_events_count + ) + end + + # Convert a link object + # + # @param [OpenCensus::Trace::Link] link The link object to convert + # @return [OpenCensus::Proto::Trace::V1::Span::TimeEvents::Link] The + # generated proto + # + def convert_link link + TraceProtos::Span::Link.new( + trace_id: link.trace_id, + span_id: link.span_id, + type: link.type, + attributes: convert_attributes( + link.attributes, + link.dropped_attributes_count + ) + ) + end + + # Convert a list of link objects + # + # @param [Array] links The link objects to + # convert + # @param [Integer] dropped_links_count Number of dropped links + # @return [OpenCensus::Proto::Trace::V1::Span::Link] The generated + # proto + # + def convert_links links, dropped_links_count + link_protos = links.map { |link| convert_link link } + + TraceProtos::Span::Links.new( + link: link_protos, + dropped_links_count: dropped_links_count + ) + end + + # Convert a status object + # + # @param [OpenCensus::Trace::Status, nil] status The status object to + # convert, or nil if absent + # @return [OpenCensus::Proto::Trace::V1::Status, nil] + # The generated proto, or nil + # + def convert_status status + return nil unless status + + TraceProtos::Status.new code: status.code, message: status.message + end + + # Convert a nullable boolean object + # + # @param [boolean, nil] value The value to convert, or nil if absent + # @return [Google::Protobuf::BoolValue, nil] The generated proto, + # or nil + # + def convert_bool value + return nil unless value + + Google::Protobuf::BoolValue.new value: value + end + + # Convert a int32 object + # + # @param [Integer, nil] value The value to convert, or nil if absent + # @return [Google::Protobuf::Int32Value, nil] Generated proto, or nil + # + def convert_int32 value + return nil unless value + + Google::Protobuf::UInt32Value.new value: value + end + end + end + end + end +end diff --git a/lib/opencensus/trace/exporters/ocagent/sampler.rb b/lib/opencensus/trace/exporters/ocagent/sampler.rb new file mode 100644 index 0000000..73090d9 --- /dev/null +++ b/lib/opencensus/trace/exporters/ocagent/sampler.rb @@ -0,0 +1,164 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "opencensus/proto/trace/v1/trace_config_pb" + +module OpenCensus + module Trace + module Exporters + class OCAgent + # Sampler + # + # Span sampler used to make decisions on span sampling + # + # @example Probability sampler + # require "opencensus-ocagent" + # + # OpenCensus::Trace::Exporters::OCAgent::Sampler.create_probability( + # 0.2 + # ) + # + # @example Probability sampler + # require "opencensus-ocagent" + # + # OpenCensus::Trace::Exporters::OCAgent::Sampler.create_probability( + # 0.2 + # ) + # + # @example Constant decision off sampler + # require "opencensus-ocagent" + # + # OpenCensus::Trace::Exporters::OCAgent::Sampler \ + # .create_off_constant_decision + # + # @example Constant decision on sampler + # require "opencensus-ocagent" + # + # OpenCensus::Trace::Exporters::OCAgent::Sampler \ + # .create_on_constant_decision + # + # @example Constant decision based on parent sampler + # require "opencensus-ocagent" + # + # OpenCensus::Trace::Exporters::OCAgent::Sampler \ + # .create_parent_constant_decision + # + # @example Rate limit sampler + # require "opencensus-ocagent" + # + # OpenCensus::Trace::Exporters::OCAgent::Sampler.create_rate_limit 10 + # + class Sampler + # @private + # + # @param [OpenCensus::Proto::Trace::V1::ProbabilitySampler | + # OpenCensus::Proto::Trace::V1::ConstantSampler | + # OpenCensus::Proto::Trace::V1::RateLimitingSampler] proto Sampler + # proto object. + def initialize proto + @proto = proto + end + + # Create probability sampler. + # + # Sampler that tries to uniformly sample traces with a given + # probability. + # + # @param [Float] value Probability value. + # The desired probability of sampling. Must be within 0.0 and 1.0 + # @return [OpenCensus::Trace::Exporters::Sampler] + # @raise [ArgumentError] if probability value not within 0.0 and 1.0 + # + def self.create_probability value + if value.negative? || value > 1 + raise ArgumentError, "value must be within 0.0 and 1.0" + end + + proto = OpenCensus::Proto::Trace::V1::ProbabilitySampler.new( + samplingProbability: value + ) + new proto + end + + # Create constant decision sampler that always off span sampling + # + # @return [OpenCensus::Trace::Exporters::Sampler] + # + def self.create_off_constant_decision + proto = OpenCensus::Proto::Trace::V1::ConstantSampler.new( + decision: :ALWAYS_OFF + ) + new proto + end + + # Create constant decision sampler that always on span sampling. + # + # @return [OpenCensus::Trace::Exporters::Sampler] + # + def self.create_on_constant_decision + proto = OpenCensus::Proto::Trace::V1::ConstantSampler.new( + decision: :ALWAYS_ON + ) + new proto + end + + # Create constant decision sampler that always follow the parent + # Span's decision (off if no parent). + # + # @return [OpenCensus::Trace::Exporters::Sampler] + # + def self.create_parent_constant_decision + proto = OpenCensus::Proto::Trace::V1::ConstantSampler.new( + decision: :ALWAYS_PARENT + ) + new proto + end + + # Sampler that tries to sample with a rate per time window + # + # @param [Integer] value Rate per second + # @return [OpenCensus::Trace::Exporters::Sampler] + # + def self.create_rate_limit value + if value.negative? + raise ArgumentError, "value must be greater then or equal to zero" + end + + proto = OpenCensus::Proto::Trace::V1::RateLimitingSampler.new( + qps: value + ) + new proto + end + + # @private + # + # Get sampler gRPC proto object + # + # @return [ + # OpenCensus::Proto::Trace::V1::ProbabilitySampler, + # OpenCensus::Proto::Trace::V1::ConstantSampler, + # OpenCensus::Proto::Trace::V1::RateLimitingSampler + # ] + # + def to_proto + @proto + end + end + end + end + end +end diff --git a/lib/opencensus/trace/exporters/ocagent/trace_enumerator_queue.rb b/lib/opencensus/trace/exporters/ocagent/trace_enumerator_queue.rb new file mode 100644 index 0000000..8928fe3 --- /dev/null +++ b/lib/opencensus/trace/exporters/ocagent/trace_enumerator_queue.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +module OpenCensus + module Trace + module Exporters + class OCAgent + # TraceEnumeratorQueue insert trace request object in queue and send to + # gRPC stream. + # + # @private + # + class TraceEnumeratorQueue + # Stop queue item value + SENTINEL = :STOP + + # @param [Float] delay Sleeping time when there no trace object to + # send. + def initialize delay + @queue = Queue.new + @delay = delay + end + + # Intsert trace object into queue. + # + # @param [OpenCensus::Proto::Agent::Trace::V1:: \ + # ExportTraceServiceRequest] item + def push item + @queue << item + end + + # Enumerator of queue items + # @return [Enumerator] + def each_item + return enum_for(:each_item) unless block_given? + + loop do + item = @queue.pop + break if item == SENTINEL + + if item + yield item + else + sleep @delay + end + end + end + end + end + end + end +end diff --git a/opencensus-ocagent.gemspec b/opencensus-ocagent.gemspec index 76fb536..c307562 100644 --- a/opencensus-ocagent.gemspec +++ b/opencensus-ocagent.gemspec @@ -37,6 +37,8 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 2.3.0" spec.add_dependency "opencensus", "~> 0.4.0" + spec.add_dependency "grpc", "~> 1.19" + spec.add_dependency "concurrent-ruby", "~> 1.1.5" spec.add_development_dependency "bundler", ">= 1.17", "< 3.0" spec.add_development_dependency "faraday", "~> 0.13" @@ -45,8 +47,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency "minitest-rg", "~> 5.2" spec.add_development_dependency "rake", "~> 12.0" spec.add_development_dependency "redcarpet", "~> 3.4" - spec.add_development_dependency "rubocop", "~> 0.63.1" spec.add_development_dependency "toys", "~> 0.7" spec.add_development_dependency "yard", "~> 0.9" spec.add_development_dependency "yard-doctest", "~> 0.1.6" + spec.add_development_dependency "google-style", "~> 0.1.0" end diff --git a/test/library_test.rb b/test/library_test.rb index 4133dd9..7561b95 100644 --- a/test/library_test.rb +++ b/test/library_test.rb @@ -21,4 +21,41 @@ it "has a version number" do refute_nil OpenCensus::OCAgent::VERSION end + + it "export spans to agent service" do + skip unless ENV["AGENT_SERVICE_ADDRESS"] + + exporter = OpenCensus::Trace::Exporters::OCAgent.new( + service_name: "RubyOCAgent-Test", + agent_service_address: ENV["AGENT_SERVICE_ADDRESS"] + ) + OpenCensus::Trace.configure do |config| + config.exporter = exporter + end + + OpenCensus::Trace.start_request_trace do |root_context| + OpenCensus::Trace.in_span("span1") do |span1| + span1.put_attribute :data, "Outer span" + sleep 0.1 + OpenCensus::Trace.in_span("span2") do |span2| + span2.put_attribute :data, "Inner span" + sleep 0.2 + end + OpenCensus::Trace.in_span("span3") do |span3| + span3.put_attribute :data, "Another inner span" + sleep 0.1 + end + end + exporter.export root_context.build_contained_spans + end + OpenCensus::Trace.start_request_trace do |root_context| + OpenCensus::Trace.in_span("span4") do |span4| + span4.put_attribute :data, "Fast span" + end + exporter.export root_context.build_contained_spans + end + + exporter.stop + sleep 1 + end end diff --git a/test/trace/exporter/ocagent/converter_test.rb b/test/trace/exporter/ocagent/converter_test.rb new file mode 100644 index 0000000..83c17f3 --- /dev/null +++ b/test/trace/exporter/ocagent/converter_test.rb @@ -0,0 +1,335 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "helper" + +describe OpenCensus::Trace::Exporters::OCAgent::Converter do + let(:service_name) { "ocagent-trace-exporter-service"} + let(:resource) { + OpenCensus::Proto::Resource::V1::Resource.new(type: "test") + } + let(:converter) { + OpenCensus::Trace::Exporters::OCAgent::Converter.new(resource) + } + let(:trace_id) { "0123456789abcdef0123456789abcdef" } + let(:trace_id2) { "fedcba9876543210fedcba9876543210" } + let(:span_id) { "0123456789abcdef" } + let(:span_id2) { "fedcba9876543210" } + let(:simple_string) { "hello" } + let(:string_truncated_bytes) { 5 } + let(:truncatable_string) { + OpenCensus::Trace::TruncatableString.new( + simple_string, + truncated_byte_count: string_truncated_bytes + ) + } + let(:loc1) { + OpenStruct.new label: "foo", path: "/path/to/file.rb", lineno: 100 + } + let(:loc2) { + OpenStruct.new label: "bar", path: "/path/to/another/file.rb", lineno: 200 + } + let(:annotation_desc) { "This is an annotation" } + let(:annotation) { + OpenCensus::Trace::Annotation.new( + OpenCensus::Trace::TruncatableString.new(annotation_desc), + attributes: {"foo" => truncatable_string}, + dropped_attributes_count: 1, + time: Time.at(1001) + ) + } + let(:message_event) { + OpenCensus::Trace::MessageEvent.new( + OpenCensus::Trace::MessageEvent::SENT, 12345, 100, time: Time.at(1002) + ) + } + let(:link1) { + OpenCensus::Trace::Link.new trace_id, span_id, + type: OpenCensus::Trace::Link::CHILD_LINKED_SPAN, + attributes: {"foo" => truncatable_string}, + dropped_attributes_count: 1 + } + let(:link2) { + OpenCensus::Trace::Link.new trace_id2, span_id2, + type: OpenCensus::Trace::Link::PARENT_LINKED_SPAN, + attributes: {"foo" => 123}, + dropped_attributes_count: 2 + } + let(:status) { + OpenCensus::Trace::Status.new 404, "Not found" + } + + describe "#make_truncatable_string" do + it "create with default value" do + proto = converter.make_truncatable_string "test" + proto.value.must_equal "test" + proto.truncated_byte_count.must_equal 0 + end + + it "create with byte count" do + proto = converter.make_truncatable_string "test", 5 + proto.value.must_equal "test" + proto.truncated_byte_count.must_equal 5 + end + end + + describe "#convert_truncatable_string" do + it "converts a truncatable string" do + proto = converter.convert_truncatable_string truncatable_string + proto.value.must_equal simple_string + proto.truncated_byte_count.must_equal string_truncated_bytes + end + end + + describe "#convert_time" do + it "converts to protobuf timestamp object" do + time = Time.now + proto = converter.convert_time time + proto.seconds.must_equal time.to_i + proto.nanos.must_equal time.nsec + end + end + + describe "#convert_attribute_value" do + it "converts a string" do + proto = converter.convert_attribute_value truncatable_string + proto.string_value.value.must_equal simple_string + proto.string_value.truncated_byte_count.must_equal string_truncated_bytes + proto.value.must_equal :string_value + end + + it "converts an integer" do + proto = converter.convert_attribute_value(-1000) + proto.int_value.must_equal(-1000) + proto.value.must_equal :int_value + end + + it "converts an double" do + proto = converter.convert_attribute_value 10.1 + proto.double_value.must_equal 10.1 + proto.value.must_equal :double_value + end + + it "converts a boolean" do + proto = converter.convert_attribute_value false + proto.bool_value.must_equal false + proto.value.must_equal :bool_value + end + end + + describe "#convert_attributes" do + it "converts attributes of different types" do + input_attrs = { + "str" => truncatable_string, + "int" => 100, + "double" => 51.1, + "bool" => false + } + + proto = converter.convert_attributes input_attrs, 2 + proto.attribute_map["str"].string_value.value.must_equal simple_string + proto.attribute_map["str"].string_value.truncated_byte_count.must_equal string_truncated_bytes + proto.attribute_map["str"].value.must_equal :string_value + + proto.attribute_map["int"].int_value.must_equal(100) + proto.attribute_map["int"].value.must_equal :int_value + + proto.attribute_map["double"].double_value.must_equal(51.1) + proto.attribute_map["double"].value.must_equal :double_value + + proto.attribute_map["bool"].bool_value.must_equal false + proto.attribute_map["bool"].value.must_equal :bool_value + proto.dropped_attributes_count.must_equal 2 + end + end + + describe "#convert_stack_frame" do + it "converts a location" do + proto = converter.convert_stack_frame loc1 + proto.function_name.value.must_equal "foo" + proto.function_name.truncated_byte_count.must_equal 0 + proto.file_name.value.must_equal "/path/to/file.rb" + proto.file_name.truncated_byte_count.must_equal 0 + proto.line_number.must_equal 100 + end + end + + describe "#convert_stack_trace" do + it "converts a location" do + proto = converter.convert_stack_trace [loc1, loc2], 3, 12345 + proto.stack_frames.frame.length.must_equal 2 + proto.stack_frames.frame[0].function_name.value.must_equal "foo" + proto.stack_frames.frame[1].function_name.value.must_equal "bar" + proto.stack_frames.dropped_frames_count.must_equal 3 + proto.stack_trace_hash_id.must_equal 12345 + end + end + + describe "#convert_annotation" do + it "converts an annotation" do + proto = converter.convert_annotation annotation + proto.annotation.description.value.must_equal annotation_desc + proto.annotation.description.truncated_byte_count.must_equal 0 + proto.annotation.attributes.dropped_attributes_count.must_equal 1 + proto.annotation.attributes.attribute_map["foo"].string_value.value.must_equal simple_string + proto.annotation.attributes.attribute_map["foo"].string_value.truncated_byte_count.must_equal string_truncated_bytes + proto.time.seconds.must_equal 1001 + end + end + + describe "#convert_message_event" do + it "converts a message event" do + proto = converter.convert_message_event message_event + proto.message_event.type.must_equal :SENT + proto.message_event.id.must_equal 12345 + proto.message_event.uncompressed_size.must_equal 100 + proto.message_event.compressed_size.must_equal 0 + proto.time.seconds.must_equal 1002 + end + end + + describe "#convert_time_events" do + it "converts a set of time events" do + proto = converter.convert_time_events [message_event, annotation], 4, 5 + proto.time_event.length.must_equal 2 + proto.time_event[0].message_event.type.must_equal :SENT + proto.time_event[1].annotation.description.value.must_equal annotation_desc + proto.dropped_annotations_count.must_equal 4 + proto.dropped_message_events_count.must_equal 5 + end + end + + describe "#convert_link" do + it "converts a link" do + proto = converter.convert_link link1 + proto.trace_id.must_equal trace_id + proto.span_id.must_equal span_id + proto.type.must_equal :CHILD_LINKED_SPAN + proto.attributes.dropped_attributes_count.must_equal 1 + proto.attributes.attribute_map["foo"].string_value.value.must_equal simple_string + end + end + + describe "#convert_links" do + it "converts a set of links" do + proto = converter.convert_links [link1, link2], 3 + proto.link.length.must_equal 2 + proto.link[0].type.must_equal :CHILD_LINKED_SPAN + proto.link[1].type.must_equal :PARENT_LINKED_SPAN + proto.dropped_links_count.must_equal 3 + end + end + + describe "#convert_status" do + it "converts a status" do + proto = converter.convert_status status + proto.code.must_equal 404 + proto.message.must_equal "Not found" + end + + it "converts nil" do + proto = converter.convert_status nil + proto.must_be_nil + end + end + + describe "#convert_status" do + it "converts a status" do + proto = converter.convert_status status + proto.code.must_equal 404 + proto.message.must_equal "Not found" + end + + it "converts nil" do + proto = converter.convert_status nil + proto.must_be_nil + end + end + + describe "#convert_bool" do + it "converts a boolean" do + proto = converter.convert_bool true + proto.value.must_equal true + end + + it "converts nil" do + proto = converter.convert_bool nil + proto.must_be_nil + end + end + + describe "#convert_int32" do + it "converts a integer" do + proto = converter.convert_int32 1000 + proto.value.must_equal 1000 + end + + it "converts nil" do + proto = converter.convert_int32 nil + proto.must_be_nil + end + end + + describe "#convert_span" do + it "converts a basic span" do + span = OpenCensus::Trace::Span.new( + trace_id, + span_id, + truncatable_string, + Time.at(1000), + Time.at(2000), + parent_span_id: span_id2, + attributes: {"foo" => 123}, + dropped_attributes_count: 1, + stack_trace: [loc1, loc2], + dropped_frames_count: 2, + time_events: [annotation, message_event], + dropped_annotations_count: 3, + dropped_message_events_count: 4, + links: [link1, link2], + dropped_links_count: 5, + status: status, + same_process_as_parent_span: true, + child_span_count: 6 + ) + proto = converter.convert_span span + proto.trace_id.must_equal trace_id + proto.span_id.must_equal span_id + proto.name.value.must_equal simple_string + proto.name.truncated_byte_count.must_equal string_truncated_bytes + proto.parent_span_id.must_equal span_id2 + proto.start_time.seconds.must_equal 1000 + proto.end_time.seconds.must_equal 2000 + proto.attributes.attribute_map["foo"].int_value.must_equal 123 + proto.attributes.dropped_attributes_count.must_equal 1 + proto.stack_trace.stack_frames.frame[0].function_name.value.must_equal "foo" + proto.stack_trace.stack_frames.dropped_frames_count.must_equal 2 + proto.time_events.time_event[0].time.seconds.must_equal 1001 + proto.time_events.time_event[0].annotation.description.value.must_equal annotation_desc + proto.time_events.time_event[1].time.seconds.must_equal 1002 + proto.time_events.time_event[1].message_event.type.must_equal :SENT + proto.time_events.dropped_annotations_count.must_equal 3 + proto.time_events.dropped_message_events_count.must_equal 4 + proto.links.link[0].type.must_equal :CHILD_LINKED_SPAN + proto.links.link[1].type.must_equal :PARENT_LINKED_SPAN + proto.links.dropped_links_count.must_equal 5 + proto.status.code.must_equal 404 + proto.same_process_as_parent_span.value.must_equal true + proto.child_span_count.value.must_equal 6 + end + end +end diff --git a/test/trace/exporter/ocagent/sampler_test.rb b/test/trace/exporter/ocagent/sampler_test.rb new file mode 100644 index 0000000..9d932dd --- /dev/null +++ b/test/trace/exporter/ocagent/sampler_test.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "helper" + +describe OpenCensus::Trace::Exporters::OCAgent::Sampler do + let(:sampler_class){ + OpenCensus::Trace::Exporters::OCAgent::Sampler + } + describe "#create_probability" do + it "create sampler" do + sampler = sampler_class.create_probability 0.1 + sampler.to_proto.samplingProbability.must_equal 0.1 + end + + it "raise error if probability less then 0 " do + proc { + sampler_class.create_probability(-0.1) + }.must_raise ArgumentError + end + + it "raise error if probability greater then 1 " do + proc { + sampler_class.create_probability 1.1 + }.must_raise ArgumentError + end + end + + describe "#create_off_constant_decision" do + it "create sampler" do + sampler = sampler_class.create_off_constant_decision + sampler.to_proto.decision.must_equal :ALWAYS_OFF + end + end + + describe "#create_on_constant_decision" do + it "create sampler" do + sampler = sampler_class.create_on_constant_decision + sampler.to_proto.decision.must_equal :ALWAYS_ON + end + end + + describe "#create_parent_constant_decision" do + it "create sampler" do + sampler = sampler_class.create_parent_constant_decision + sampler.to_proto.decision.must_equal :ALWAYS_PARENT + end + end + + describe "#create_rate_limit" do + it "create sampler" do + sampler = sampler_class.create_rate_limit 100 + sampler.to_proto.qps.must_equal 100 + end + + it "raise error if value less then 0" do + proc { + sampler_class.create_probability(-10) + }.must_raise ArgumentError + end + end +end diff --git a/test/trace/exporter/ocagent/trace_enumerator_queue_test.rb b/test/trace/exporter/ocagent/trace_enumerator_queue_test.rb new file mode 100644 index 0000000..ac1d984 --- /dev/null +++ b/test/trace/exporter/ocagent/trace_enumerator_queue_test.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "helper" + +describe OpenCensus::Trace::Exporters::OCAgent::TraceEnumeratorQueue do + describe "#each_item" do + it "add items and iterate" do + enumerator = OpenCensus::Trace::Exporters::OCAgent::TraceEnumeratorQueue.new 0.1 + enumerator.push "item1" + enumerator.push "item2" + enumerator.push :STOP + + items = enumerator.each_item.map{ |v| v } + items.length.must_equal 2 + items[0].must_equal "item1" + items[1].must_equal "item2" + end + end +end diff --git a/test/trace/ocagent_test.rb b/test/trace/ocagent_test.rb new file mode 100644 index 0000000..896e483 --- /dev/null +++ b/test/trace/ocagent_test.rb @@ -0,0 +1,122 @@ +# frozen_string_literal: true + +# Copyright 2019 OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "helper" + +describe OpenCensus::Trace::Exporters::OCAgent do + let(:service_name) { "ocagent-trace-exporter-service"} + let(:trace_id) { "e8b86184bbb7f57f0aa3f6fd36c8f268" } + let(:span1_id) { "4e24dd9d2724a35f" } + let(:span2_id) { "140a0f209cfa84a6" } + let(:truncatable_string) { + OpenCensus::Trace::TruncatableString.new("Hello", truncated_byte_count: 0) + } + let(:span1){ + OpenCensus::Trace::Span.new( + trace_id, + span1_id, + truncatable_string, + Time.now, + Time.now + 1 + ) + } + let(:span2){ + OpenCensus::Trace::Span.new( + trace_id, + span2_id, + truncatable_string, + Time.now, + Time.now + 1 + ) + } + + describe "#create" do + it "create exporter instance with default values" do + oc_agent = OpenCensus::Trace::Exporters::OCAgent.new service_name: service_name + + oc_agent.service_name.must_equal service_name + oc_agent.agent_service_address.must_equal "localhost:55678" + oc_agent.credentials.must_equal :this_channel_is_insecure + + identifier = oc_agent.node_info.identifier + identifier.host_name.must_equal Socket.gethostname + identifier.pid.must_equal Process.pid + identifier.start_timestamp.seconds.must_be_close_to Time.now.utc.to_i + + library_info = oc_agent.node_info.library_info + library_info.language.must_equal :RUBY + library_info.exporter_version.must_equal OpenCensus::OCAgent::VERSION + library_info.core_library_version.must_equal OpenCensus::VERSION + + oc_agent.node_info.service_info.name.must_equal service_name + end + + it "create exporter instance with agent address" do + agent_service_address = "test-ocagent-host:7777" + oc_agent = OpenCensus::Trace::Exporters::OCAgent.new( + service_name: service_name, + agent_service_address: agent_service_address + ) + + oc_agent.agent_service_address.must_equal agent_service_address + end + + it "create exporter instance with TLS credentials file" do + oc_agent = OpenCensus::Trace::Exporters::OCAgent.new( + service_name: service_name, + credentials: "my-test.pem" + ) + + oc_agent.credentials.must_be_instance_of GRPC::Core::ChannelCredentials + end + end + + describe "#export" do + it "export spans and stop exporter" do + result = OpenStruct.new(requests: [], responses: []) + mock_stub = Minitest::Mock.new(result) + + def mock_stub.export req, &block + Enumerator.new do |y| + req.each do |trace| + self.requests << trace + self.responses << OpenCensus::Proto::Agent::Trace::V1::ExportTraceServiceResponse.new + end + end + end + + OpenCensus::Proto::Agent::Trace::V1::TraceService::Stub.stub(:new, mock_stub) do + oc_agent = OpenCensus::Trace::Exporters::OCAgent.new( + service_name: service_name + ) + oc_agent.export [span1] + oc_agent.export [span2] + oc_agent.stop + + # Wait unitl request queue cleared. + sleep 1 + oc_agent.stopped?.must_equal true + result.requests.length.must_equal 2 + result.responses.length.must_equal 2 + + oc_agent.export [span1] + trace_req_queue = oc_agent.instance_variable_get("@trace_req_queue") + trace_req_queue.instance_variable_get("@queue").empty?.must_equal true + end + end + end +end