opentelemetry-instrumentation-base 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ba0841769aa5f9825a4441f3e58c54fd9a6e45e9293b10d69328021ddd737f62
4
+ data.tar.gz: f036225206648e9a5e62ed94654ae70ed18b4c473daae02aade8ea7dd0f7148b
5
+ SHA512:
6
+ metadata.gz: ea0bb52d80a047ff083032150a3c1badfc89837f9ef0bbba024318b6db4043a7070df9997e7dd73af7150f454f811a7a4ed0d8ab65448f0a3af15689a88f5750
7
+ data.tar.gz: '019bf3b8fe6e30ee74c0f6cd4a8361e838ce7a1d52248c661361cc4e71d4a1696aef0507d2a21f8bcc15dc23f0e9f0dae32d518dd814c08481bbff983bda8388'
data/.yardopts ADDED
@@ -0,0 +1,9 @@
1
+ --no-private
2
+ --title=OpenTelemetry Base Instrumentation
3
+ --markup=markdown
4
+ --main=README.md
5
+ ./lib/opentelemetry/instrumentation/**/*.rb
6
+ ./lib/opentelemetry/instrumentation.rb
7
+ -
8
+ README.md
9
+ CHANGELOG.md
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Release History: opentelemetry-instrumentation-base
2
+
3
+ ### v0.17.0 / 2021-04-22
4
+
5
+ * Initial release.
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright The OpenTelemetry Authors
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # OpenTelemetry Instrumentation Base
2
+
3
+ The `opentelemetry-instrumentation-base` gem contains the instrumentation base class, and the instrumentation registry. These modules provide a common interface to support the installation of auto instrumentation libraries. The instrumentation base is responsible for adding itself to the instrumentation registry as well as providing convenience hooks for the installation process. The instrumentation registry contains all the instrumentation to be installed during the SDK configuration process.
4
+
5
+ ## How do I get started?
6
+
7
+ Install the gem using:
8
+
9
+ ```
10
+ gem install opentelemetry-instrumentation-base
11
+ ```
12
+
13
+ Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-base` in your `Gemfile`.
14
+
15
+ ### For SDK Authors
16
+
17
+ The following is a simplified demonstration of how the `OpenTelemetry::Instrumentation.registry` can be used by an SDK to install auto-instrumentation gems as part of its configuration. This should not be used as an example of how to implement an SDK as there are large omissions. For an example of a complete implementation see the `opentelemetry-sdk` gem.
18
+
19
+ ```ruby
20
+ require 'bundler/inline'
21
+
22
+ gemfile(true) do
23
+ source 'https://rubygems.org'
24
+ gem 'opentelemetry-api'
25
+ gem 'opentelemetry-instrumentation-base'
26
+ gem 'opentelemetry-instrumentation-net_http'
27
+ end
28
+
29
+ require 'opentelemetry-api'
30
+ require 'opentelemetry-instrumentation-base'
31
+
32
+ # Setup a noop custom tracer for our SDK
33
+ class MyCustomTracer < OpenTelemetry::Trace::Tracer
34
+ def initialize(name, version)
35
+ @name = name
36
+ @version = version
37
+ end
38
+ end
39
+
40
+ # Setup a tracer provider for our SDK
41
+ class MyCustomTracerProvider < OpenTelemetry::Trace::TracerProvider
42
+ def tracer(name = nil, version = nil)
43
+ MyCustomTracer.new(name, version)
44
+ end
45
+ end
46
+
47
+ class MyCustomSDK
48
+ def self.configure(config = {})
49
+ # It is important that we upgrade the API tracer provider to
50
+ # our SDK tracer provider so that when the install hook is
51
+ # called that our instrumentation libraries receive an
52
+ # SDK tracer instead of the noop API tracer.
53
+ OpenTelemetry.tracer_provider = MyCustomTracerProvider.new
54
+ OpenTelemetry::Instrumentation.registry.install_all(config)
55
+ end
56
+ end
57
+
58
+ # The config option being passed to through to the registry install_all method.
59
+ # This is not a valid configuration option for this instrumentation library
60
+ # so the Opentelemetry logger will receive a warning message.
61
+ config = { 'OpenTelemetry::Instrumentation::Net::HTTP' => { foo: 'bar' } }
62
+ MyCustomSDK.configure(config)
63
+
64
+ # The purpose of this line is to demonstrate that the instrumentation
65
+ # library has received the SDK tracer and is not using the default
66
+ # API noop tracer.
67
+ puts OpenTelemetry::Instrumentation::Net::HTTP::Instrumentation.instance.tracer.inspect
68
+
69
+ #### Output
70
+ # Fetching gem metadata from https://rubygems.org/..
71
+ # Resolving dependencies...
72
+ # Using bundler 1.17.3
73
+ # Using opentelemetry-api 0.16.0
74
+ # Using opentelemetry-common 0.16.0
75
+ # Using opentelemetry-instrumentation-base 0.16.0
76
+ # Using opentelemetry-instrumentation-net_http 0.16.0
77
+ # W, [2021-04-08T17:28:04.430002 #8425] WARN -- : Instrumentation OpenTelemetry::Instrumentation::Net::HTTP ignored the following unknown configuration options [:foo]
78
+ # I, [2021-04-08T17:28:04.430697 #8425] INFO -- : Instrumentation: OpenTelemetry::Instrumentation::Net::HTTP was successfully installed
79
+ # #<MyCustomTracer:0x00007faee43c6c58 @name="OpenTelemetry::Instrumentation::Net::HTTP", @version="0.16.0">
80
+ ```
81
+
82
+ ### For auto-instrumentation authors
83
+
84
+ The following is a simplified demonstration of how the `OpenTelemetry::Instrumentation::Base` class can be used to hook into the instrumentation registry, and the basic functionality provided.
85
+
86
+ ```ruby
87
+ # A simple class to instrument
88
+ class SimpleClass
89
+ def greeting
90
+ puts "hello"
91
+ end
92
+ end
93
+
94
+ # Our instrumentation patch
95
+ class SimplePatch
96
+ def greeting
97
+ tracer.in_span('SimpleClass#greeting') { super }
98
+ end
99
+
100
+ private
101
+
102
+ # We can gain access to the instrumentation tracer using
103
+ # the instance method available on the class inheriting
104
+ # from the instrumentation base.
105
+ def tracer
106
+ CustomAutoInstrumentation.instance.tracer
107
+ end
108
+ end
109
+
110
+ # The OpenTelemetry::Instrumentation::Base class will implicitly add
111
+ # any class that inherits from it to the registry.
112
+ # Note that the name of the instrumentation in the registry will match
113
+ # the class name and its namespace. In this example the registry
114
+ # will contain 'CustomAutoInstrumentation', if it was within
115
+ # a module named `Legacy`, it would take the form `Legacy::CustomAutoInstrumentation`.
116
+ class CustomAutoInstrumentation < OpenTelemetry::Instrumentation::Base
117
+ # The install hook is provided to apply patches through prepending
118
+ # or using library hooks if available.
119
+ install do |_config|
120
+ patch
121
+ end
122
+
123
+ # The presence check provides a hook so that we can
124
+ # test for the presence of the class we intend to patch.
125
+ # If the presence check returns false, we will not
126
+ # proceed with the installation hook.
127
+ present do
128
+ defined?(SimpleClass)
129
+ end
130
+
131
+ private
132
+
133
+ def patch
134
+ SimpleClass.prepend(SimplePatch)
135
+ end
136
+ end
137
+ ```
138
+
139
+ ## How can I get involved?
140
+
141
+ The `opentelemetry-instrumentation-base` gem source is [on github][repo-github], along with related gems including `opentelemetry-api` and `opentelemetry-sdk`.
142
+
143
+ The OpenTelemetry Ruby gems are maintained by the OpenTelemetry-Ruby special interest group (SIG). You can get involved by joining us in [GitHub Discussions][discussions-url] or attending our weekly meeting. See the [meeting calendar][community-meetings] for dates and times. For more information on this and other language SIGs, see the OpenTelemetry [community page][ruby-sig].
144
+
145
+ ## License
146
+
147
+ The `opentelemetry-instrumentation-base` gem is distributed under the Apache 2.0 license. See [LICENSE][license-github] for more information.
148
+
149
+ [bundler-home]: https://bundler.io
150
+ [repo-github]: https://github.com/open-telemetry/opentelemetry-ruby
151
+ [license-github]: https://github.com/open-telemetry/opentelemetry-ruby/blob/main/LICENSE
152
+ [ruby-sig]: https://github.com/open-telemetry/community#ruby-sig
153
+ [community-meetings]: https://github.com/open-telemetry/community#community-meetings
154
+ [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require_relative './opentelemetry/instrumentation'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require 'opentelemetry'
8
+ require 'opentelemetry/instrumentation/registry'
9
+ require 'opentelemetry/instrumentation/base'
10
+
11
+ module OpenTelemetry
12
+ # The instrumentation module contains functionality to register and install
13
+ # instrumentation
14
+ module Instrumentation
15
+ extend self
16
+
17
+ # @return [Registry] registry containing all known
18
+ # instrumentation
19
+ def registry
20
+ @registry ||= Registry.new
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,308 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ # The Base class holds all metadata and configuration for an
10
+ # instrumentation. All instrumentation packages should
11
+ # include a subclass of +Instrumentation::Base+ that will register
12
+ # it with +OpenTelemetry.instrumentation_registry+ and make it available for
13
+ # discovery and installation by an SDK.
14
+ #
15
+ # A typical subclass of Base will provide an install block, a present
16
+ # block, and possibly a compatible block. Below is an
17
+ # example:
18
+ #
19
+ # module OpenTelemetry
20
+ # module Instrumentation
21
+ # module Sinatra
22
+ # class Instrumentation < OpenTelemetry::Instrumentation::Base
23
+ # install do |config|
24
+ # # install instrumentation, either by library hook or applying
25
+ # # a monkey patch
26
+ # end
27
+ #
28
+ # # determine if the target library is present
29
+ # present do
30
+ # defined?(::Sinatra)
31
+ # end
32
+ #
33
+ # # if the target library is present, is it compatible?
34
+ # compatible do
35
+ # Gem.loaded_specs['sinatra'].version > MIN_VERSION
36
+ # end
37
+ # end
38
+ # end
39
+ # end
40
+ # end
41
+ #
42
+ # The instrumentation name and version will be inferred from the namespace of the
43
+ # class. In this example, they'd be 'OpenTelemetry::Instrumentation::Sinatra' and
44
+ # OpenTelemetry::Instrumentation::Sinatra::VERSION, but can be explicitly set using
45
+ # the +instrumentation_name+ and +instrumetation_version+ methods if necessary.
46
+ #
47
+ # All subclasses of OpenTelemetry::Instrumentation::Base are automatically
48
+ # registered with OpenTelemetry.instrumentation_registry which is used by
49
+ # SDKs for instrumentation discovery and installation.
50
+ #
51
+ # Instrumentation libraries can use the instrumentation subclass to easily gain
52
+ # a reference to its named tracer. For example:
53
+ #
54
+ # OpenTelemetry::Instrumentation::Sinatra.instance.tracer
55
+ #
56
+ # The instrumention class establishes a convention for disabling an instrumentation
57
+ # by environment variable and local configuration. An instrumentation disabled
58
+ # by environment variable will take precedence over local config. The
59
+ # convention for environment variable name is the library name, upcased with
60
+ # '::' replaced by underscores, OPENTELEMETRY shortened to OTEL_{LANG}, and '_ENABLED' appended.
61
+ # For example: OTEL_RUBY_INSTRUMENTATION_SINATRA_ENABLED = false.
62
+ class Base # rubocop:disable Metrics/ClassLength
63
+ class << self
64
+ NAME_REGEX = /^(?:(?<namespace>[a-zA-Z0-9_:]+):{2})?(?<classname>[a-zA-Z0-9_]+)$/.freeze
65
+ VALIDATORS = {
66
+ array: ->(v) { v.is_a?(Array) },
67
+ boolean: ->(v) { v == true || v == false }, # rubocop:disable Style/MultipleComparison
68
+ callable: ->(v) { v.respond_to?(:call) },
69
+ integer: ->(v) { v.is_a?(Integer) },
70
+ string: ->(v) { v.is_a?(String) }
71
+ }.freeze
72
+
73
+ private_constant :NAME_REGEX, :VALIDATORS
74
+
75
+ private :new # rubocop:disable Style/AccessModifierDeclarations
76
+
77
+ def inherited(subclass)
78
+ OpenTelemetry::Instrumentation.registry.register(subclass)
79
+ end
80
+
81
+ # Optionally set the name of this instrumentation. If not
82
+ # explicitly set, the name will default to the namespace of the class,
83
+ # or the class name if it does not have a namespace. If there is not
84
+ # a namespace, or a class name, it will default to 'unknown'.
85
+ #
86
+ # @param [String] instrumentation_name The full name of the instrumentation package
87
+ def instrumentation_name(instrumentation_name = nil)
88
+ if instrumentation_name
89
+ @instrumentation_name = instrumentation_name
90
+ else
91
+ @instrumentation_name ||= infer_name || 'unknown'
92
+ end
93
+ end
94
+
95
+ # Optionally set the version of this instrumentation. If not explicitly set,
96
+ # the version will default to the VERSION constant under namespace of
97
+ # the class, or the VERSION constant under the class name if it does not
98
+ # have a namespace. If a VERSION constant cannot be found, it defaults
99
+ # to '0.0.0'.
100
+ #
101
+ # @param [String] instrumentation_version The version of the instrumentation package
102
+ def instrumentation_version(instrumentation_version = nil)
103
+ if instrumentation_version
104
+ @instrumentation_version = instrumentation_version
105
+ else
106
+ @instrumentation_version ||= infer_version || '0.0.0'
107
+ end
108
+ end
109
+
110
+ # The install block for this instrumentation. This will be where you install
111
+ # instrumentation, either by framework hook or applying a monkey patch.
112
+ #
113
+ # @param [Callable] blk The install block for this instrumentation
114
+ # @yieldparam [Hash] config The instrumentation config will be yielded to the
115
+ # install block
116
+ def install(&blk)
117
+ @install_blk = blk
118
+ end
119
+
120
+ # The present block for this instrumentation. This block is used to detect if
121
+ # target library is present on the system. Typically this will involve
122
+ # checking to see if the target gem spec was loaded or if expected
123
+ # constants from the target library are present.
124
+ #
125
+ # @param [Callable] blk The present block for this instrumentation
126
+ def present(&blk)
127
+ @present_blk = blk
128
+ end
129
+
130
+ # The compatible block for this instrumentation. This check will be run if the
131
+ # target library is present to determine if it's compatible. It's not
132
+ # required, but a common use case will be to check to target library
133
+ # version for compatibility.
134
+ #
135
+ # @param [Callable] blk The compatibility block for this instrumentation
136
+ def compatible(&blk)
137
+ @compatible_blk = blk
138
+ end
139
+
140
+ # The option method is used to define default configuration options
141
+ # for the instrumentation library. It requires a name, default value,
142
+ # and a validation callable to be provided.
143
+ # @param [String] name The name of the configuration option
144
+ # @param default The default value to be used, or to used if validation fails
145
+ # @param [Callable, Symbol] validate Accepts a callable or a symbol that matches
146
+ # a key in the VALIDATORS hash. The supported keys are, :array, :boolean,
147
+ # :callable, :integer, :string.
148
+ def option(name, default:, validate:)
149
+ validate = VALIDATORS[validate] || validate
150
+ raise ArgumentError, "validate must be #{VALIDATORS.keys.join(', ')}, or a callable" unless validate.respond_to?(:call)
151
+
152
+ @options ||= []
153
+ @options << { name: name, default: default, validate: validate }
154
+ end
155
+
156
+ def instance
157
+ @instance ||= new(instrumentation_name, instrumentation_version, install_blk,
158
+ present_blk, compatible_blk, options)
159
+ end
160
+
161
+ private
162
+
163
+ attr_reader :install_blk, :present_blk, :compatible_blk, :options
164
+
165
+ def infer_name
166
+ @inferred_name ||= if (md = name.match(NAME_REGEX)) # rubocop:disable Naming/MemoizedInstanceVariableName
167
+ md['namespace'] || md['classname']
168
+ end
169
+ end
170
+
171
+ def infer_version
172
+ return unless (inferred_name = infer_name)
173
+
174
+ mod = inferred_name.split('::').map(&:to_sym).inject(Object) do |object, const|
175
+ object.const_get(const)
176
+ end
177
+ mod.const_get(:VERSION)
178
+ rescue NameError
179
+ nil
180
+ end
181
+ end
182
+
183
+ attr_reader :name, :version, :config, :installed, :tracer
184
+
185
+ alias installed? installed
186
+
187
+ def initialize(name, version, install_blk, present_blk,
188
+ compatible_blk, options)
189
+ @name = name
190
+ @version = version
191
+ @install_blk = install_blk
192
+ @present_blk = present_blk
193
+ @compatible_blk = compatible_blk
194
+ @config = {}
195
+ @installed = false
196
+ @options = options
197
+ @tracer = OpenTelemetry::Trace::Tracer.new
198
+ end
199
+
200
+ # Install instrumentation with the given config. The present? and compatible?
201
+ # will be run first, and install will return false if either fail. Will
202
+ # return true if install was completed successfully.
203
+ #
204
+ # @param [Hash] config The config for this instrumentation
205
+ def install(config = {})
206
+ return true if installed?
207
+ return false unless installable?(config)
208
+
209
+ @config = config_options(config)
210
+ instance_exec(@config, &@install_blk)
211
+ @tracer = OpenTelemetry.tracer_provider.tracer(name, version)
212
+ @installed = true
213
+ end
214
+
215
+ # Whether or not this instrumentation is installable in the current process. Will
216
+ # be true when the instrumentation defines an install block, is not disabled
217
+ # by environment or config, and the target library present and compatible.
218
+ #
219
+ # @param [Hash] config The config for this instrumentation
220
+ def installable?(config = {})
221
+ @install_blk && enabled?(config) && present? && compatible?
222
+ end
223
+
224
+ # Calls the present block of the Instrumentation subclasses, if no block is provided
225
+ # it's assumed the instrumentation is not present
226
+ def present?
227
+ return false unless @present_blk
228
+
229
+ instance_exec(&@present_blk)
230
+ end
231
+
232
+ # Calls the compatible block of the Instrumentation subclasses, if no block is provided
233
+ # it's assumed to be compatible
234
+ def compatible?
235
+ return true unless @compatible_blk
236
+
237
+ instance_exec(&@compatible_blk)
238
+ end
239
+
240
+ # Whether this instrumentation is enabled. It first checks to see if it's enabled
241
+ # by an environment variable and will proceed to check if it's enabled
242
+ # by local config, if given.
243
+ #
244
+ # @param [optional Hash] config The local config
245
+ def enabled?(config = nil)
246
+ return false unless enabled_by_env_var?
247
+ return config[:enabled] if config&.key?(:enabled)
248
+
249
+ true
250
+ end
251
+
252
+ private
253
+
254
+ # The config_options method is responsible for validating that the user supplied
255
+ # config hash is valid.
256
+ # Unknown configuration keys are not included in the final config hash.
257
+ # Invalid configuration values are logged, and replaced by the default.
258
+ #
259
+ # @param [Hash] user_config The user supplied configuration hash
260
+ def config_options(user_config) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
261
+ @options ||= {}
262
+ user_config ||= {}
263
+ validated_config = @options.each_with_object({}) do |option, h|
264
+ option_name = option[:name]
265
+ config_value = user_config[option_name]
266
+
267
+ value = if config_value.nil?
268
+ option[:default]
269
+ elsif option[:validate].call(config_value)
270
+ config_value
271
+ else
272
+ OpenTelemetry.logger.warn(
273
+ "Instrumentation #{name} configuration option #{option_name} value=#{config_value} " \
274
+ "failed validation, falling back to default value=#{option[:default]}"
275
+ )
276
+ option[:default]
277
+ end
278
+
279
+ h[option_name] = value
280
+ rescue StandardError => e
281
+ OpenTelemetry.handle_error(exception: e, message: "Instrumentation #{name} unexpected configuration error")
282
+ h[option_name] = option[:default]
283
+ end
284
+
285
+ dropped_config_keys = user_config.keys - validated_config.keys
286
+ OpenTelemetry.logger.warn("Instrumentation #{name} ignored the following unknown configuration options #{dropped_config_keys}") unless dropped_config_keys.empty?
287
+
288
+ validated_config
289
+ end
290
+
291
+ # Checks to see if this instrumentation is enabled by env var. By convention, the
292
+ # environment variable will be the instrumentation name upper cased, with '::'
293
+ # replaced by underscores, OPENTELEMETRY shortened to OTEL_{LANG} and _ENABLED appended.
294
+ # For example, the, environment variable name for OpenTelemetry::Instrumentation::Sinatra
295
+ # will be OTEL_RUBY_INSTRUMENTATION_SINATRA_ENABLED. A value of 'false' will disable
296
+ # the instrumentation, all other values will enable it.
297
+ def enabled_by_env_var?
298
+ var_name = name.dup.tap do |n|
299
+ n.upcase!
300
+ n.gsub!('::', '_')
301
+ n.gsub!('OPENTELEMETRY_', 'OTEL_RUBY_')
302
+ n << '_ENABLED'
303
+ end
304
+ ENV[var_name] != 'false'
305
+ end
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ # The instrumentation Registry contains information about instrumentation
10
+ # available and facilitates discovery, installation and
11
+ # configuration. This functionality is primarily useful for SDK
12
+ # implementors.
13
+ class Registry
14
+ def initialize
15
+ @lock = Mutex.new
16
+ @instrumentation = []
17
+ end
18
+
19
+ # @api private
20
+ def register(instrumentation)
21
+ @lock.synchronize do
22
+ @instrumentation << instrumentation
23
+ end
24
+ end
25
+
26
+ # Lookup an instrumentation definition by name. Returns nil if +instrumentation_name+
27
+ # is not found.
28
+ #
29
+ # @param [String] instrumentation_name A stringified class name for an instrumentation
30
+ # @return [Instrumentation]
31
+ def lookup(instrumentation_name)
32
+ @lock.synchronize do
33
+ find_instrumentation(instrumentation_name)
34
+ end
35
+ end
36
+
37
+ # Install the specified instrumentation with optionally specified configuration.
38
+ #
39
+ # @param [Array<String>] instrumentation_names An array of instrumentation names to
40
+ # install
41
+ # @param [optional Hash<String, Hash>] instrumentation_config_map A map of
42
+ # instrumentation_name to config. This argument is optional and config can be
43
+ # passed for as many or as few instrumentations as desired.
44
+ def install(instrumentation_names, instrumentation_config_map = {})
45
+ @lock.synchronize do
46
+ instrumentation_names.each do |instrumentation_name|
47
+ instrumentation = find_instrumentation(instrumentation_name)
48
+ OpenTelemetry.logger.warn "Could not install #{instrumentation_name} because it was not found" unless instrumentation
49
+
50
+ install_instrumentation(instrumentation, instrumentation_config_map[instrumentation.name])
51
+ end
52
+ end
53
+ end
54
+
55
+ # Install all instrumentation available and installable in this process.
56
+ #
57
+ # @param [optional Hash<String, Hash>] instrumentation_config_map A map of
58
+ # instrumentation_name to config. This argument is optional and config can be
59
+ # passed for as many or as few instrumentations as desired.
60
+ def install_all(instrumentation_config_map = {})
61
+ @lock.synchronize do
62
+ @instrumentation.map(&:instance).each do |instrumentation|
63
+ install_instrumentation(instrumentation, instrumentation_config_map[instrumentation.name])
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def find_instrumentation(instrumentation_name)
71
+ @instrumentation.detect { |a| a.instance.name == instrumentation_name }
72
+ &.instance
73
+ end
74
+
75
+ def install_instrumentation(instrumentation, config)
76
+ if instrumentation.install(config)
77
+ OpenTelemetry.logger.info "Instrumentation: #{instrumentation.name} was successfully installed"
78
+ else
79
+ OpenTelemetry.logger.warn "Instrumentation: #{instrumentation.name} failed to install"
80
+ end
81
+ rescue => e # rubocop:disable Style/RescueStandardError
82
+ OpenTelemetry.handle_error(exception: e, message: "Instrumentation: #{instrumentation.name} unhandled exception during install: #{e.backtrace}")
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ VERSION = '0.17.0'
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opentelemetry-instrumentation-base
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.17.0
5
+ platform: ruby
6
+ authors:
7
+ - OpenTelemetry Authors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-04-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: opentelemetry-api
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.17.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.17.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.17'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.17'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 12.3.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 12.3.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.73.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.73.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.17.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.17.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.9'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.9'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard-doctest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.1.6
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.1.6
125
+ description: Instrumentation Base for the OpenTelemetry framework
126
+ email:
127
+ - cncf-opentelemetry-contributors@lists.cncf.io
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".yardopts"
133
+ - CHANGELOG.md
134
+ - LICENSE
135
+ - README.md
136
+ - lib/opentelemetry-instrumentation-base.rb
137
+ - lib/opentelemetry/instrumentation.rb
138
+ - lib/opentelemetry/instrumentation/base.rb
139
+ - lib/opentelemetry/instrumentation/registry.rb
140
+ - lib/opentelemetry/instrumentation/version.rb
141
+ homepage: https://github.com/open-telemetry/opentelemetry-ruby
142
+ licenses:
143
+ - Apache-2.0
144
+ metadata:
145
+ changelog_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-instrumentation-base/v0.17.0/file.CHANGELOG.html
146
+ source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby/tree/main/instrumentation/base
147
+ bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby/issues
148
+ documentation_uri: https://open-telemetry.github.io/opentelemetry-ruby/opentelemetry-instrumentation-base/v0.17.0
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: 2.5.0
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubygems_version: 3.1.6
165
+ signing_key:
166
+ specification_version: 4
167
+ summary: Instrumentation Base for the OpenTelemetry framework
168
+ test_files: []