opentelemetry-exporter-google_cloud_trace 0.a → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +21 -0
- data/.yardopts +15 -0
- data/AUTHENTICATION.md +142 -0
- data/CHANGELOG.md +13 -0
- data/CODE_OF_CONDUCT.md +43 -0
- data/CONTRIBUTING.md +138 -0
- data/Gemfile +27 -0
- data/LICENSE +201 -0
- data/README.md +51 -8
- data/Rakefile +61 -0
- data/acceptance/sinatra/gcp_trace_exporter_test.rb +99 -0
- data/acceptance/sinatra/sinatra_app.rb +25 -0
- data/acceptance/test_helper.rb +25 -0
- data/lib/opentelemetry/exporter/google_cloud_trace/span_exporter.rb +145 -0
- data/lib/opentelemetry/exporter/google_cloud_trace/translator.rb +239 -0
- data/lib/opentelemetry/exporter/google_cloud_trace/version.rb +6 -3
- data/lib/opentelemetry/exporter/google_cloud_trace.rb +37 -0
- data/lib/opentelemetry-exporter-google_cloud_trace.rb +17 -0
- data/opentelemetry-exporter-google_cloud_trace.gemspec +61 -0
- metadata +270 -17
- data/LICENSE.md +0 -201
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
|
18
|
+
require "bundler/gem_tasks"
|
19
|
+
require "rake/testtask"
|
20
|
+
|
21
|
+
Rake::TestTask.new :test do |t|
|
22
|
+
t.libs << "test"
|
23
|
+
t.libs << "lib"
|
24
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
25
|
+
end
|
26
|
+
|
27
|
+
require "yard"
|
28
|
+
require "yard/rake/yardoc_task"
|
29
|
+
YARD::Rake::YardocTask.new do |y|
|
30
|
+
# y.options << "--fail-on-warning"
|
31
|
+
end
|
32
|
+
|
33
|
+
task :acceptance, :project, :keyfile do |_t, args|
|
34
|
+
project = args[:project]
|
35
|
+
project ||= ENV["TRACE_EXPORTER_TEST_PROJECT"] || ENV["GCLOUD_TEST_PROJECT"]
|
36
|
+
keyfile = args[:keyfile]
|
37
|
+
keyfile ||= ENV["TRACE_EXPORTER_TEST_KEYFILE"] || ENV["GCLOUD_TEST_KEYFILE"]
|
38
|
+
if keyfile
|
39
|
+
keyfile = File.read keyfile
|
40
|
+
end
|
41
|
+
if project.nil? || keyfile.nil?
|
42
|
+
raise "You must provide a project and keyfile. e.g. rake acceptance[test123, /path/to/keyfile.json] or " \
|
43
|
+
"TRACE_EXPORTER_TEST_PROJECT=test123 TRACE_EXPORTER_TEST_KEYFILE=/path/to/keyfile.json rake acceptance"
|
44
|
+
end
|
45
|
+
|
46
|
+
Rake::Task["acceptance:run"].invoke
|
47
|
+
end
|
48
|
+
|
49
|
+
namespace :acceptance do
|
50
|
+
Rake::TestTask.new :run do |t|
|
51
|
+
t.libs << "acceptance"
|
52
|
+
t.libs << "lib"
|
53
|
+
t.test_files = FileList["acceptance/**/*_test.rb"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
require "rubocop/rake_task"
|
58
|
+
|
59
|
+
RuboCop::RakeTask.new
|
60
|
+
|
61
|
+
task default: [:test, :rubocop]
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "test_helper"
|
18
|
+
require "webrick"
|
19
|
+
require "fileutils"
|
20
|
+
require "google/protobuf/well_known_types"
|
21
|
+
|
22
|
+
# Test the Sinatra server for the Cloud Scheduler sample.
|
23
|
+
describe "Opentelemety exporter for Google Cloud Trace" do
|
24
|
+
before :all do
|
25
|
+
@project_id = ENV["TRACE_EXPORTER_TEST_PROJECT"] || ENV["GCLOUD_TEST_PROJECT"]
|
26
|
+
Google::Cloud.configure do |config|
|
27
|
+
config.project_id = @project_id
|
28
|
+
config.credentials = ENV["TRACE_EXPORTER_TEST_KEYFILE"] || ENV["GCLOUD_TEST_KEYFILE"]
|
29
|
+
end
|
30
|
+
|
31
|
+
@pid = Process.spawn "bundle exec ruby acceptance/sinatra/sinatra_app.rb"
|
32
|
+
|
33
|
+
# wait for server to start
|
34
|
+
sleep 10
|
35
|
+
@trace_client = Google::Cloud::Trace::V1::TraceService::Client.new
|
36
|
+
end
|
37
|
+
|
38
|
+
after :all do
|
39
|
+
Process.kill "KILL", @pid
|
40
|
+
Process.wait2 @pid
|
41
|
+
end
|
42
|
+
|
43
|
+
it "test_returns_hello_world" do
|
44
|
+
uri = URI("http://127.0.0.1:4567")
|
45
|
+
start_time = Google::Protobuf::Timestamp.from_time Time.now
|
46
|
+
res = Net::HTTP.get uri
|
47
|
+
assert_match "Hello !", res
|
48
|
+
sleep 10 # wait for trace to be sent
|
49
|
+
end_time = Google::Protobuf::Timestamp.from_time Time.now
|
50
|
+
|
51
|
+
assert_trace start_time, end_time
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def assert_trace start_time, end_time
|
56
|
+
result = @trace_client.list_traces project_id: @project_id, start_time: start_time, end_time: end_time
|
57
|
+
traces = result.response.traces
|
58
|
+
test_span = nil
|
59
|
+
parent_span = nil
|
60
|
+
|
61
|
+
traces.each do |trace|
|
62
|
+
full_trace = @trace_client.get_trace project_id: @project_id, trace_id: trace.trace_id
|
63
|
+
full_trace.spans.each do |span|
|
64
|
+
if span.name === "test_span"
|
65
|
+
test_span = span
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
if test_span
|
71
|
+
parent_span = full_trace.spans.find { |span| span.span_id === test_span.parent_span_id }
|
72
|
+
break
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
assert_child_span test_span
|
77
|
+
assert_parent_span parent_span
|
78
|
+
end
|
79
|
+
|
80
|
+
def assert_child_span span
|
81
|
+
refute_nil span
|
82
|
+
assert_equal span.labels["span_attr"], "span_value"
|
83
|
+
end
|
84
|
+
|
85
|
+
def assert_parent_span span
|
86
|
+
refute_nil span
|
87
|
+
assert_equal span.kind, :RPC_SERVER
|
88
|
+
assert_equal span.name, "GET /"
|
89
|
+
assert_equal span.labels["g.co/agent"], "opentelemetry-ruby #{OpenTelemetry::SDK::VERSION};" \
|
90
|
+
"google-cloud-trace-exporter " \
|
91
|
+
"#{OpenTelemetry::Exporter::GoogleCloudTrace::VERSION}"
|
92
|
+
assert_equal span.labels["/http/client_protocol"], "http"
|
93
|
+
assert_equal span.labels["/http/status_code"], "200"
|
94
|
+
assert_equal span.labels["http.target"], "/"
|
95
|
+
assert_equal span.labels["/http/method"], "GET"
|
96
|
+
assert_equal span.labels["/http/host"], "127.0.0.1:4567"
|
97
|
+
assert_equal span.labels["/http/route"], "/"
|
98
|
+
assert_equal span.labels["/http/user_agent"], "Ruby"
|
99
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "sinatra"
|
2
|
+
require "opentelemetry-sdk"
|
3
|
+
require "opentelemetry/instrumentation/sinatra"
|
4
|
+
require "opentelemetry/instrumentation/rack"
|
5
|
+
require "opentelemetry/exporter/google_cloud_trace"
|
6
|
+
|
7
|
+
OpenTelemetry::SDK.configure do |c|
|
8
|
+
c.service_name = "test_app"
|
9
|
+
c.add_span_processor(
|
10
|
+
OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
|
11
|
+
OpenTelemetry::Exporter::GoogleCloudTrace::SpanExporter.new
|
12
|
+
)
|
13
|
+
)
|
14
|
+
c.use "OpenTelemetry::Instrumentation::Sinatra"
|
15
|
+
end
|
16
|
+
|
17
|
+
get "/" do
|
18
|
+
test_tracer = OpenTelemetry.tracer_provider.tracer "test_tracer"
|
19
|
+
span_to_link_from = OpenTelemetry::Trace.current_span
|
20
|
+
link = OpenTelemetry::Trace::Link.new(span_to_link_from.context, { "some.attribute" => 12 })
|
21
|
+
test_tracer.in_span "test_span", attributes: { "span_attr" => "span_value" }, links: [link] do |span|
|
22
|
+
span.add_event "Creating test span event!!", attributes: { "event_attr" => "event_value" }
|
23
|
+
end
|
24
|
+
"Hello !"
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
|
18
|
+
require "minitest/autorun"
|
19
|
+
require "minitest/focus"
|
20
|
+
require "minitest/hooks/default"
|
21
|
+
require "minitest/rg"
|
22
|
+
require "ostruct"
|
23
|
+
require "google/cloud"
|
24
|
+
require "google/cloud/trace/v1"
|
25
|
+
require "opentelemetry/exporter/google_cloud_trace"
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
|
18
|
+
require "google/cloud/trace/v2/trace_service"
|
19
|
+
require "opentelemetry/exporter/google_cloud_trace/translator"
|
20
|
+
require "google/cloud/env"
|
21
|
+
|
22
|
+
module OpenTelemetry
|
23
|
+
module Exporter
|
24
|
+
module GoogleCloudTrace
|
25
|
+
##
|
26
|
+
# This provides an implementation of span exporter for Google Cloud Trace
|
27
|
+
# It will convert the Opentelemetry span data into Clould Trace spans
|
28
|
+
# and publish them to the Cloud trace service.
|
29
|
+
class SpanExporter
|
30
|
+
SUCCESS = OpenTelemetry::SDK::Trace::Export::SUCCESS
|
31
|
+
FAILURE = OpenTelemetry::SDK::Trace::Export::FAILURE
|
32
|
+
private_constant :SUCCESS, :FAILURE
|
33
|
+
|
34
|
+
|
35
|
+
##
|
36
|
+
# Creates a new object for google cloud trace
|
37
|
+
# opentelemetry span exporter. It creates client for
|
38
|
+
# Google cloud trace service to be used for publihing span.
|
39
|
+
#
|
40
|
+
#
|
41
|
+
# @param [String] project_id Project identifier for the Trace service
|
42
|
+
# you are connecting to. If not present, the default project for the
|
43
|
+
# credentials is used.
|
44
|
+
# @param [String, Hash, Google::Auth::Credentials] credentials The path to
|
45
|
+
# the keyfile as a String, the contents of the keyfile as a Hash, or a
|
46
|
+
# Google::Auth::Credentials object.
|
47
|
+
# @param [String, Array<String>] scope The OAuth 2.0 scopes controlling
|
48
|
+
# the set of resources and operations that the connection can access.
|
49
|
+
# See [Using OAuth 2.0 to Access Google
|
50
|
+
# APIs](https://developers.google.com/identity/protocols/OAuth2).
|
51
|
+
#
|
52
|
+
# The default scope is:
|
53
|
+
#
|
54
|
+
# * `https://www.googleapis.com/auth/trace.append`
|
55
|
+
# @param [Numeric] timeout Default timeout to use in requests. Optional.
|
56
|
+
# @param [String] endpoint Override of the endpoint host name. Optional.
|
57
|
+
# If the param is nil, uses the default endpoint.
|
58
|
+
#
|
59
|
+
# @return [OpenTelemetry::Exporter::GoogleCloudTrace::SpanExporter]
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# require 'opentelemetry/sdk'
|
63
|
+
# require 'opentelemetry/instrumentation/all'
|
64
|
+
# require 'opentelemetry/exporter/google_cloud_trace'
|
65
|
+
# OpenTelemetry::SDK.configure do |c|
|
66
|
+
# c.service_name = 'test_app'
|
67
|
+
# c.add_span_processor(
|
68
|
+
# OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
|
69
|
+
# OpenTelemetry::Exporter::GoogleCloudTrace::SpanExporter.new
|
70
|
+
# )
|
71
|
+
# )
|
72
|
+
# c.use_all() # enables all instrumentation!
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
def initialize project_id: nil,
|
76
|
+
credentials: nil,
|
77
|
+
scope: nil,
|
78
|
+
timeout: nil,
|
79
|
+
endpoint: nil
|
80
|
+
|
81
|
+
@client = ::Google::Cloud::Trace::V2::TraceService::Client.new do |config|
|
82
|
+
config.project_id = project_id if project_id
|
83
|
+
config.credentials = credentials if credentials
|
84
|
+
config.scope = scope if scope
|
85
|
+
config.timeout = timeout if timeout
|
86
|
+
config.endpoint = endpoint if endpoint
|
87
|
+
end
|
88
|
+
@project_id = (project_id || default_project_id || credentials&.project_id)
|
89
|
+
@project_id = @project_id.to_s
|
90
|
+
raise ArgumentError, "project_id is missing" if @project_id.empty?
|
91
|
+
@shutdown = false
|
92
|
+
@translator = Translator.new @project_id
|
93
|
+
end
|
94
|
+
|
95
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
96
|
+
# timeout is needed to match Opentelemetry exporter interface
|
97
|
+
|
98
|
+
# Called to export sampled {OpenTelemetry::SDK::Trace::SpanData} structs.
|
99
|
+
#
|
100
|
+
# @param [Enumerable<OpenTelemetry::SDK::Trace::SpanData>] span_data the
|
101
|
+
# list of recorded {OpenTelemetry::SDK::Trace::SpanData} structs to be
|
102
|
+
# exported.
|
103
|
+
# @return [Integer] the result of the export.
|
104
|
+
def export span_data, timeout: nil
|
105
|
+
return FAILURE if @shutdown
|
106
|
+
|
107
|
+
begin
|
108
|
+
batch_request = @translator.create_batch span_data
|
109
|
+
@client.batch_write_spans batch_request
|
110
|
+
SUCCESS
|
111
|
+
rescue StandardError
|
112
|
+
FAILURE
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Called when {OpenTelemetry::SDK::Trace::TracerProvider#force_flush} is called, if
|
117
|
+
# this exporter is registered to a {OpenTelemetry::SDK::Trace::TracerProvider}
|
118
|
+
# object.
|
119
|
+
def force_flush timeout: nil
|
120
|
+
SUCCESS
|
121
|
+
end
|
122
|
+
|
123
|
+
# Called when {OpenTelemetry::SDK::Trace::TracerProvider#shutdown} is called, if
|
124
|
+
# this exporter is registered to a {OpenTelemetry::SDK::Trace::TracerProvider}
|
125
|
+
# object.
|
126
|
+
def shutdown timeout: nil
|
127
|
+
@shutdown = true
|
128
|
+
SUCCESS
|
129
|
+
end
|
130
|
+
|
131
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def default_project_id
|
136
|
+
Google::Cloud.env.project_id
|
137
|
+
end
|
138
|
+
|
139
|
+
def shutdown?
|
140
|
+
@shutdown
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
|
18
|
+
require "google/protobuf/well_known_types"
|
19
|
+
require "google/rpc/status_pb"
|
20
|
+
require "google/rpc/code_pb"
|
21
|
+
require "opentelemetry/trace/status"
|
22
|
+
require "opentelemetry/trace/span_kind"
|
23
|
+
require "opentelemetry/exporter/google_cloud_trace/version"
|
24
|
+
|
25
|
+
module OpenTelemetry
|
26
|
+
module Exporter
|
27
|
+
module GoogleCloudTrace
|
28
|
+
##
|
29
|
+
# @private
|
30
|
+
# This class helps translating the opentelemetry
|
31
|
+
# span data [Enumerable<OpenTelemetry::SDK::Trace::SpanData>] into
|
32
|
+
# cloud trace spans [Google::Cloud::Trace::V2::Span]
|
33
|
+
class Translator
|
34
|
+
MAX_LINKS = 128
|
35
|
+
MAX_EVENTS = 32
|
36
|
+
MAX_EVENT_ATTRIBUTES = 4
|
37
|
+
MAX_LINK_ATTRIBUTES = 32
|
38
|
+
MAX_SPAN_ATTRIBUTES = 32
|
39
|
+
MAX_ATTRIBUTES_KEY_BYTES = 128
|
40
|
+
MAX_ATTRIBUTES_VAL_BYTES = 16 * 1024 # 16 kilobytes
|
41
|
+
MAX_DISPLAY_NAME_BYTE_COUNT = 128
|
42
|
+
MAX_EVENT_NAME_BYTE_COUNT = 256
|
43
|
+
LABELS_MAPPING = {
|
44
|
+
"http.scheme": "/http/client_protocol",
|
45
|
+
"http.method": "/http/method",
|
46
|
+
# https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#common-attributes
|
47
|
+
"http.request_content_length": "/http/request/size",
|
48
|
+
"http.response_content_length": "/http/response/size",
|
49
|
+
"http.route": "/http/route",
|
50
|
+
"http.status_code": "/http/status_code",
|
51
|
+
"http.url": "/http/url",
|
52
|
+
"http.user_agent": "/http/user_agent",
|
53
|
+
"http.host": "/http/host"
|
54
|
+
}.freeze
|
55
|
+
|
56
|
+
def initialize project_id
|
57
|
+
@project_id = project_id
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates batch_write_spans_request from opentelemetry spans
|
61
|
+
#
|
62
|
+
# @param [Enumerable<OpenTelemetry::SDK::Trace::SpanData>] spans the
|
63
|
+
# list of recorded {OpenTelemetry::SDK::Trace::SpanData} structs to be
|
64
|
+
# exported.
|
65
|
+
# @return [Google::Cloud::Trace::V2::BatchWriteSpansRequest]
|
66
|
+
# The request message for the BatchWriteSpans method.
|
67
|
+
def create_batch spans
|
68
|
+
cloud_trace_spans = spans.map do |span|
|
69
|
+
trace_id = span.hex_trace_id
|
70
|
+
span_id = span.hex_span_id
|
71
|
+
parent_id = span.hex_parent_span_id
|
72
|
+
span_name = "projects/#{@project_id}/traces/#{trace_id}/spans/#{span_id}"
|
73
|
+
Google::Cloud::Trace::V2::Span.new(
|
74
|
+
name: span_name,
|
75
|
+
span_id: span_id,
|
76
|
+
parent_span_id: parent_id,
|
77
|
+
display_name: create_name(span.name, MAX_DISPLAY_NAME_BYTE_COUNT),
|
78
|
+
start_time: create_time(span.start_timestamp),
|
79
|
+
end_time: create_time(span.end_timestamp),
|
80
|
+
attributes: create_attributes(span.attributes, MAX_SPAN_ATTRIBUTES, add_agent_attribute: true),
|
81
|
+
links: create_links(span.links),
|
82
|
+
status: create_status(span.status),
|
83
|
+
time_events: create_time_events(span.events),
|
84
|
+
span_kind: create_span_kind(span.kind)
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
{
|
89
|
+
name: "projects/#{@project_id}",
|
90
|
+
spans: cloud_trace_spans
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def create_time epoch
|
97
|
+
return if epoch.nil?
|
98
|
+
time_nsec = Time.at 0, epoch, :nsec # create Time from nanoseconds epoch
|
99
|
+
Google::Protobuf::Timestamp.from_time time_nsec
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_name name, max_bytes
|
103
|
+
truncated_str, truncated_byte_count = truncate_str name, max_bytes
|
104
|
+
Google::Cloud::Trace::V2::TruncatableString.new value: truncated_str,
|
105
|
+
truncated_byte_count: truncated_byte_count
|
106
|
+
end
|
107
|
+
|
108
|
+
def truncate_str str, max_bytes
|
109
|
+
encoded = str.encode "utf-8"
|
110
|
+
truncated_str = encoded.byteslice 0, max_bytes
|
111
|
+
[truncated_str, encoded.length - truncated_str.encode("utf-8").length]
|
112
|
+
end
|
113
|
+
|
114
|
+
def create_attributes attributes, max_attributes, add_agent_attribute: false
|
115
|
+
return if attributes.nil? || attributes.empty?
|
116
|
+
attribute_map = {}
|
117
|
+
|
118
|
+
if add_agent_attribute
|
119
|
+
attribute_map["g.co/agent"] = create_attribute_value(
|
120
|
+
"opentelemetry-ruby #{OpenTelemetry::SDK::VERSION};" \
|
121
|
+
"google-cloud-trace-exporter #{OpenTelemetry::Exporter::GoogleCloudTrace::VERSION}"
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
attributes.each_pair do |k, v|
|
126
|
+
key = truncate_str(k.to_s, MAX_ATTRIBUTES_KEY_BYTES).first
|
127
|
+
key = LABELS_MAPPING[key.to_sym] if LABELS_MAPPING.key? key.to_sym
|
128
|
+
value = create_attribute_value v
|
129
|
+
attribute_map[key] = value unless value.nil?
|
130
|
+
|
131
|
+
break if attribute_map.count >= max_attributes
|
132
|
+
end
|
133
|
+
|
134
|
+
dropped_attributes_count = attributes.count - attribute_map.count
|
135
|
+
dropped_attributes_count += 1 if add_agent_attribute
|
136
|
+
|
137
|
+
Google::Cloud::Trace::V2::Span::Attributes.new(
|
138
|
+
attribute_map: attribute_map,
|
139
|
+
dropped_attributes_count: dropped_attributes_count
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
def create_attribute_value value
|
144
|
+
case value
|
145
|
+
when true, false
|
146
|
+
Google::Cloud::Trace::V2::AttributeValue.new bool_value: value
|
147
|
+
when Integer
|
148
|
+
Google::Cloud::Trace::V2::AttributeValue.new int_value: value
|
149
|
+
else
|
150
|
+
Google::Cloud::Trace::V2::AttributeValue.new(
|
151
|
+
string_value: create_name(value.to_s, MAX_ATTRIBUTES_VAL_BYTES)
|
152
|
+
)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def create_links links
|
157
|
+
return if links.nil?
|
158
|
+
dropped_links_count = 0
|
159
|
+
|
160
|
+
if links.length > MAX_LINKS
|
161
|
+
dropped_links_count = links.length - MAX_LINKS
|
162
|
+
links = links[0...MAX_LINKS]
|
163
|
+
end
|
164
|
+
|
165
|
+
trace_links = links.map do |link|
|
166
|
+
trace_id = link.span_context&.hex_trace_id
|
167
|
+
span_id = link.span_context&.hex_span_id
|
168
|
+
Google::Cloud::Trace::V2::Span::Link.new(
|
169
|
+
trace_id: trace_id,
|
170
|
+
span_id: span_id,
|
171
|
+
type: "TYPE_UNSPECIFIED",
|
172
|
+
attributes: create_attributes(link.attributes, MAX_LINK_ATTRIBUTES)
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
Google::Cloud::Trace::V2::Span::Links.new(
|
177
|
+
link: trace_links,
|
178
|
+
dropped_links_count: dropped_links_count
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
def create_status status
|
183
|
+
case status.code
|
184
|
+
when OpenTelemetry::Trace::Status::OK
|
185
|
+
Google::Rpc::Status.new code: Google::Rpc::Code::OK, message: status.description
|
186
|
+
when OpenTelemetry::Trace::Status::UNSET
|
187
|
+
nil
|
188
|
+
else
|
189
|
+
Google::Rpc::Status.new code: Google::Rpc::Code::UNKNOWN, message: status.description
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def create_time_events events
|
194
|
+
return if events.nil?
|
195
|
+
dropped_message_events_count = 0
|
196
|
+
|
197
|
+
dropped_annotations_count = 0
|
198
|
+
if events.length > MAX_EVENTS
|
199
|
+
dropped_annotations_count = events.length - MAX_EVENTS
|
200
|
+
events = events[0...MAX_EVENTS]
|
201
|
+
end
|
202
|
+
|
203
|
+
time_events = events.map do |event|
|
204
|
+
Google::Cloud::Trace::V2::Span::TimeEvent.new(
|
205
|
+
time: create_time(event.timestamp),
|
206
|
+
annotation: Google::Cloud::Trace::V2::Span::TimeEvent::Annotation.new(
|
207
|
+
description: create_name(event.name, MAX_EVENT_NAME_BYTE_COUNT),
|
208
|
+
attributes: create_attributes(event.attributes, MAX_EVENT_ATTRIBUTES)
|
209
|
+
)
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
Google::Cloud::Trace::V2::Span::TimeEvents.new(
|
214
|
+
time_event: time_events,
|
215
|
+
dropped_annotations_count: dropped_annotations_count,
|
216
|
+
dropped_message_events_count: dropped_message_events_count
|
217
|
+
)
|
218
|
+
end
|
219
|
+
|
220
|
+
def create_span_kind kind
|
221
|
+
case kind
|
222
|
+
when OpenTelemetry::Trace::SpanKind::INTERNAL
|
223
|
+
Google::Cloud::Trace::V2::Span::SpanKind::INTERNAL
|
224
|
+
when OpenTelemetry::Trace::SpanKind::CLIENT
|
225
|
+
Google::Cloud::Trace::V2::Span::SpanKind::CLIENT
|
226
|
+
when OpenTelemetry::Trace::SpanKind::SERVER
|
227
|
+
Google::Cloud::Trace::V2::Span::SpanKind::SERVER
|
228
|
+
when OpenTelemetry::Trace::SpanKind::PRODUCER
|
229
|
+
Google::Cloud::Trace::V2::Span::SpanKind::PRODUCER
|
230
|
+
when OpenTelemetry::Trace::SpanKind::CONSUMER
|
231
|
+
Google::Cloud::Trace::V2::Span::SpanKind::CONSUMER
|
232
|
+
else
|
233
|
+
Google::Cloud::Trace::V2::Span::SpanKind::SPAN_KIND_UNSPECIFIED
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright 2023 Google LLC
|
2
4
|
#
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
6
|
# you may not use this file except in compliance with the License.
|
5
7
|
# You may obtain a copy of the License at
|
6
8
|
#
|
7
|
-
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
10
|
#
|
9
11
|
# Unless required by applicable law or agreed to in writing, software
|
10
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
@@ -12,10 +14,11 @@
|
|
12
14
|
# See the License for the specific language governing permissions and
|
13
15
|
# limitations under the License.
|
14
16
|
|
15
|
-
|
17
|
+
|
18
|
+
module OpenTelemetry
|
16
19
|
module Exporter
|
17
20
|
module GoogleCloudTrace
|
18
|
-
VERSION = "0.
|
21
|
+
VERSION = "0.1.1"
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module OpenTelemetry
|
18
|
+
module Exporter
|
19
|
+
##
|
20
|
+
# # Google Cloud Trace
|
21
|
+
#
|
22
|
+
# Cloud Trace is a distributed tracing system that collects latency data
|
23
|
+
# from your applications and displays it in the Google Cloud Console.
|
24
|
+
# You can track how requests propagate through your application and
|
25
|
+
# receive detailed near real-time performance insights.
|
26
|
+
# Cloud Trace automatically analyzes all of your application's traces
|
27
|
+
# to generate in-depth latency reports to surface performance degradations,
|
28
|
+
# and can capture traces from all of your VMs, containers, or App Engine projects.
|
29
|
+
module GoogleCloudTrace
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
require "opentelemetry/sdk"
|
36
|
+
require "opentelemetry/exporter/google_cloud_trace/span_exporter"
|
37
|
+
require "opentelemetry/exporter/google_cloud_trace/version"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "opentelemetry/exporter/google_cloud_trace"
|