From a5a5386a2618b5f771ea102266a918bc80bc3100 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 14 Nov 2023 18:27:06 -0500 Subject: [PATCH 01/42] feat: add aws lambda instrumentation --- instrumentation/aws_lambda/.yardopts | 9 + instrumentation/aws_lambda/Appraisals | 5 + instrumentation/aws_lambda/CHANGELOG.md | 5 + instrumentation/aws_lambda/Gemfile | 14 ++ instrumentation/aws_lambda/LICENSE | 201 ++++++++++++++++++ instrumentation/aws_lambda/README.md | 60 ++++++ instrumentation/aws_lambda/Rakefile | 29 +++ instrumentation/aws_lambda/example/Gemfile | 7 + instrumentation/aws_lambda/example/sample.rb | 9 + .../aws_lambda/example/trace_demonstration.rb | 75 +++++++ ...pentelemetry-instrumentation-aws_lambda.rb | 7 + .../lib/opentelemetry/instrumentation.rb | 22 ++ .../instrumentation/aws_lambda.rb | 19 ++ .../instrumentation/aws_lambda/handler.rb | 127 +++++++++++ .../aws_lambda/instrumentation.rb | 33 +++ .../instrumentation/aws_lambda/version.rb | 13 ++ ...lemetry-instrumentation-aws_lambda.gemspec | 50 +++++ .../opentelemetry/instrumentation_test.rb | 127 +++++++++++ .../aws_lambda/test/test_helper.rb | 106 +++++++++ 19 files changed, 918 insertions(+) create mode 100644 instrumentation/aws_lambda/.yardopts create mode 100644 instrumentation/aws_lambda/Appraisals create mode 100644 instrumentation/aws_lambda/CHANGELOG.md create mode 100644 instrumentation/aws_lambda/Gemfile create mode 100644 instrumentation/aws_lambda/LICENSE create mode 100644 instrumentation/aws_lambda/README.md create mode 100644 instrumentation/aws_lambda/Rakefile create mode 100644 instrumentation/aws_lambda/example/Gemfile create mode 100644 instrumentation/aws_lambda/example/sample.rb create mode 100755 instrumentation/aws_lambda/example/trace_demonstration.rb create mode 100644 instrumentation/aws_lambda/lib/opentelemetry-instrumentation-aws_lambda.rb create mode 100644 instrumentation/aws_lambda/lib/opentelemetry/instrumentation.rb create mode 100644 instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb create mode 100644 instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb create mode 100644 instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb create mode 100644 instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb create mode 100644 instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec create mode 100644 instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb create mode 100644 instrumentation/aws_lambda/test/test_helper.rb diff --git a/instrumentation/aws_lambda/.yardopts b/instrumentation/aws_lambda/.yardopts new file mode 100644 index 000000000..7bd7686dc --- /dev/null +++ b/instrumentation/aws_lambda/.yardopts @@ -0,0 +1,9 @@ +--no-private +--title=OpenTelemetry AWS Lambda Instrumentation +--markup=markdown +--main=README.md +./lib/opentelemetry/instrumentation/**/*.rb +./lib/opentelemetry/instrumentation.rb +- +README.md +CHANGELOG.md diff --git a/instrumentation/aws_lambda/Appraisals b/instrumentation/aws_lambda/Appraisals new file mode 100644 index 000000000..f7cf8339f --- /dev/null +++ b/instrumentation/aws_lambda/Appraisals @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 diff --git a/instrumentation/aws_lambda/CHANGELOG.md b/instrumentation/aws_lambda/CHANGELOG.md new file mode 100644 index 000000000..25fbd7472 --- /dev/null +++ b/instrumentation/aws_lambda/CHANGELOG.md @@ -0,0 +1,5 @@ +# Release History: opentelemetry-instrumentation-aws_lambda + +### v0.1.0 / 2021-12-01 + +* Initial release. diff --git a/instrumentation/aws_lambda/Gemfile b/instrumentation/aws_lambda/Gemfile new file mode 100644 index 000000000..a03fdb17e --- /dev/null +++ b/instrumentation/aws_lambda/Gemfile @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +source 'https://rubygems.org' + +gemspec + +group :test do + gem 'opentelemetry-instrumentation-base', path: '../base' + gem 'webrick', '~> 1.7' +end diff --git a/instrumentation/aws_lambda/LICENSE b/instrumentation/aws_lambda/LICENSE new file mode 100644 index 000000000..1ef7dad2c --- /dev/null +++ b/instrumentation/aws_lambda/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright The OpenTelemetry 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. diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md new file mode 100644 index 000000000..dc091e279 --- /dev/null +++ b/instrumentation/aws_lambda/README.md @@ -0,0 +1,60 @@ +# OpenTelemetry AWS-Lambda Instrumentation + +The OpenTelemetry `aws-lambda` gem is a community maintained instrumentation for [aws-sdk-lambda][aws-sdk-lambda]. + +## How do I get started? + +Install the gem using: + +``` +gem install opentelemetry-instrumentation-aws_lambda +``` + +Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-aws_lambda` in your `Gemfile`. + +## Usage + +From Lambda Layer side, create the wrapper. More information can be found in https://github.com/open-telemetry/opentelemetry-lambda +```ruby +require 'opentelemetry/sdk' +require 'opentelemetry/instrumentation/all' +OpenTelemetry::SDK.configure do |c| + c.service_name = '' + c.use_all() +end + +def otel_wrapper(event:, context:) + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new() + otel_wrapper.call_wrapped(event: event, context: context) +end +``` + +## Example + +To run the example: + +1. `cd` to the examples directory and install gems + * `cd example` + * `bundle install` +2. Run the sample client script + * `ruby trace_demonstration.rb` + +This will run SNS publish command, printing OpenTelemetry traces to the console as it goes. + +## How can I get involved? + +The `opentelemetry-instrumentation-aws_lambda` gem source is [on github][repo-github], along with related gems including `opentelemetry-api` and `opentelemetry-sdk`. + +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]. + +## License + +Apache 2.0 license. See [LICENSE][license-github] for more information. + +[aws-sdk-home]: https://github.com/aws/aws-sdk-ruby +[bundler-home]: https://bundler.io +[repo-github]: https://github.com/open-telemetry/opentelemetry-ruby +[license-github]: https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/LICENSE +[ruby-sig]: https://github.com/open-telemetry/community#ruby-sig +[community-meetings]: https://github.com/open-telemetry/community#community-meetings +[discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions diff --git a/instrumentation/aws_lambda/Rakefile b/instrumentation/aws_lambda/Rakefile new file mode 100644 index 000000000..4b0e9b5a8 --- /dev/null +++ b/instrumentation/aws_lambda/Rakefile @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'bundler/gem_tasks' +require 'rake/testtask' +require 'yard' +require 'rubocop/rake_task' + +RuboCop::RakeTask.new + +Rake::TestTask.new :test do |t| + t.libs << 'test' + t.libs << 'lib' + t.test_files = FileList['test/**/*_test.rb'] + t.warning = false +end + +YARD::Rake::YardocTask.new do |t| + t.stats_options = ['--list-undoc'] +end + +if RUBY_ENGINE == 'truffleruby' + task default: %i[test] +else + task default: %i[test rubocop yard] +end diff --git a/instrumentation/aws_lambda/example/Gemfile b/instrumentation/aws_lambda/example/Gemfile new file mode 100644 index 000000000..f6b99dfd6 --- /dev/null +++ b/instrumentation/aws_lambda/example/Gemfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'opentelemetry-api' +gem 'opentelemetry-instrumentation-aws_lambda', path: '../' +gem 'opentelemetry-sdk' diff --git a/instrumentation/aws_lambda/example/sample.rb b/instrumentation/aws_lambda/example/sample.rb new file mode 100644 index 000000000..aab8a72dd --- /dev/null +++ b/instrumentation/aws_lambda/example/sample.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +def handler(event:, context:) + puts "Success" +end \ No newline at end of file diff --git a/instrumentation/aws_lambda/example/trace_demonstration.rb b/instrumentation/aws_lambda/example/trace_demonstration.rb new file mode 100755 index 000000000..f7eb1e301 --- /dev/null +++ b/instrumentation/aws_lambda/example/trace_demonstration.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'rubygems' +require 'bundler/setup' +require_relative './sample' + +Bundler.require + +# Export traces to console by default +ENV['OTEL_TRACES_EXPORTER'] ||= 'console' +ENV['ORIG_HANDLER'] ||= 'sample.handler' + +OpenTelemetry::SDK.configure do |c| + c.use 'OpenTelemetry::Instrumentation::AwsLambda' +end + +class MockLambdaContext + attr_reader :aws_request_id, :invoked_function_arn + + def initialize(aws_request_id:, invoked_function_arn:) + @aws_request_id = aws_request_id + @invoked_function_arn = invoked_function_arn + end +end + +def otel_wrapper(event:, context:) + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new() + otel_wrapper.call_wrapped(event: event, context: context) +end + +# sample event obtained from sample test +event = { + "body" => nil, + "headers" => { + "Accept" => "*/*", + "Host" => "127.0.0.1:3000", + "User-Agent" => "curl/8.1.2", + "X-Forwarded-Port" => 3000, + "X-Forwarded-Proto" => "http" + }, + "httpMethod" => "GET", + "isBase64Encoded" => false, + "multiValueHeaders" => {}, + "multiValueQueryStringParameters" => nil, + "path" => "/", + "pathParameters" => nil, + "queryStringParameters" => nil, + "requestContext":{ + "accountId" => 123456789012, + "apiId" => 1234567890, + "domainName" => "127.0.0.1:3000", + "extendedRequestId" => nil, + "httpMethod" => "GET", + "identity" => {}, + "path" => "/", + "protocol" => "HTTP/1.1", + "requestId" => "db7f8e7a-4cc5-4f6d-987b-713d0d9052c3", + "requestTime" => "08/Nov/2023:19:09:59 +0000", + "requestTimeEpoch" => 1699470599, + "resourceId" => "123456", + "resourcePath" => "/", + "stage" => "api" + }, + "resource" => "/", + "stageVariables" => nil, + "version" => "1.0" +} + +context = MockLambdaContext.new(aws_request_id: "aws_request_id",invoked_function_arn: "invoked_function_arn") + +otel_wrapper(event: event, context: context) # you should see Success before the trace diff --git a/instrumentation/aws_lambda/lib/opentelemetry-instrumentation-aws_lambda.rb b/instrumentation/aws_lambda/lib/opentelemetry-instrumentation-aws_lambda.rb new file mode 100644 index 000000000..c034f140f --- /dev/null +++ b/instrumentation/aws_lambda/lib/opentelemetry-instrumentation-aws_lambda.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require_relative 'opentelemetry/instrumentation' diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation.rb new file mode 100644 index 000000000..8dd0f5127 --- /dev/null +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +# OpenTelemetry is an open source observability framework, providing a +# general-purpose API, SDK, and related tools required for the instrumentation +# of cloud-native software, frameworks, and libraries. +# +# The OpenTelemetry module provides global accessors for telemetry objects. +# See the documentation for the `opentelemetry-api` gem for details. +module OpenTelemetry + # "Instrumentation" are specified by + # https://github.com/open-telemetry/opentelemetry-specification/blob/784635d01d8690c8f5fcd1f55bdbc8a13cf2f4f2/specification/glossary.md#instrumentation-library + # + # Instrumentation should be able to handle the case when the library is not installed on a user's system. + module Instrumentation + end +end + +require_relative 'instrumentation/aws_lambda' diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb new file mode 100644 index 000000000..975a6913e --- /dev/null +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'opentelemetry' +require 'opentelemetry-instrumentation-base' + +module OpenTelemetry + module Instrumentation + # Contains the OpenTelemetry instrumentation for the Aws gem + module AwsLambda + end + end +end + +require_relative 'aws_lambda/instrumentation' +require_relative 'aws_lambda/version' diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb new file mode 100644 index 000000000..2548dfe99 --- /dev/null +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module AwsLambda + # Handler class that create span around the _HANDLER + class Handler + attr_reader :handler_method, :handler_class + + def initialize + @flush_timeout = ENV.fetch('OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT', '30000').to_i + end + + # Extract context from request headers + def call_wrapped(event:, context:) + parent_context = extract_parent_context(event) + span_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) + original_handler = resolve_original_handler + response = call_original_handler(event: event, context: context) + + span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] if response.instance_of?(Hash) && response['statusCode'] + span_attributes[OpenTelemetry::SemanticConventions::Resource::FAAS_ID] = context.invoked_function_arn + span_attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_EXECUTION] = context.aws_request_id + + OpenTelemetry::Context.with_current(parent_context) do + span = tracer.start_span( + original_handler, + attributes: span_attributes, + kind: :server # Span kind MUST be `:server` for a HTTP server span + ) + rescue Exception => e # rubocop:disable Lint/RescueException + span&.record_exception(e) + span&.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}") + raise e + ensure + span&.finish + OpenTelemetry.tracer_provider.force_flush(timeout: @flush_timeout) + end + end + + def resolve_original_handler + original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' + original_handler_parts = original_handler.split('.') + if original_handler_parts.size == 2 + _, @handler_method = original_handler_parts + elsif original_handler_parts.size == 3 + _, @handler_class, @handler_method = original_handler_parts + else + OpenTelemetry.logger.warn("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") + end + original_handler + end + + def call_original_handler(event:, context:) + if @handler_class + Kernel.const_get(@handler_class).send(@handler_method, event: event, context: context) + else + __send__(@handler_method, event: event, context: context) + end + end + + def instrumentation_config + AwsLambda::Instrumentation.instance.config + end + + def tracer + AwsLambda::Instrumentation.instance.tracer + end + + private + + # Downcase Traceparent and Tracestate because TraceContext::TextMapPropagator's TRACEPARENT_KEY and TRACESTATE_KEY are all lowercase + def extract_parent_context(event) + headers = event['headers'] || {} + headers.transform_keys! do |key| + %w[Traceparent Tracestate].include?(key) ? key.downcase : key + end + + OpenTelemetry.propagation.extract( + headers, + getter: OpenTelemetry::Context::Propagation.text_map_getter + ) + end + + def v1_proxy_attributes(event) + attributes = { + OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => event['httpMethod'], + OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE => event['resource'], + OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => event['resource'] + } + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] += "?#{event['queryStringParameters']}" if event['queryStringParameters'] + + headers = event['headers'] + if headers + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_USER_AGENT] = headers['User-Agent'] + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME] = headers['X-Forwarded-Proto'] + attributes[OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME] = headers['Host'] + end + + attributes + end + + def v2_proxy_attributes(event) + request_context = event['requestContext'] + if request_context + attributes = { + OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME => request_context['domainName'], + OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_context['http']['method'], + OpenTelemetry::SemanticConventions::Trace::HTTP_USER_AGENT => request_context['http']['userAgent'], + OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE => request_context['http']['path'], + OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => request_context['http']['path'] + } + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] += "?#{event['rawQueryString']}" if event['rawQueryString'] + else + attributes = {} + end + + attributes + end + end + end + end +end diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb new file mode 100644 index 000000000..f907db5cb --- /dev/null +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module AwsLambda + # Instrumentation class that detects and installs the AwsLambda instrumentation + class Instrumentation < OpenTelemetry::Instrumentation::Base + install do |_config| + require_dependencies + end + + present do + # maybe check if ORIG_HANDLER or _HANLDER exist + true + end + + compatible do + true + end + + private + + def require_dependencies + require_relative 'handler' + end + end + end + end +end diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb new file mode 100644 index 000000000..b1313b85c --- /dev/null +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module AwsLambda + VERSION = '0.0.1' + end + end +end diff --git a/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec b/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec new file mode 100644 index 000000000..5567e5081 --- /dev/null +++ b/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'opentelemetry/instrumentation/aws_lambda/version' + +Gem::Specification.new do |spec| + spec.name = 'opentelemetry-instrumentation-aws_lambda' + spec.version = OpenTelemetry::Instrumentation::AwsLambda::VERSION + spec.authors = ['OpenTelemetry Authors'] + spec.email = ['cncf-opentelemetry-contributors@lists.cncf.io'] + + spec.summary = 'AWS Lambda instrumentation for the OpenTelemetry framework' + spec.description = 'AWS Lambda instrumentation for the OpenTelemetry framework' + spec.homepage = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib' + spec.license = 'Apache-2.0' + + spec.files = Dir.glob('lib/**/*.rb') + + Dir.glob('*.md') + + ['LICENSE', '.yardopts'] + spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 3.0' + + spec.add_dependency 'opentelemetry-api', '~> 1.0' + spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.22.1' + + spec.add_development_dependency 'appraisal', '~> 2.5' + spec.add_development_dependency 'bundler', '~> 2.4' + spec.add_development_dependency 'minitest', '~> 5.0' + spec.add_development_dependency 'opentelemetry-sdk', '~> 1.1' + spec.add_development_dependency 'opentelemetry-test-helpers', '~> 0.3' + spec.add_development_dependency 'pry' + spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' + spec.add_development_dependency 'rspec-mocks' + spec.add_development_dependency 'rubocop', '~> 1.56.1' + spec.add_development_dependency 'simplecov', '~> 0.17.1' + spec.add_development_dependency 'webmock', '~> 3.19' + spec.add_development_dependency 'yard', '~> 0.9' + + if spec.respond_to?(:metadata) + spec.metadata['changelog_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}/file/CHANGELOG.md" + spec.metadata['source_code_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/aws_lambda' + spec.metadata['bug_tracker_uri'] = 'https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues' + spec.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{spec.name}/#{spec.version}" + end +end diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb new file mode 100644 index 000000000..bb7af0d36 --- /dev/null +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +describe OpenTelemetry::Instrumentation::AwsLambda do + let(:instrumentation) { OpenTelemetry::Instrumentation::AwsLambda::Instrumentation.instance } + let(:exporter) { EXPORTER } + let(:event_v1) { EVENT_V1 } + let(:event_v2) { EVENT_V2 } + let(:context) { CONTEXT } + let(:last_span) { exporter.finished_spans.last } + + it 'has #name' do + _(instrumentation.name).must_equal 'OpenTelemetry::Instrumentation::AwsLambda' + end + + it 'has #version' do + _(instrumentation.version).wont_be_nil + _(instrumentation.version).wont_be_empty + end + + describe '#compatible' do + it 'returns true for supported gem versions' do + _(instrumentation.compatible?).must_equal true + end + end + + describe '#install' do + it 'accepts argument' do + _(instrumentation.install({})).must_equal(true) + instrumentation.instance_variable_set(:@installed, false) + end + end + + describe 'validate_wrapper' do + before do + ENV['ORIG_HANDLER'] = 'sample.test' + end + + after do + ENV.delete('ORIG_HANDLER') + end + + it 'result should be span' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, {}) do + otel_wrapper.call_wrapped(event: event_v1, context: context) + _(last_span).must_be_kind_of(OpenTelemetry::SDK::Trace::SpanData) + end + end + + it 'validate_spans' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, {}) do + otel_wrapper.call_wrapped(event: event_v1, context: context) + + _(last_span.name).must_equal 'sample.test' + _(last_span.kind).must_equal :server + _(last_span.status.code).must_equal 1 + _(last_span.hex_parent_span_id).must_equal '0000000000000000' + + _(last_span.attributes['faas.id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' + _(last_span.attributes['faas.execution']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['http.method']).must_equal 'GET' + _(last_span.attributes['http.route']).must_equal '/' + _(last_span.attributes['http.target']).must_equal '/' + _(last_span.attributes['http.user_agent']).must_equal 'curl/8.1.2' + _(last_span.attributes['http.scheme']).must_equal 'http' + _(last_span.attributes['net.host.name']).must_equal '127.0.0.1:3000' + + _(last_span.instrumentation_scope).must_be_kind_of OpenTelemetry::SDK::InstrumentationScope + _(last_span.instrumentation_scope.name).must_equal 'OpenTelemetry::Instrumentation::AwsLambda' + _(last_span.instrumentation_scope.version).must_equal '0.0.1' + + _(last_span.hex_span_id.size).must_equal 16 + _(last_span.hex_trace_id.size).must_equal 32 + _(last_span.trace_flags.sampled?).must_equal true + _(last_span.tracestate.to_h.to_s).must_equal '{}' + end + end + + it 'validate_spans_with_parent_context' do + event_v1['headers']['Traceparent'] = '00-48b05d64abe4690867685635f72bdbac-ff40ea9699e62af2-01' + event_v1['headers']['Tracestate'] = 'otel=ff40ea9699e62af2-01' + + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, {}) do + otel_wrapper.call_wrapped(event: event_v1, context: context) + + _(last_span.name).must_equal 'sample.test' + _(last_span.kind).must_equal :server + + _(last_span.hex_parent_span_id).must_equal 'ff40ea9699e62af2' + _(last_span.hex_span_id.size).must_equal 16 + _(last_span.hex_trace_id.size).must_equal 32 + _(last_span.trace_flags.sampled?).must_equal true + _(last_span.tracestate.to_h.to_s).must_equal '{"otel"=>"ff40ea9699e62af2-01"}' + end + event_v1['headers'].delete('traceparent') + event_v1['headers'].delete('tracestate') + end + + it 'validate_spans_with_v2_events' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, {}) do + otel_wrapper.call_wrapped(event: event_v2, context: context) + + _(last_span.name).must_equal 'sample.test' + _(last_span.kind).must_equal :server + _(last_span.status.code).must_equal 1 + _(last_span.hex_parent_span_id).must_equal '0000000000000000' + + _(last_span.attributes['faas.id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' + _(last_span.attributes['faas.execution']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['net.host.name']).must_equal 'id.execute-api.us-east-1.amazonaws.com' + _(last_span.attributes['http.method']).must_equal 'POST' + _(last_span.attributes['http.user_agent']).must_equal 'agent' + _(last_span.attributes['http.route']).must_equal '/path/to/resource' + _(last_span.attributes['http.target']).must_equal '/path/to/resource?parameter1=value1¶meter1=value2¶meter2=value' + end + end + end +end diff --git a/instrumentation/aws_lambda/test/test_helper.rb b/instrumentation/aws_lambda/test/test_helper.rb new file mode 100644 index 000000000..a28f89e72 --- /dev/null +++ b/instrumentation/aws_lambda/test/test_helper.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'bundler/setup' +Bundler.require(:default, :development, :test) + +require 'opentelemetry-instrumentation-aws_lambda' + +require 'minitest/autorun' +require 'rspec/mocks/minitest_integration' + +class MockLambdaContext + attr_reader :aws_request_id, :invoked_function_arn + + def initialize(aws_request_id:, invoked_function_arn:) + @aws_request_id = aws_request_id + @invoked_function_arn = invoked_function_arn + end +end + +EXPORTER = OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new +span_processor = OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER) + +EVENT_V1 = { + 'body' => nil, + 'headers' => { + 'Accept' => '*/*', + 'Host' => '127.0.0.1:3000', + 'User-Agent' => 'curl/8.1.2', + 'X-Forwarded-Port' => 3000, + 'X-Forwarded-Proto' => 'http' + }, + 'httpMethod' => 'GET', + 'isBase64Encoded' => false, + 'multiValueHeaders' => {}, + 'multiValueQueryStringParameters' => nil, + 'path' => '/', + 'pathParameters' => nil, + 'queryStringParameters' => nil, + requestContext: { + 'accountId' => 123_456_789_012, + 'apiId' => 1_234_567_890, + 'domainName' => '127.0.0.1:3000', + 'extendedRequestId' => nil, + 'httpMethod' => 'GET', + 'identity' => {}, + 'path' => '/', + 'protocol' => 'HTTP/1.1', + 'requestId' => 'db7f8e7a-4cc5-4f6d-987b-713d0d9052c3', + 'requestTime' => '08/Nov/2023:19:09:59 +0000', + 'requestTimeEpoch' => 1_699_470_599, + 'resourceId' => '123456', + 'resourcePath' => '/', + 'stage' => 'api' + }, + 'resource' => '/', + 'stageVariables' => nil, + 'version' => '1.0' +}.freeze + +EVENT_V2 = { + 'version' => '2.0', + 'routeKey' => '$default', + 'rawPath' => '/path/to/resource', + 'rawQueryString' => 'parameter1=value1¶meter1=value2¶meter2=value', + 'cookies' => %w[cookie1 cookie2], + 'headers' => { 'header1' => 'value1', 'Header2' => 'value1,value2' }, + 'queryStringParameters' => {}, + 'requestContext' => { + 'accountId' => '123456789012', + 'apiId' => 'api-id', + 'authentication' => { 'clientCert' => {} }, + 'authorizer' => {}, + 'domainName' => 'id.execute-api.us-east-1.amazonaws.com', + 'domainPrefix' => 'id', + 'http' => { + 'method' => 'POST', + 'path' => '/path/to/resource', + 'protocol' => 'HTTP/1.1', + 'sourceIp' => '192.168.0.1/32', + 'userAgent' => 'agent' + }, + 'requestId' => 'id', + 'routeKey' => '$default', + 'stage' => '$default', + 'time' => '12/Mar/2020:19:03:58 +0000', + 'timeEpoch' => 1_583_348_638_390 + }, + 'body' => 'eyJ0ZXN0IjoiYm9keSJ9', + 'pathParameters' => { 'parameter1' => 'value1' }, + 'isBase64Encoded' => true, + 'stageVariables' => { 'stageVariable1' => 'value1', 'stageVariable2' => 'value2' } +}.freeze + +CONTEXT = MockLambdaContext.new(aws_request_id: '41784178-4178-4178-4178-4178417855e', + invoked_function_arn: 'arn:aws:lambda:location:id:function_name:function_name') + +OpenTelemetry::SDK.configure do |c| + c.error_handler = ->(exception:, message:) { raise(exception || message) } + c.logger = Logger.new($stderr, level: ENV.fetch('OTEL_LOG_LEVEL', 'fatal').to_sym) + c.use 'OpenTelemetry::Instrumentation::AwsLambda' + c.add_span_processor span_processor +end From 42dba8e129c629a03b2d841d567695e91d9790dd Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 15 Nov 2023 00:35:45 -0500 Subject: [PATCH 02/42] feat: return original handler response and require the handler file --- .../opentelemetry/instrumentation/aws_lambda/handler.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 2548dfe99..20c1ff4f7 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -40,18 +40,23 @@ def call_wrapped(event:, context:) span&.finish OpenTelemetry.tracer_provider.force_flush(timeout: @flush_timeout) end + + response end def resolve_original_handler original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' original_handler_parts = original_handler.split('.') if original_handler_parts.size == 2 - _, @handler_method = original_handler_parts + hanlder_file, @handler_method = original_handler_parts elsif original_handler_parts.size == 3 - _, @handler_class, @handler_method = original_handler_parts + hanlder_file, @handler_class, @handler_method = original_handler_parts else OpenTelemetry.logger.warn("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") end + + require hanlder_file + original_handler end From c708d0ad35a5aa6d820f404175d7d9ede0c69610 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:57:40 -0500 Subject: [PATCH 03/42] Update instrumentation/aws_lambda/README.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index dc091e279..e94e61e6e 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -14,7 +14,7 @@ Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-a ## Usage -From Lambda Layer side, create the wrapper. More information can be found in https://github.com/open-telemetry/opentelemetry-lambda +From the Lambda Layer side, create the wrapper. More information can be found at https://github.com/open-telemetry/opentelemetry-lambda ```ruby require 'opentelemetry/sdk' require 'opentelemetry/instrumentation/all' From 0b5891abffd1510a429bbea22d3731b600c73263 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:58:01 -0500 Subject: [PATCH 04/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 20c1ff4f7..6be69c2c7 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -48,7 +48,7 @@ def resolve_original_handler original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' original_handler_parts = original_handler.split('.') if original_handler_parts.size == 2 - hanlder_file, @handler_method = original_handler_parts + handler_file, @handler_method = original_handler_parts elsif original_handler_parts.size == 3 hanlder_file, @handler_class, @handler_method = original_handler_parts else From 9601fd1e87883b0bae3ede352f44887cccc69ca0 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:58:07 -0500 Subject: [PATCH 05/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 6be69c2c7..85645f0c7 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -50,7 +50,7 @@ def resolve_original_handler if original_handler_parts.size == 2 handler_file, @handler_method = original_handler_parts elsif original_handler_parts.size == 3 - hanlder_file, @handler_class, @handler_method = original_handler_parts + handler_file, @handler_class, @handler_method = original_handler_parts else OpenTelemetry.logger.warn("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") end From 34db557293c8dffbbe9648abc33b024ee6efd72c Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:58:13 -0500 Subject: [PATCH 06/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 85645f0c7..656630a6d 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -55,7 +55,7 @@ def resolve_original_handler OpenTelemetry.logger.warn("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") end - require hanlder_file + require handler_file original_handler end From 3e54dfad1a5c1abc5163f2dd657d30b06323b467 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:58:20 -0500 Subject: [PATCH 07/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb index 975a6913e..fb8d41885 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda.rb @@ -9,7 +9,7 @@ module OpenTelemetry module Instrumentation - # Contains the OpenTelemetry instrumentation for the Aws gem + # Contains the OpenTelemetry instrumentation for the aws_lambda gem module AwsLambda end end From fbc942e9496325659a63e9fc66230e0105c4903a Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:58:27 -0500 Subject: [PATCH 08/42] Update instrumentation/aws_lambda/example/Gemfile Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/example/Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/instrumentation/aws_lambda/example/Gemfile b/instrumentation/aws_lambda/example/Gemfile index f6b99dfd6..934ac342f 100644 --- a/instrumentation/aws_lambda/example/Gemfile +++ b/instrumentation/aws_lambda/example/Gemfile @@ -2,6 +2,5 @@ source 'https://rubygems.org' -gem 'opentelemetry-api' gem 'opentelemetry-instrumentation-aws_lambda', path: '../' gem 'opentelemetry-sdk' From 432670a3230fbe3ceabcd32f4432a061db1aab87 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 12 Dec 2023 12:23:14 -0500 Subject: [PATCH 09/42] feat: revision on fix sample test, update readme and add rubocop-performance --- instrumentation/aws_lambda/.rubocop.yml | 1 + instrumentation/aws_lambda/README.md | 3 +-- .../aws_lambda/example/trace_demonstration.rb | 26 +++++++++++++++++++ ...lemetry-instrumentation-aws_lambda.gemspec | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 instrumentation/aws_lambda/.rubocop.yml diff --git a/instrumentation/aws_lambda/.rubocop.yml b/instrumentation/aws_lambda/.rubocop.yml new file mode 100644 index 000000000..1248a2f82 --- /dev/null +++ b/instrumentation/aws_lambda/.rubocop.yml @@ -0,0 +1 @@ +inherit_from: ../../.rubocop.yml diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index e94e61e6e..04f57fe54 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -17,10 +17,9 @@ Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-a From the Lambda Layer side, create the wrapper. More information can be found at https://github.com/open-telemetry/opentelemetry-lambda ```ruby require 'opentelemetry/sdk' -require 'opentelemetry/instrumentation/all' +require 'opentelemetry/instrumentation/aws_lambda' OpenTelemetry::SDK.configure do |c| c.service_name = '' - c.use_all() end def otel_wrapper(event:, context:) diff --git a/instrumentation/aws_lambda/example/trace_demonstration.rb b/instrumentation/aws_lambda/example/trace_demonstration.rb index f7eb1e301..44efc5fb9 100755 --- a/instrumentation/aws_lambda/example/trace_demonstration.rb +++ b/instrumentation/aws_lambda/example/trace_demonstration.rb @@ -27,6 +27,32 @@ def initialize(aws_request_id:, invoked_function_arn:) end end +# To accommendate the test case, handler class doesn't need to require the sample file if it's required here +# In lambda environment, the env will find the handler file. +module OpenTelemetry + module Instrumentation + module AwsLambda + class Handler + def resolve_original_handler + original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' + original_handler_parts = original_handler.split('.') + if original_handler_parts.size == 2 + handler_file, @handler_method = original_handler_parts + elsif original_handler_parts.size == 3 + handler_file, @handler_class, @handler_method = original_handler_parts + else + OpenTelemetry.logger.warn("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") + end + + # require handler_file #-> don't require file for this sample test + + original_handler + end + end + end + end +end + def otel_wrapper(event:, context:) otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new() otel_wrapper.call_wrapped(event: event, context: context) diff --git a/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec b/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec index 5567e5081..972f1ee70 100644 --- a/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec +++ b/instrumentation/aws_lambda/opentelemetry-instrumentation-aws_lambda.gemspec @@ -37,6 +37,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'pry-byebug' unless RUBY_ENGINE == 'jruby' spec.add_development_dependency 'rspec-mocks' spec.add_development_dependency 'rubocop', '~> 1.56.1' + spec.add_development_dependency 'rubocop-performance', '~> 1.19.1' spec.add_development_dependency 'simplecov', '~> 0.17.1' spec.add_development_dependency 'webmock', '~> 3.19' spec.add_development_dependency 'yard', '~> 0.9' From 25f04954da699e2c15028bb2a44f7186b7fbfe96 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 12 Dec 2023 14:09:40 -0500 Subject: [PATCH 10/42] feat: update readme --- instrumentation/aws_lambda/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index 04f57fe54..79aeaac8e 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -20,6 +20,7 @@ require 'opentelemetry/sdk' require 'opentelemetry/instrumentation/aws_lambda' OpenTelemetry::SDK.configure do |c| c.service_name = '' + c.use 'OpenTelemetry::Instrumentation::AwsLambda' end def otel_wrapper(event:, context:) From 0a19da1134ffa950223ca4bbd7bf299a60b30596 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:11:42 -0500 Subject: [PATCH 11/42] Update instrumentation/aws_lambda/CHANGELOG.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/instrumentation/aws_lambda/CHANGELOG.md b/instrumentation/aws_lambda/CHANGELOG.md index 25fbd7472..1fb233945 100644 --- a/instrumentation/aws_lambda/CHANGELOG.md +++ b/instrumentation/aws_lambda/CHANGELOG.md @@ -1,5 +1 @@ # Release History: opentelemetry-instrumentation-aws_lambda - -### v0.1.0 / 2021-12-01 - -* Initial release. From 609a4199bd282787d7c21956f806c29c8cd3051e Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:11:59 -0500 Subject: [PATCH 12/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb index b1313b85c..6723022fd 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module AwsLambda - VERSION = '0.0.1' + VERSION = '0.1.0' end end end From 118f6eef9210bd125e5edc534e004398703884bb Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 13 Feb 2024 14:30:27 -0500 Subject: [PATCH 13/42] feat: add codeowner for aws_lambda --- CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index f24644798..8047b4632 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -31,3 +31,5 @@ instrumentation/racecar/ @chrisholmes @open-telemetry/ruby-contrib-maintainers @ instrumentation/rspec/ @chrisholmes @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi instrumentation/que/ @indrekj @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi + +instrumentation/aws_lambda/ @indrekj @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi From b1536ac9303f2157c6e0f6f8e7bad304a8b8ba90 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:46:15 -0500 Subject: [PATCH 14/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 656630a6d..a1628f394 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module AwsLambda - # Handler class that create span around the _HANDLER + # Handler class that creates a span around the _HANDLER class Handler attr_reader :handler_method, :handler_class From 625efa36a0d5ded78d53f89e4123a0e11ce44148 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 5 Mar 2024 11:27:10 -0500 Subject: [PATCH 15/42] Update CODEOWNERS Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- CODEOWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 8047b4632..7031899fa 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -32,4 +32,3 @@ instrumentation/rspec/ @chrisholmes @open-telemetry/ruby-contrib-maintainers @op instrumentation/que/ @indrekj @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi -instrumentation/aws_lambda/ @indrekj @open-telemetry/ruby-contrib-maintainers @open-telemetry/ruby-contrib-approvers @fbogsany @mwear @robertlaurin @dazuma @ericmustin @arielvalentin @ahayworth @plantfansam @robbkidd @simi @kaylareopelle @xuan-cao-swi From ea195c6f10e8ab89851e0a035b3f9b9cb5f0fb63 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 5 Mar 2024 20:53:45 -0500 Subject: [PATCH 16/42] feat: lambda - update semantic convention and test case --- .../aws_lambda/example/trace_demonstration.rb | 7 +++--- .../instrumentation/aws_lambda/handler.rb | 13 +++++++++-- .../aws_lambda/instrumentation.rb | 4 ++-- .../opentelemetry/instrumentation_test.rb | 22 ++++++++----------- .../aws_lambda/test/test_helper.rb | 11 +++++++--- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/instrumentation/aws_lambda/example/trace_demonstration.rb b/instrumentation/aws_lambda/example/trace_demonstration.rb index 44efc5fb9..b416ffd7a 100755 --- a/instrumentation/aws_lambda/example/trace_demonstration.rb +++ b/instrumentation/aws_lambda/example/trace_demonstration.rb @@ -19,11 +19,12 @@ end class MockLambdaContext - attr_reader :aws_request_id, :invoked_function_arn + attr_reader :aws_request_id, :invoked_function_arn, :function_name - def initialize(aws_request_id:, invoked_function_arn:) + def initialize(aws_request_id:, invoked_function_arn:, function_name:) @aws_request_id = aws_request_id @invoked_function_arn = invoked_function_arn + @function_name = function_name end end @@ -96,6 +97,6 @@ def otel_wrapper(event:, context:) "version" => "1.0" } -context = MockLambdaContext.new(aws_request_id: "aws_request_id",invoked_function_arn: "invoked_function_arn") +context = MockLambdaContext.new(aws_request_id: "aws_request_id",invoked_function_arn: "invoked_function_arn",function_name: "function") otel_wrapper(event: event, context: context) # you should see Success before the trace diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index a1628f394..29c4ce10a 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -22,9 +22,8 @@ def call_wrapped(event:, context:) original_handler = resolve_original_handler response = call_original_handler(event: event, context: context) + span_attributes.merge!(otel_attributes(context)) span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] if response.instance_of?(Hash) && response['statusCode'] - span_attributes[OpenTelemetry::SemanticConventions::Resource::FAAS_ID] = context.invoked_function_arn - span_attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_EXECUTION] = context.aws_request_id OpenTelemetry::Context.with_current(parent_context) do span = tracer.start_span( @@ -126,6 +125,16 @@ def v2_proxy_attributes(event) attributes end + + # TODO: need to update Semantic Conventions for invocation_id, trigger and resource_id + def otel_attributes(context) + { + 'faas.invocation_id' => context.aws_request_id, + 'faas.trigger' => context.function_name, + OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN => context.invoked_function_arn, + 'cloud.resource_id' => "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" + } + end end end end diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb index f907db5cb..3f99c29f1 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb @@ -13,9 +13,9 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base require_dependencies end + # determine if current environment is lambda by checking _HANLDER or ORIG_HANDLER present do - # maybe check if ORIG_HANDLER or _HANLDER exist - true + (ENV.key?('_HANDLER') || ENV.key?('ORIG_HANDLER')) end compatible do diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index bb7af0d36..5547aca49 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -37,14 +37,6 @@ end describe 'validate_wrapper' do - before do - ENV['ORIG_HANDLER'] = 'sample.test' - end - - after do - ENV.delete('ORIG_HANDLER') - end - it 'result should be span' do otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new otel_wrapper.stub(:call_original_handler, {}) do @@ -63,8 +55,10 @@ _(last_span.status.code).must_equal 1 _(last_span.hex_parent_span_id).must_equal '0000000000000000' - _(last_span.attributes['faas.id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' - _(last_span.attributes['faas.execution']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' + _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['faas.trigger']).must_equal 'funcion' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' _(last_span.attributes['http.method']).must_equal 'GET' _(last_span.attributes['http.route']).must_equal '/' _(last_span.attributes['http.target']).must_equal '/' @@ -74,7 +68,7 @@ _(last_span.instrumentation_scope).must_be_kind_of OpenTelemetry::SDK::InstrumentationScope _(last_span.instrumentation_scope.name).must_equal 'OpenTelemetry::Instrumentation::AwsLambda' - _(last_span.instrumentation_scope.version).must_equal '0.0.1' + _(last_span.instrumentation_scope.version).must_equal '0.1.0' _(last_span.hex_span_id.size).must_equal 16 _(last_span.hex_trace_id.size).must_equal 32 @@ -114,8 +108,10 @@ _(last_span.status.code).must_equal 1 _(last_span.hex_parent_span_id).must_equal '0000000000000000' - _(last_span.attributes['faas.id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' - _(last_span.attributes['faas.execution']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' + _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['faas.trigger']).must_equal 'funcion' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' _(last_span.attributes['net.host.name']).must_equal 'id.execute-api.us-east-1.amazonaws.com' _(last_span.attributes['http.method']).must_equal 'POST' _(last_span.attributes['http.user_agent']).must_equal 'agent' diff --git a/instrumentation/aws_lambda/test/test_helper.rb b/instrumentation/aws_lambda/test/test_helper.rb index a28f89e72..df241736d 100644 --- a/instrumentation/aws_lambda/test/test_helper.rb +++ b/instrumentation/aws_lambda/test/test_helper.rb @@ -13,11 +13,12 @@ require 'rspec/mocks/minitest_integration' class MockLambdaContext - attr_reader :aws_request_id, :invoked_function_arn + attr_reader :aws_request_id, :invoked_function_arn, :function_name - def initialize(aws_request_id:, invoked_function_arn:) + def initialize(aws_request_id:, invoked_function_arn:, function_name:) @aws_request_id = aws_request_id @invoked_function_arn = invoked_function_arn + @function_name = function_name end end @@ -96,8 +97,12 @@ def initialize(aws_request_id:, invoked_function_arn:) }.freeze CONTEXT = MockLambdaContext.new(aws_request_id: '41784178-4178-4178-4178-4178417855e', - invoked_function_arn: 'arn:aws:lambda:location:id:function_name:function_name') + invoked_function_arn: 'arn:aws:lambda:location:id:function_name:function_name', + function_name: 'funcion') +$LOAD_PATH.unshift("#{Dir.pwd}/example/") +ENV['ORIG_HANDLER'] = 'sample.test' +ENV['_HANDLER'] = 'sample.test' OpenTelemetry::SDK.configure do |c| c.error_handler = ->(exception:, message:) { raise(exception || message) } c.logger = Logger.new($stderr, level: ENV.fetch('OTEL_LOG_LEVEL', 'fatal').to_sym) From 9807308600a1d2b5aaeb0534c6958f43718238a9 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 5 Mar 2024 21:07:55 -0500 Subject: [PATCH 17/42] feat: add lambda to workflow --- .github/dependabot.yml | 4 ++++ .github/workflows/ci-instrumentation-canary.yml | 2 ++ .github/workflows/ci-instrumentation.yml | 2 ++ 3 files changed, 8 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9e4ed404b..5cf3f91db 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -89,6 +89,10 @@ updates: directory: "/instrumentation/aws_sdk" schedule: interval: weekly +- package-ecosystem: bundler + directory: "/instrumentation/aws_lambda" + schedule: + interval: weekly - package-ecosystem: bundler directory: "/instrumentation/active_record" schedule: diff --git a/.github/workflows/ci-instrumentation-canary.yml b/.github/workflows/ci-instrumentation-canary.yml index e3e1afe16..b6c26bfdf 100644 --- a/.github/workflows/ci-instrumentation-canary.yml +++ b/.github/workflows/ci-instrumentation-canary.yml @@ -19,6 +19,7 @@ jobs: - active_support - all - aws_sdk + - aws_lambda - base - concurrent_ruby - delayed_job @@ -98,6 +99,7 @@ jobs: [[ "${{ matrix.gem }}" == "active_record" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "active_support" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "aws_sdk" ]] && echo "skip=true" >> $GITHUB_OUTPUT + [[ "${{ matrix.gem }}" == "aws_lambda" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "delayed_job" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "graphql" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "http" ]] && echo "skip=true" >> $GITHUB_OUTPUT diff --git a/.github/workflows/ci-instrumentation.yml b/.github/workflows/ci-instrumentation.yml index 59088633a..5c77f1869 100644 --- a/.github/workflows/ci-instrumentation.yml +++ b/.github/workflows/ci-instrumentation.yml @@ -23,6 +23,7 @@ jobs: - active_support - all - aws_sdk + - aws_lambda - base - concurrent_ruby - delayed_job @@ -85,6 +86,7 @@ jobs: [[ "${{ matrix.gem }}" == "active_record" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "active_support" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "aws_sdk" ]] && echo "skip=true" >> $GITHUB_OUTPUT + [[ "${{ matrix.gem }}" == "aws_lambda" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "delayed_job" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "graphql" ]] && echo "skip=true" >> $GITHUB_OUTPUT [[ "${{ matrix.gem }}" == "http" ]] && echo "skip=true" >> $GITHUB_OUTPUT From 198d464d3523c47942022f345b293ae705e3cbf1 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 5 Mar 2024 21:21:04 -0500 Subject: [PATCH 18/42] feat: lambda - run test with rake test directly --- instrumentation/aws_lambda/Appraisals | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 instrumentation/aws_lambda/Appraisals diff --git a/instrumentation/aws_lambda/Appraisals b/instrumentation/aws_lambda/Appraisals deleted file mode 100644 index f7cf8339f..000000000 --- a/instrumentation/aws_lambda/Appraisals +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -# Copyright The OpenTelemetry Authors -# -# SPDX-License-Identifier: Apache-2.0 From f01e9fe383e711db1fd9ffc7010d510e7a24ec17 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Wed, 6 Mar 2024 11:35:11 -0500 Subject: [PATCH 19/42] feat: lambda - add rescue to avoid break user function --- .../instrumentation/aws_lambda/handler.rb | 97 ++++++++++++------- .../opentelemetry/instrumentation_test.rb | 42 ++++++++ 2 files changed, 103 insertions(+), 36 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 29c4ce10a..c4b19899b 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -11,52 +11,79 @@ module AwsLambda class Handler attr_reader :handler_method, :handler_class + # anytime when update the code in a Lambda function or change the functional configuration, + # the next invocation results in a cold start; therefore these instance variable will be up-to-date def initialize - @flush_timeout = ENV.fetch('OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT', '30000').to_i + @flush_timeout = ENV.fetch('OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT', '30000').to_i + @original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' + @handler_class = nil + @handler_method = nil + @handler_file = nil + + resolve_original_handler end - # Extract context from request headers + # We want to capture the error if user's handler is causing issue + # but our wrapper and handler shouldn't cause any issue def call_wrapped(event:, context:) parent_context = extract_parent_context(event) - span_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) - original_handler = resolve_original_handler - response = call_original_handler(event: event, context: context) - - span_attributes.merge!(otel_attributes(context)) - span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] if response.instance_of?(Hash) && response['statusCode'] + span_attributes = otel_attributes(event, context) + + response = nil + original_handler_error = nil + begin + response = call_original_handler(event: event, context: context) + span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] if response.instance_of?(Hash) && response['statusCode'] + rescue StandardError => e + original_handler_error = e + span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = '500' + end OpenTelemetry::Context.with_current(parent_context) do span = tracer.start_span( - original_handler, + @original_handler, attributes: span_attributes, kind: :server # Span kind MUST be `:server` for a HTTP server span ) - rescue Exception => e # rubocop:disable Lint/RescueException + rescue StandardError => e span&.record_exception(e) span&.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}") - raise e ensure + if original_handler_error + span&.record_exception(original_handler_error) + span&.status = OpenTelemetry::Trace::Status.error("Original lambda handler exception: #{original_handler_error.class}. Please check if you have correct handler setting or code in lambda function.") + end span&.finish OpenTelemetry.tracer_provider.force_flush(timeout: @flush_timeout) end + raise original_handler_error if original_handler_error + response end + def instrumentation_config + AwsLambda::Instrumentation.instance.config + end + + def tracer + AwsLambda::Instrumentation.instance.tracer + end + + private + + # we don't expose error if our code cause issue that block user's code def resolve_original_handler - original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' - original_handler_parts = original_handler.split('.') + original_handler_parts = @original_handler.split('.') if original_handler_parts.size == 2 - handler_file, @handler_method = original_handler_parts + @handler_file, @handler_method = original_handler_parts elsif original_handler_parts.size == 3 - handler_file, @handler_class, @handler_method = original_handler_parts + @handler_file, @handler_class, @handler_method = original_handler_parts else - OpenTelemetry.logger.warn("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") + OpenTelemetry.logger.error("aws-lambda instrumentation: Invalid handler #{original_handler}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD.") end - require handler_file - - original_handler + require @handler_file if @handler_file end def call_original_handler(event:, context:) @@ -67,17 +94,9 @@ def call_original_handler(event:, context:) end end - def instrumentation_config - AwsLambda::Instrumentation.instance.config - end - - def tracer - AwsLambda::Instrumentation.instance.tracer - end - - private - + # Extract parent context from request headers # Downcase Traceparent and Tracestate because TraceContext::TextMapPropagator's TRACEPARENT_KEY and TRACESTATE_KEY are all lowercase + # If any error occur, rescue and give empty context def extract_parent_context(event) headers = event['headers'] || {} headers.transform_keys! do |key| @@ -88,6 +107,9 @@ def extract_parent_context(event) headers, getter: OpenTelemetry::Context::Propagation.text_map_getter ) + rescue StandardError => e + OpenTelemetry.logger.error("aws-lambda instrumentation exception occur while extracting parent context: #{e.message}") + OpenTelemetry::Context.empty end def v1_proxy_attributes(event) @@ -127,13 +149,16 @@ def v2_proxy_attributes(event) end # TODO: need to update Semantic Conventions for invocation_id, trigger and resource_id - def otel_attributes(context) - { - 'faas.invocation_id' => context.aws_request_id, - 'faas.trigger' => context.function_name, - OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN => context.invoked_function_arn, - 'cloud.resource_id' => "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" - } + def otel_attributes(event, context) + span_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) + span_attributes['faas.invocation_id'] = context.aws_request_id + span_attributes['faas.trigger'] = context.function_name + span_attributes[OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN] = context.invoked_function_arn + span_attributes['cloud.resource_id'] = "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" + span_attributes + rescue StandardError => e + OpenTelemetry.logger.error("aws-lambda instrumentation exception occur while preparing span attributes: #{e.message}") + {} end end end diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index 5547aca49..5835d1730 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -120,4 +120,46 @@ end end end + + describe 'validate_error_handling' do + it 'handle error if original handler cause issue' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, ->(**_args) { raise StandardError, 'Simulated Error' }) do + otel_wrapper.call_wrapped(event: event_v1, context: context) + rescue StandardError + _(last_span.name).must_equal 'sample.test' + _(last_span.kind).must_equal :server + + _(last_span.status.code).must_equal 2 + _(last_span.status.description).must_equal 'Original lambda handler exception: StandardError. Please check if you have correct handler setting or code in lambda function.' + _(last_span.hex_parent_span_id).must_equal '0000000000000000' + + _(last_span.events[0].name).must_equal 'exception' + _(last_span.events[0].attributes['exception.type']).must_equal 'StandardError' + _(last_span.events[0].attributes['exception.message']).must_equal 'Simulated Error' + + _(last_span.hex_span_id.size).must_equal 16 + _(last_span.hex_trace_id.size).must_equal 32 + _(last_span.trace_flags.sampled?).must_equal true + _(last_span.tracestate.to_h.to_s).must_equal '{}' + + _(last_span.attributes['http.status_code']).must_equal '500' + end + end + + it 'if wrapped handler cause otel-related issue, wont break the entire lambda call' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_wrapped, { 'test' => 'ok' }) do + otel_wrapper.stub(:call_original_handler, {}) do + OpenTelemetry::Context.stub(:with_current, lambda { |_context| + tracer.start_span('test_span', attributes: {}, kind: :server) + raise StandardError, 'OTEL Error' + }) do + response = otel_wrapper.call_wrapped(event: event_v1, context: context) + _(response['test']).must_equal 'ok' + end + end + end + end + end end From d7c47b37f755c39d835531342ea5929f65a5e739 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 18 Mar 2024 18:49:05 -0400 Subject: [PATCH 20/42] feat: aws lambda - make faas.trigger static to http as following spec. add cloud account id --- .../aws_lambda/example/trace_demonstration.rb | 2 +- .../instrumentation/aws_lambda/handler.rb | 26 +++++++++++-------- .../opentelemetry/instrumentation_test.rb | 4 +-- .../aws_lambda/test/test_helper.rb | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/instrumentation/aws_lambda/example/trace_demonstration.rb b/instrumentation/aws_lambda/example/trace_demonstration.rb index b416ffd7a..b135bad5b 100755 --- a/instrumentation/aws_lambda/example/trace_demonstration.rb +++ b/instrumentation/aws_lambda/example/trace_demonstration.rb @@ -76,7 +76,7 @@ def otel_wrapper(event:, context:) "path" => "/", "pathParameters" => nil, "queryStringParameters" => nil, - "requestContext":{ + "requestContext" => { "accountId" => 123456789012, "apiId" => 1234567890, "domainName" => "127.0.0.1:3000", diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index c4b19899b..b272473f5 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -112,6 +112,8 @@ def extract_parent_context(event) OpenTelemetry::Context.empty end + # lambda event version 1.0 and version 2.0 + # https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html def v1_proxy_attributes(event) attributes = { OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => event['httpMethod'], @@ -131,30 +133,32 @@ def v1_proxy_attributes(event) end def v2_proxy_attributes(event) + attributes = {} request_context = event['requestContext'] if request_context - attributes = { - OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME => request_context['domainName'], - OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_context['http']['method'], - OpenTelemetry::SemanticConventions::Trace::HTTP_USER_AGENT => request_context['http']['userAgent'], - OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE => request_context['http']['path'], - OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => request_context['http']['path'] - } + attributes.merge!({ + OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME => request_context['domainName'], + OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_context['http']['method'], + OpenTelemetry::SemanticConventions::Trace::HTTP_USER_AGENT => request_context['http']['userAgent'], + OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE => request_context['http']['path'], + OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => request_context['http']['path'] + }) attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] += "?#{event['rawQueryString']}" if event['rawQueryString'] - else - attributes = {} end attributes end + # fass.trigger set to http: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#api-gateway # TODO: need to update Semantic Conventions for invocation_id, trigger and resource_id def otel_attributes(event, context) span_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) span_attributes['faas.invocation_id'] = context.aws_request_id - span_attributes['faas.trigger'] = context.function_name - span_attributes[OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN] = context.invoked_function_arn + span_attributes['faas.trigger'] = 'http' span_attributes['cloud.resource_id'] = "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" + span_attributes[OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN] = context.invoked_function_arn + span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = event['requestContext']['accountId'] if event['requestContext'] + span_attributes rescue StandardError => e OpenTelemetry.logger.error("aws-lambda instrumentation exception occur while preparing span attributes: #{e.message}") diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index 5835d1730..c0cc5f59a 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -57,7 +57,7 @@ _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' - _(last_span.attributes['faas.trigger']).must_equal 'funcion' + _(last_span.attributes['faas.trigger']).must_equal 'http' _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' _(last_span.attributes['http.method']).must_equal 'GET' _(last_span.attributes['http.route']).must_equal '/' @@ -110,7 +110,7 @@ _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' - _(last_span.attributes['faas.trigger']).must_equal 'funcion' + _(last_span.attributes['faas.trigger']).must_equal 'http' _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' _(last_span.attributes['net.host.name']).must_equal 'id.execute-api.us-east-1.amazonaws.com' _(last_span.attributes['http.method']).must_equal 'POST' diff --git a/instrumentation/aws_lambda/test/test_helper.rb b/instrumentation/aws_lambda/test/test_helper.rb index df241736d..ccb596c2e 100644 --- a/instrumentation/aws_lambda/test/test_helper.rb +++ b/instrumentation/aws_lambda/test/test_helper.rb @@ -41,7 +41,7 @@ def initialize(aws_request_id:, invoked_function_arn:, function_name:) 'path' => '/', 'pathParameters' => nil, 'queryStringParameters' => nil, - requestContext: { + 'requestContext' => { 'accountId' => 123_456_789_012, 'apiId' => 1_234_567_890, 'domainName' => '127.0.0.1:3000', From 4fe7b87f6d2c85988b73ceccafeb7f4833cc83cb Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:33:35 -0400 Subject: [PATCH 21/42] Update instrumentation/aws_lambda/README.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index 79aeaac8e..ccc5c9986 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -14,7 +14,7 @@ Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-a ## Usage -From the Lambda Layer side, create the wrapper. More information can be found at https://github.com/open-telemetry/opentelemetry-lambda +From the Lambda Layer side, create the wrapper. More information can be found at https://github.com/open-telemetry/opentelemetry-lambda/tree/main/ruby ```ruby require 'opentelemetry/sdk' require 'opentelemetry/instrumentation/aws_lambda' From ba86dc76dec7be616c46d54f47a8287a4457b4db Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:38:25 -0400 Subject: [PATCH 22/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index b272473f5..1e3ce57cf 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -108,7 +108,7 @@ def extract_parent_context(event) getter: OpenTelemetry::Context::Propagation.text_map_getter ) rescue StandardError => e - OpenTelemetry.logger.error("aws-lambda instrumentation exception occur while extracting parent context: #{e.message}") + OpenTelemetry.logger.error("aws-lambda instrumentation exception occurred while extracting the parent context: #{e.message}") OpenTelemetry::Context.empty end From 3cb6dd688924afae015a1d41b714d88e2316b201 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:38:32 -0400 Subject: [PATCH 23/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 1e3ce57cf..ef8632d99 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -161,7 +161,7 @@ def otel_attributes(event, context) span_attributes rescue StandardError => e - OpenTelemetry.logger.error("aws-lambda instrumentation exception occur while preparing span attributes: #{e.message}") + OpenTelemetry.logger.error("aws-lambda instrumentation exception occurred while preparing span attributes: #{e.message}") {} end end From f412fd5ef65cdbcf90aabe4c4fc050694cf0bbec Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 19 Mar 2024 17:24:08 -0400 Subject: [PATCH 24/42] feat: lambda - use symbol and str for statusCode --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index b272473f5..01b0ec866 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -33,7 +33,7 @@ def call_wrapped(event:, context:) original_handler_error = nil begin response = call_original_handler(event: event, context: context) - span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] if response.instance_of?(Hash) && response['statusCode'] + span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] || response[:statusCode] if response.is_a? Hash rescue StandardError => e original_handler_error = e span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = '500' From f80067bb453fe90247d1d52acded7c89af99b84b Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 19 Mar 2024 17:37:36 -0400 Subject: [PATCH 25/42] feat: lambda - refactor on status code --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 2dd9ae027..b8652b263 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -33,12 +33,14 @@ def call_wrapped(event:, context:) original_handler_error = nil begin response = call_original_handler(event: event, context: context) - span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = response['statusCode'] || response[:statusCode] if response.is_a? Hash + status_code = response.is_a?(Hash) ? (response['statusCode'] || response[:statusCode]) : nil rescue StandardError => e original_handler_error = e - span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = '500' + status_code = '500' end + span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = status_code if status_code + OpenTelemetry::Context.with_current(parent_context) do span = tracer.start_span( @original_handler, From 63bf9ad19bc38c9db30068be46fa50e85a71e2d2 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Sat, 23 Mar 2024 22:24:20 -0400 Subject: [PATCH 26/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index b8652b263..e424b807d 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -53,7 +53,7 @@ def call_wrapped(event:, context:) ensure if original_handler_error span&.record_exception(original_handler_error) - span&.status = OpenTelemetry::Trace::Status.error("Original lambda handler exception: #{original_handler_error.class}. Please check if you have correct handler setting or code in lambda function.") + span&.status = OpenTelemetry::Trace::Status.error("Original lambda handler exception: #{original_handler_error.class}. Please check if you have the correct handler setting and code in your lambda function.") end span&.finish OpenTelemetry.tracer_provider.force_flush(timeout: @flush_timeout) From 52d9bdab67629356438ea8fc8631585ce7c58f70 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 25 Mar 2024 17:27:03 -0400 Subject: [PATCH 27/42] feat: lambda - update span name calculation period. add non-http trigger and test case --- .../instrumentation/aws_lambda/handler.rb | 93 +++++++++++++------ .../opentelemetry/instrumentation_test.rb | 56 ++++++++++- .../aws_lambda/test/test_helper.rb | 51 ++++++++++ 3 files changed, 168 insertions(+), 32 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index b8652b263..a9858f621 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -26,27 +26,34 @@ def initialize # We want to capture the error if user's handler is causing issue # but our wrapper and handler shouldn't cause any issue def call_wrapped(event:, context:) - parent_context = extract_parent_context(event) - span_attributes = otel_attributes(event, context) + parent_context = extract_parent_context(event) - response = nil - original_handler_error = nil - begin - response = call_original_handler(event: event, context: context) - status_code = response.is_a?(Hash) ? (response['statusCode'] || response[:statusCode]) : nil - rescue StandardError => e - original_handler_error = e - status_code = '500' - end - - span_attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE] = status_code if status_code + span_kind = nil + span_kind = if event['Records'] && ['aws:sqs', 'aws:s3', 'aws:sns', 'aws:dynamodb'].include?(event['Records'].dig(0,'eventSource')) + :consumer + else + :server + end + original_handler_error = nil + original_response = nil OpenTelemetry::Context.with_current(parent_context) do + span_attributes = otel_attributes(event, context) span = tracer.start_span( @original_handler, attributes: span_attributes, - kind: :server # Span kind MUST be `:server` for a HTTP server span + kind: span_kind ) + + begin + response = call_original_handler(event: event, context: context) + status_code = response['statusCode'] || response[:statusCode] if response.is_a?(Hash) + span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, status_code) if status_code + rescue StandardError => e + original_handler_error = e + ensure + original_response = response + end rescue StandardError => e span&.record_exception(e) span&.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}") @@ -61,7 +68,7 @@ def call_wrapped(event:, context:) raise original_handler_error if original_handler_error - response + original_response end def instrumentation_config @@ -130,42 +137,68 @@ def v1_proxy_attributes(event) attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME] = headers['X-Forwarded-Proto'] attributes[OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME] = headers['Host'] end - attributes end def v2_proxy_attributes(event) - attributes = {} request_context = event['requestContext'] - if request_context - attributes.merge!({ - OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME => request_context['domainName'], - OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_context['http']['method'], - OpenTelemetry::SemanticConventions::Trace::HTTP_USER_AGENT => request_context['http']['userAgent'], - OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE => request_context['http']['path'], - OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => request_context['http']['path'] - }) - attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] += "?#{event['rawQueryString']}" if event['rawQueryString'] - end - + attributes = { + OpenTelemetry::SemanticConventions::Trace::NET_HOST_NAME => request_context['domainName'], + OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_context['http']['method'], + OpenTelemetry::SemanticConventions::Trace::HTTP_USER_AGENT => request_context['http']['userAgent'], + OpenTelemetry::SemanticConventions::Trace::HTTP_ROUTE => request_context['http']['path'], + OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => request_context['http']['path'] + } + attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] += "?#{event['rawQueryString']}" if event['rawQueryString'] attributes end # fass.trigger set to http: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#api-gateway # TODO: need to update Semantic Conventions for invocation_id, trigger and resource_id def otel_attributes(event, context) - span_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) + span_attributes = {} span_attributes['faas.invocation_id'] = context.aws_request_id - span_attributes['faas.trigger'] = 'http' span_attributes['cloud.resource_id'] = "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" span_attributes[OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN] = context.invoked_function_arn span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = event['requestContext']['accountId'] if event['requestContext'] + # from python, need to find out which one is correct + account_id = context.invoked_function_arn.split(':')[4] + span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = account_id + span_attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_EXECUTION] = context.aws_request_id + span_attributes[OpenTelemetry::SemanticConventions::Resource::FAAS_ID] = context.invoked_function_arn + + if event['requestContext'] + request_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) + request_attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_TRIGGER] = 'http' + span_attributes.merge!(request_attributes) + end + + if event['Records'] + trigger_attributes = trigger_type_attributes(event) + span_attributes.merge!(trigger_attributes) + end + span_attributes rescue StandardError => e OpenTelemetry.logger.error("aws-lambda instrumentation exception occurred while preparing span attributes: #{e.message}") {} end + + # sqs spec for lambda: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#sqs + def trigger_type_attributes(event) + attributes = {} + case event['Records'].dig(0,'eventSource') + when 'aws:sqs' + attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_TRIGGER] = 'pubsub' + attributes[OpenTelemetry::SemanticConventions::Trace::MESSAGING_OPERATION] = 'process' + attributes[OpenTelemetry::SemanticConventions::Trace::MESSAGING_SYSTEM] = 'AmazonSQS' + when 'aws:sns' + when 'aws:s3' + when 'aws:dynamodb' + end + attributes + end end end end diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index c0cc5f59a..f37d7c4e6 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -11,6 +11,8 @@ let(:exporter) { EXPORTER } let(:event_v1) { EVENT_V1 } let(:event_v2) { EVENT_V2 } + let(:event_record) { EVENT_RECORD } + let(:sqs_record) { SQS_RECORD } let(:context) { CONTEXT } let(:last_span) { exporter.finished_spans.last } @@ -59,6 +61,7 @@ _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' _(last_span.attributes['faas.trigger']).must_equal 'http' _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.account.id']).must_equal 'id' _(last_span.attributes['http.method']).must_equal 'GET' _(last_span.attributes['http.route']).must_equal '/' _(last_span.attributes['http.target']).must_equal '/' @@ -111,6 +114,7 @@ _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' _(last_span.attributes['faas.trigger']).must_equal 'http' + _(last_span.attributes['cloud.account.id']).must_equal 'id' _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' _(last_span.attributes['net.host.name']).must_equal 'id.execute-api.us-east-1.amazonaws.com' _(last_span.attributes['http.method']).must_equal 'POST' @@ -119,6 +123,56 @@ _(last_span.attributes['http.target']).must_equal '/path/to/resource?parameter1=value1¶meter1=value2¶meter2=value' end end + + it 'validate_spans_with_records_from_non_gateway_request' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, {}) do + otel_wrapper.call_wrapped(event: event_record, context: context) + + _(last_span.name).must_equal 'sample.test' + _(last_span.kind).must_equal :consumer + _(last_span.status.code).must_equal 1 + _(last_span.hex_parent_span_id).must_equal '0000000000000000' + + _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' + _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.account.id']).must_equal 'id' + + assert_nil(last_span.attributes['faas.trigger']) + assert_nil(last_span.attributes['http.method']) + assert_nil(last_span.attributes['http.user_agent']) + assert_nil(last_span.attributes['http.route']) + assert_nil(last_span.attributes['http.target']) + assert_nil(last_span.attributes['net.host.name']) + end + end + + it 'validate_spans_with_records_from_sqs' do + otel_wrapper = OpenTelemetry::Instrumentation::AwsLambda::Handler.new + otel_wrapper.stub(:call_original_handler, {}) do + otel_wrapper.call_wrapped(event: sqs_record, context: context) + + _(last_span.name).must_equal 'sample.test' + _(last_span.kind).must_equal :consumer + _(last_span.status.code).must_equal 1 + _(last_span.hex_parent_span_id).must_equal '0000000000000000' + + _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' + _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.account.id']).must_equal 'id' + _(last_span.attributes['faas.trigger']).must_equal 'pubsub' + _(last_span.attributes['messaging.operation']).must_equal 'process' + _(last_span.attributes['messaging.system']).must_equal 'AmazonSQS' + + assert_nil(last_span.attributes['http.method']) + assert_nil(last_span.attributes['http.user_agent']) + assert_nil(last_span.attributes['http.route']) + assert_nil(last_span.attributes['http.target']) + assert_nil(last_span.attributes['net.host.name']) + end + end end describe 'validate_error_handling' do @@ -142,8 +196,6 @@ _(last_span.hex_trace_id.size).must_equal 32 _(last_span.trace_flags.sampled?).must_equal true _(last_span.tracestate.to_h.to_s).must_equal '{}' - - _(last_span.attributes['http.status_code']).must_equal '500' end end diff --git a/instrumentation/aws_lambda/test/test_helper.rb b/instrumentation/aws_lambda/test/test_helper.rb index ccb596c2e..cf3cde320 100644 --- a/instrumentation/aws_lambda/test/test_helper.rb +++ b/instrumentation/aws_lambda/test/test_helper.rb @@ -96,6 +96,57 @@ def initialize(aws_request_id:, invoked_function_arn:, function_name:) 'stageVariables' => { 'stageVariable1' => 'value1', 'stageVariable2' => 'value2' } }.freeze +EVENT_RECORD = { + 'Records' => + [ + { 'eventVersion' => '2.0', + 'eventSource' => 'aws:s3', + 'awsRegion' => 'us-east-1', + 'eventTime' => '1970-01-01T00:00:00.000Z', + 'eventName' => 'ObjectCreated:Put', + 'userIdentity' => { 'principalId' => 'EXAMPLE' }, + 'requestParameters' => { 'sourceIPAddress' => '127.0.0.1' }, + 'responseElements' => { + 'x-amz-request-id' => 'EXAMPLE123456789', + 'x-amz-id-2' => 'EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH' + }, + 's3' => { + 's3SchemaVersion' => '1.0', + 'configurationId' => 'testConfigRule', + 'bucket' => { + 'name' => 'mybucket', + 'ownerIdentity' => { + 'principalId' => 'EXAMPLE' + }, + 'arn' => 'arn:aws:s3:::mybucket' + }, + 'object' => { + 'key' => 'test/key', + 'size' => 1024, + 'eTag' => '0123456789abcdef0123456789abcdef', + 'sequencer' => '0A1B2C3D4E5F678901' + } + } } + ] +}.freeze + +SQS_RECORD = { + 'Records' => + [{ 'messageId' => '19dd0b57-b21e-4ac1-bd88-01bbb068cb78', + 'receiptHandle' => 'MessageReceiptHandle', + 'body' => 'Hello from SQS!', + 'attributes' => + { 'ApproximateReceiveCount' => '1', + 'SentTimestamp' => '1523232000000', + 'SenderId' => '123456789012', + 'ApproximateFirstReceiveTimestamp' => '1523232000001' }, + 'messageAttributes' => {}, + 'md5OfBody' => '7b270e59b47ff90a553787216d55d91d', + 'eventSource' => 'aws:sqs', + 'eventSourceARN' => 'arn:aws:sqs:us-east-1:123456789012:MyQueue', + 'awsRegion' => 'us-east-1' }] +}.freeze + CONTEXT = MockLambdaContext.new(aws_request_id: '41784178-4178-4178-4178-4178417855e', invoked_function_arn: 'arn:aws:lambda:location:id:function_name:function_name', function_name: 'funcion') From 8f187c9d82edbce4fe6239cd53aa154d28792419 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 25 Mar 2024 17:30:23 -0400 Subject: [PATCH 28/42] feat: aws_lambda update --- .../opentelemetry/instrumentation/aws_lambda/handler.rb | 8 +++----- .../aws_lambda/test/opentelemetry/instrumentation_test.rb | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 9285c31a6..8d0bce31d 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -29,7 +29,7 @@ def call_wrapped(event:, context:) parent_context = extract_parent_context(event) span_kind = nil - span_kind = if event['Records'] && ['aws:sqs', 'aws:s3', 'aws:sns', 'aws:dynamodb'].include?(event['Records'].dig(0,'eventSource')) + span_kind = if event['Records'] && ['aws:sqs', 'aws:s3', 'aws:sns', 'aws:dynamodb'].include?(event['Records'].dig(0, 'eventSource')) :consumer else :server @@ -186,16 +186,14 @@ def otel_attributes(event, context) end # sqs spec for lambda: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/faas/aws-lambda.md#sqs + # current there is no spec for 'aws:sns', 'aws:s3' and 'aws:dynamodb' def trigger_type_attributes(event) attributes = {} - case event['Records'].dig(0,'eventSource') + case event['Records'].dig(0, 'eventSource') when 'aws:sqs' attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_TRIGGER] = 'pubsub' attributes[OpenTelemetry::SemanticConventions::Trace::MESSAGING_OPERATION] = 'process' attributes[OpenTelemetry::SemanticConventions::Trace::MESSAGING_SYSTEM] = 'AmazonSQS' - when 'aws:sns' - when 'aws:s3' - when 'aws:dynamodb' end attributes end diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index f37d7c4e6..33974a7c3 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -185,7 +185,7 @@ _(last_span.kind).must_equal :server _(last_span.status.code).must_equal 2 - _(last_span.status.description).must_equal 'Original lambda handler exception: StandardError. Please check if you have correct handler setting or code in lambda function.' + _(last_span.status.description).must_equal 'Original lambda handler exception: StandardError. Please check if you have the correct handler setting and code in your lambda function.' _(last_span.hex_parent_span_id).must_equal '0000000000000000' _(last_span.events[0].name).must_equal 'exception' From 8608e436cb043e7031defd614208629673062d77 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 2 Apr 2024 11:09:35 -0400 Subject: [PATCH 29/42] feat: aws lambda - update attributes --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 8d0bce31d..12d65a325 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -160,9 +160,7 @@ def otel_attributes(event, context) span_attributes['faas.invocation_id'] = context.aws_request_id span_attributes['cloud.resource_id'] = "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" span_attributes[OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN] = context.invoked_function_arn - span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = event['requestContext']['accountId'] if event['requestContext'] - # from python, need to find out which one is correct account_id = context.invoked_function_arn.split(':')[4] span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = account_id span_attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_EXECUTION] = context.aws_request_id From 3896d9bdbfa11925816a94078aa78be8d9fa5795 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Fri, 5 Apr 2024 11:59:06 -0400 Subject: [PATCH 30/42] feat: aws lambda - revision --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 4 +++- .../instrumentation/aws_lambda/instrumentation.rb | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 12d65a325..2a72674bc 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -7,6 +7,8 @@ module OpenTelemetry module Instrumentation module AwsLambda + AWS_TRIGGERS = ['aws:sqs', 'aws:s3', 'aws:sns', 'aws:dynamodb'].freeze + # Handler class that creates a span around the _HANDLER class Handler attr_reader :handler_method, :handler_class @@ -29,7 +31,7 @@ def call_wrapped(event:, context:) parent_context = extract_parent_context(event) span_kind = nil - span_kind = if event['Records'] && ['aws:sqs', 'aws:s3', 'aws:sns', 'aws:dynamodb'].include?(event['Records'].dig(0, 'eventSource')) + span_kind = if event['Records'] && AWS_TRIGGERS.include?(event['Records'].dig(0, 'eventSource')) :consumer else :server diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb index 3f99c29f1..62f25aee5 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/instrumentation.rb @@ -18,10 +18,6 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base (ENV.key?('_HANDLER') || ENV.key?('ORIG_HANDLER')) end - compatible do - true - end - private def require_dependencies From 078618f821fbe2a0acc34cfc097c39458751f950 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 9 Apr 2024 11:29:31 -0400 Subject: [PATCH 31/42] Update instrumentation/aws_lambda/README.md Co-authored-by: Lin Lin --- instrumentation/aws_lambda/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index ccc5c9986..720dbef1d 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -1,6 +1,6 @@ # OpenTelemetry AWS-Lambda Instrumentation -The OpenTelemetry `aws-lambda` gem is a community maintained instrumentation for [aws-sdk-lambda][aws-sdk-lambda]. +The OpenTelemetry `aws-lambda` gem is a community maintained instrumentation for [AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/ruby-handler.html). ## How do I get started? From 78a7040e29e052d57af770a1582eaf93e95e1903 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 9 Apr 2024 11:29:41 -0400 Subject: [PATCH 32/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Lin Lin --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 2a72674bc..abc5a3d84 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -25,8 +25,8 @@ def initialize resolve_original_handler end - # We want to capture the error if user's handler is causing issue - # but our wrapper and handler shouldn't cause any issue + # Try to record and re-raise any exception from the wrapped function handler + # Instrumentation should never raise its own exception def call_wrapped(event:, context:) parent_context = extract_parent_context(event) From ebcf3128d1878c810052ec275ab475f358692e67 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 9 Apr 2024 11:29:51 -0400 Subject: [PATCH 33/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Lin Lin --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index abc5a3d84..060ee0501 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -165,8 +165,6 @@ def otel_attributes(event, context) account_id = context.invoked_function_arn.split(':')[4] span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = account_id - span_attributes[OpenTelemetry::SemanticConventions::Trace::FAAS_EXECUTION] = context.aws_request_id - span_attributes[OpenTelemetry::SemanticConventions::Resource::FAAS_ID] = context.invoked_function_arn if event['requestContext'] request_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) From 5c873c99b8bd2d33cb9b25a726b37a961a688899 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 9 Apr 2024 11:53:21 -0400 Subject: [PATCH 34/42] feat: aws lambda - revision --- .../instrumentation/aws_lambda/handler.rb | 11 ++++------- .../test/opentelemetry/instrumentation_test.rb | 10 +++++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 060ee0501..3d6372eda 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -57,12 +57,11 @@ def call_wrapped(event:, context:) original_response = response end rescue StandardError => e - span&.record_exception(e) - span&.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}") + OpenTelemetry.logger.error("aws-lambda instrumentation #{e.class}: #{e.message}") ensure if original_handler_error span&.record_exception(original_handler_error) - span&.status = OpenTelemetry::Trace::Status.error("Original lambda handler exception: #{original_handler_error.class}. Please check if you have the correct handler setting and code in your lambda function.") + span&.status = OpenTelemetry::Trace::Status.error(original_handler_error.message) end span&.finish OpenTelemetry.tracer_provider.force_flush(timeout: @flush_timeout) @@ -160,11 +159,9 @@ def v2_proxy_attributes(event) def otel_attributes(event, context) span_attributes = {} span_attributes['faas.invocation_id'] = context.aws_request_id - span_attributes['cloud.resource_id'] = "#{context.invoked_function_arn};#{context.aws_request_id};#{context.function_name}" + span_attributes['cloud.resource_id'] = context.invoked_function_arn span_attributes[OpenTelemetry::SemanticConventions::Trace::AWS_LAMBDA_INVOKED_ARN] = context.invoked_function_arn - - account_id = context.invoked_function_arn.split(':')[4] - span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = account_id + span_attributes[OpenTelemetry::SemanticConventions::Resource::CLOUD_ACCOUNT_ID] = context.invoked_function_arn.split(':')[4] if event['requestContext'] request_attributes = event['version'] == '2.0' ? v2_proxy_attributes(event) : v1_proxy_attributes(event) diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index 33974a7c3..e737544f6 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -60,7 +60,7 @@ _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' _(last_span.attributes['faas.trigger']).must_equal 'http' - _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['cloud.account.id']).must_equal 'id' _(last_span.attributes['http.method']).must_equal 'GET' _(last_span.attributes['http.route']).must_equal '/' @@ -115,7 +115,7 @@ _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' _(last_span.attributes['faas.trigger']).must_equal 'http' _(last_span.attributes['cloud.account.id']).must_equal 'id' - _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['net.host.name']).must_equal 'id.execute-api.us-east-1.amazonaws.com' _(last_span.attributes['http.method']).must_equal 'POST' _(last_span.attributes['http.user_agent']).must_equal 'agent' @@ -136,7 +136,7 @@ _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' - _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['cloud.account.id']).must_equal 'id' assert_nil(last_span.attributes['faas.trigger']) @@ -160,7 +160,7 @@ _(last_span.attributes['aws.lambda.invoked_arn']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['faas.invocation_id']).must_equal '41784178-4178-4178-4178-4178417855e' - _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name;41784178-4178-4178-4178-4178417855e;funcion' + _(last_span.attributes['cloud.resource_id']).must_equal 'arn:aws:lambda:location:id:function_name:function_name' _(last_span.attributes['cloud.account.id']).must_equal 'id' _(last_span.attributes['faas.trigger']).must_equal 'pubsub' _(last_span.attributes['messaging.operation']).must_equal 'process' @@ -185,7 +185,7 @@ _(last_span.kind).must_equal :server _(last_span.status.code).must_equal 2 - _(last_span.status.description).must_equal 'Original lambda handler exception: StandardError. Please check if you have the correct handler setting and code in your lambda function.' + _(last_span.status.description).must_equal 'Simulated Error' _(last_span.hex_parent_span_id).must_equal '0000000000000000' _(last_span.events[0].name).must_equal 'exception' From dcdbc655a06efd164ee16b4952756b12600c1234 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Tue, 16 Apr 2024 11:21:07 -0400 Subject: [PATCH 35/42] Update instrumentation/aws_lambda/example/sample.rb Co-authored-by: Ariel Valentin --- instrumentation/aws_lambda/example/sample.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/example/sample.rb b/instrumentation/aws_lambda/example/sample.rb index aab8a72dd..7efc9561a 100644 --- a/instrumentation/aws_lambda/example/sample.rb +++ b/instrumentation/aws_lambda/example/sample.rb @@ -6,4 +6,4 @@ def handler(event:, context:) puts "Success" -end \ No newline at end of file +end From 80ee8715037b62c447861aaf3fb0d7cff9ea8b2a Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 2 May 2024 12:07:26 -0400 Subject: [PATCH 36/42] Update instrumentation/aws_lambda/README.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index 720dbef1d..15786ed61 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -1,6 +1,6 @@ # OpenTelemetry AWS-Lambda Instrumentation -The OpenTelemetry `aws-lambda` gem is a community maintained instrumentation for [AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/ruby-handler.html). +The OpenTelemetry `aws-lambda` gem is a community-maintained instrumentation for [AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/ruby-handler.html). ## How do I get started? From 0aec40e1f8e47ab44effc910ad8ee2f6c7ec5a19 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 2 May 2024 12:10:34 -0400 Subject: [PATCH 37/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index 3d6372eda..f4350c1ac 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -13,7 +13,7 @@ module AwsLambda class Handler attr_reader :handler_method, :handler_class - # anytime when update the code in a Lambda function or change the functional configuration, + # anytime when the code in a Lambda function is updated or the functional configuration is changed, # the next invocation results in a cold start; therefore these instance variable will be up-to-date def initialize @flush_timeout = ENV.fetch('OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT', '30000').to_i From 75e0ce5620c75bfc5abb49be4e095d6cb36e1d5c Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 2 May 2024 12:11:57 -0400 Subject: [PATCH 38/42] Update instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- .../lib/opentelemetry/instrumentation/aws_lambda/handler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb index f4350c1ac..7c9a32c18 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/handler.rb @@ -14,7 +14,7 @@ class Handler attr_reader :handler_method, :handler_class # anytime when the code in a Lambda function is updated or the functional configuration is changed, - # the next invocation results in a cold start; therefore these instance variable will be up-to-date + # the next invocation results in a cold start; therefore these instance variables will be up-to-date def initialize @flush_timeout = ENV.fetch('OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT', '30000').to_i @original_handler = ENV['ORIG_HANDLER'] || ENV['_HANDLER'] || '' From 237465a989a67384d2ff403e8179d964f4887855 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 2 May 2024 12:30:11 -0400 Subject: [PATCH 39/42] Update instrumentation/aws_lambda/README.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index 15786ed61..cf90d21ac 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -15,6 +15,8 @@ Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-a ## Usage From the Lambda Layer side, create the wrapper. More information can be found at https://github.com/open-telemetry/opentelemetry-lambda/tree/main/ruby + +Below is an example of `ruby/src/layer/wrapper.rb`, where you can configure the layer to suit your needs before building it: ```ruby require 'opentelemetry/sdk' require 'opentelemetry/instrumentation/aws_lambda' From 40c6316985995473bce94257d2aff5c50307fe91 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Thu, 2 May 2024 12:30:16 -0400 Subject: [PATCH 40/42] Update instrumentation/aws_lambda/README.md Co-authored-by: Kayla Reopelle (she/her) <87386821+kaylareopelle@users.noreply.github.com> --- instrumentation/aws_lambda/README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/instrumentation/aws_lambda/README.md b/instrumentation/aws_lambda/README.md index cf90d21ac..90dc918c9 100644 --- a/instrumentation/aws_lambda/README.md +++ b/instrumentation/aws_lambda/README.md @@ -2,15 +2,11 @@ The OpenTelemetry `aws-lambda` gem is a community-maintained instrumentation for [AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/ruby-handler.html). -## How do I get started? +## How do I get started? -Install the gem using: +Installation of the `opentelemetry-instrumentation-aws_lambda` gem is handled by the [OpenTelemetry Lambda Layer for Ruby](https://github.com/open-telemetry/opentelemetry-lambda/tree/main/ruby). -``` -gem install opentelemetry-instrumentation-aws_lambda -``` - -Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-aws_lambda` in your `Gemfile`. +We do not advise installing the `opentelemetry-instrumentation-aws_lambda` gem directly into your Ruby lambda. Instead, clone the [OpenTelemetry Lambda Layer for Ruby](https://github.com/open-telemetry/opentelemetry-lambda/tree/main/ruby) and build the layer locally. Then, save it in your AWS account. ## Usage From f70a66fd76bd0e68b18fa45b1fc8ff93f91ccb28 Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Mon, 6 May 2024 11:12:09 -0400 Subject: [PATCH 41/42] feat: lambda - update release file --- .release-please-manifest.json | 1 + .toys/.data/releases.yml | 4 ++++ release-please-config.json | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6d6a159dc..b66849230 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -16,6 +16,7 @@ "instrumentation/base": "0.22.3", "instrumentation/active_record": "0.7.0", "instrumentation/aws_sdk": "0.5.0", + "instrumentation/aws_lambda": "0.1.0", "instrumentation/lmdb": "0.22.1", "instrumentation/http": "0.23.2", "instrumentation/graphql": "0.27.0", diff --git a/.toys/.data/releases.yml b/.toys/.data/releases.yml index 563b9be80..db5722c22 100644 --- a/.toys/.data/releases.yml +++ b/.toys/.data/releases.yml @@ -100,6 +100,10 @@ gems: directory: instrumentation/aws_sdk version_constant: [OpenTelemetry, Instrumentation, AwsSdk, VERSION] + - name: opentelemetry-instrumentation-aws_lambda + directory: instrumentation/aws_lambda + version_constant: [OpenTelemetry, Instrumentation, AwsLambda, VERSION] + - name: opentelemetry-instrumentation-lmdb directory: instrumentation/lmdb version_constant: [OpenTelemetry, Instrumentation, LMDB, VERSION] diff --git a/release-please-config.json b/release-please-config.json index 8686eb523..eba2f3786 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -81,6 +81,10 @@ "package-name": "opentelemetry-instrumentation-aws_sdk", "version-file": "lib/opentelemetry/instrumentation/aws_sdk/version.rb" }, + "instrumentation/aws_lambda": { + "package-name": "opentelemetry-instrumentation-aws_lambda", + "version-file": "lib/opentelemetry/instrumentation/aws_lambda/version.rb" + }, "instrumentation/lmdb": { "package-name": "opentelemetry-instrumentation-lmdb", "version-file": "lib/opentelemetry/instrumentation/lmdb/version.rb" From 26801c0e8525cc660a45672c96780006350414fc Mon Sep 17 00:00:00 2001 From: xuan-cao-swi Date: Tue, 7 May 2024 10:57:12 -0400 Subject: [PATCH 42/42] feat: remove ci-instrumentation-canary.yml --- .../workflows/ci-instrumentation-canary.yml | 141 ------------------ 1 file changed, 141 deletions(-) delete mode 100644 .github/workflows/ci-instrumentation-canary.yml diff --git a/.github/workflows/ci-instrumentation-canary.yml b/.github/workflows/ci-instrumentation-canary.yml deleted file mode 100644 index b6c26bfdf..000000000 --- a/.github/workflows/ci-instrumentation-canary.yml +++ /dev/null @@ -1,141 +0,0 @@ -name: CI Instrumentation - Canary - -on: - workflow_dispatch: - schedule: - - cron: "0 0 * * *" - -jobs: - instrumentation: - strategy: - fail-fast: false - matrix: - gem: - - action_pack - - action_view - - active_job - - active_model_serializers - - active_record - - active_support - - all - - aws_sdk - - aws_lambda - - base - - concurrent_ruby - - delayed_job - - ethon - - excon - - faraday - - grape - - graphql - - gruf - - http - - http_client - - koala - - lmdb - - net_http - - httpx - - rack - - rails - - restclient - - rspec - - sinatra - os: - - ubuntu-latest - - macos-latest - - windows-latest - exclude: - - os: windows-latest - gem: ethon - - os: windows-latest - gem: action_pack - - os: windows-latest - gem: restclient - - os: windows-latest - gem: rails - - os: macos-latest - gem: lmdb - - name: ${{ matrix.gem }} / ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - name: "Test Ruby 3.3" - uses: ./.github/actions/test_gem - with: - gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "3.3" - latest: "true" - - name: "Test Ruby 3.2" - uses: ./.github/actions/test_gem - with: - gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "3.2" - latest: "true" - - name: "Test Ruby 3.1" - uses: ./.github/actions/test_gem - with: - gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "3.1" - latest: "true" - - name: "Test Ruby 3.0" - if: "${{ matrix.os == 'ubuntu-latest' }}" - uses: ./.github/actions/test_gem - with: - gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "3.0" - latest: "true" - yard: true - rubocop: true - build: true - - name: "JRuby Filter" - id: jruby_skip - shell: bash - run: | - echo "skip=false" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "action_pack" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "action_view" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "active_model_serializers" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "active_record" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "active_support" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "aws_sdk" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "aws_lambda" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "delayed_job" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "graphql" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "http" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "http_client" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "koala" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "lmdb" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "rack" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "rails" ]] && echo "skip=true" >> $GITHUB_OUTPUT - # This is essentially a bash script getting evaluated, so we need to return true or the whole job fails. - true - - name: "Test JRuby" - if: "${{ matrix.os == 'ubuntu-latest' && steps.jruby_skip.outputs.skip == 'false' }}" - uses: ./.github/actions/test_gem - with: - gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - latest: "true" - ruby: "jruby-9.4.2.0" - - name: "Truffleruby Filter" - id: truffleruby_skip - shell: bash - run: | - echo "skip=false" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "action_pack" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "action_view" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "active_job" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "active_record" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "active_support" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "delayed_job" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "lmdb" ]] && echo "skip=true" >> $GITHUB_OUTPUT - [[ "${{ matrix.gem }}" == "rails" ]] && echo "skip=true" >> $GITHUB_OUTPUT - # This is essentially a bash script getting evaluated, so we need to return true or the whole job fails. - true - - name: "Test Truffleruby" - if: "${{ matrix.os == 'ubuntu-latest' && steps.truffleruby_skip.outputs.skip == 'false' }}" - uses: ./.github/actions/test_gem - with: - gem: "opentelemetry-instrumentation-${{ matrix.gem }}" - ruby: "truffleruby" - latest: "true"