From 82e03978b89938219958032efb1448cc76baa181 Mon Sep 17 00:00:00 2001 From: Saumit Date: Sat, 27 Sep 2025 02:14:26 +0530 Subject: Initial snapshot - OpenTelemetry demo 2.1.3 -f --- src/email/.dockerignore | 1 + src/email/.ruby-version | 1 + src/email/Dockerfile | 28 ++++ src/email/Gemfile | 18 +++ src/email/Gemfile.lock | 304 +++++++++++++++++++++++++++++++++++++++ src/email/README.md | 23 +++ src/email/email_server.rb | 83 +++++++++++ src/email/views/confirmation.erb | 53 +++++++ 8 files changed, 511 insertions(+) create mode 100644 src/email/.dockerignore create mode 100644 src/email/.ruby-version create mode 100644 src/email/Dockerfile create mode 100644 src/email/Gemfile create mode 100644 src/email/Gemfile.lock create mode 100644 src/email/README.md create mode 100644 src/email/email_server.rb create mode 100644 src/email/views/confirmation.erb (limited to 'src/email') diff --git a/src/email/.dockerignore b/src/email/.dockerignore new file mode 100644 index 0000000..b43bf86 --- /dev/null +++ b/src/email/.dockerignore @@ -0,0 +1 @@ +README.md diff --git a/src/email/.ruby-version b/src/email/.ruby-version new file mode 100644 index 0000000..f989260 --- /dev/null +++ b/src/email/.ruby-version @@ -0,0 +1 @@ +3.4.4 diff --git a/src/email/Dockerfile b/src/email/Dockerfile new file mode 100644 index 0000000..c2aa6d3 --- /dev/null +++ b/src/email/Dockerfile @@ -0,0 +1,28 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + + +FROM docker.io/library/ruby:3.4.4-alpine3.22 AS builder + +COPY ./src/email/Gemfile Gemfile +COPY ./src/email/Gemfile.lock Gemfile.lock + +RUN apk update && \ + apk add make gcc musl-dev gcompat && \ + bundle install + +FROM docker.io/library/ruby:3.4.4-alpine3.22 + +COPY --from=builder /usr/local/bundle/ /usr/local/bundle/ + +WORKDIR /email_server + +COPY ./src/email/views/ views/ + +COPY ./src/email/.ruby-version .ruby-version +COPY ./src/email/Gemfile Gemfile +COPY ./src/email/Gemfile.lock Gemfile.lock +COPY ./src/email/email_server.rb email_server.rb + +EXPOSE ${EMAIL_PORT} +ENTRYPOINT ["bundle", "exec", "ruby", "email_server.rb"] diff --git a/src/email/Gemfile b/src/email/Gemfile new file mode 100644 index 0000000..7d2890a --- /dev/null +++ b/src/email/Gemfile @@ -0,0 +1,18 @@ + + +source "https://rubygems.org" + +gem "net-smtp", "~> 0.5.1" +gem "pony", "~> 1.13" +gem "puma", "~> 7.0" +gem "sinatra", "~> 4.1" +gem "rackup", "~> 2.2" + +gem "google-protobuf", "~> 4.32.0" + +gem "opentelemetry-sdk", "~> 1.8" +gem "opentelemetry-exporter-otlp", "~> 0.30.0" +gem "opentelemetry-instrumentation-all", "~> 0.80.0" + +gem "openfeature-sdk", "~> 0.4" +gem "openfeature-flagd-provider", "~> 0.1" diff --git a/src/email/Gemfile.lock b/src/email/Gemfile.lock new file mode 100644 index 0000000..53e6da2 --- /dev/null +++ b/src/email/Gemfile.lock @@ -0,0 +1,304 @@ +GEM + remote: https://rubygems.org/ + specs: + base64 (0.2.0) + bigdecimal (3.2.2) + date (3.4.1) + google-protobuf (4.32.0-aarch64-linux-musl) + bigdecimal + rake (>= 13) + google-protobuf (4.32.0-arm64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.32.0-x86_64-darwin) + bigdecimal + rake (>= 13) + google-protobuf (4.32.0-x86_64-linux-musl) + bigdecimal + rake (>= 13) + googleapis-common-protos-types (1.20.0) + google-protobuf (>= 3.18, < 5.a) + logger (1.7.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + mini_mime (1.1.5) + mustermann (3.0.3) + ruby2_keywords (~> 0.0.1) + net-imap (0.5.8) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.4) + opentelemetry-api (1.6.0) + opentelemetry-common (0.22.0) + opentelemetry-api (~> 1.0) + opentelemetry-exporter-otlp (0.30.0) + google-protobuf (>= 3.18) + googleapis-common-protos-types (~> 1.3) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-sdk (~> 1.2) + opentelemetry-semantic_conventions + opentelemetry-helpers-mysql (0.2.0) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.21) + opentelemetry-helpers-sql (0.1.1) + opentelemetry-api (~> 1.0) + opentelemetry-helpers-sql-obfuscation (0.3.0) + opentelemetry-common (~> 0.21) + opentelemetry-instrumentation-action_mailer (0.4.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (~> 0.7) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-action_pack (0.13.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-rack (~> 0.21) + opentelemetry-instrumentation-action_view (0.9.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (~> 0.7) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-active_job (0.8.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-active_model_serializers (0.22.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (>= 0.7.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-active_record (0.9.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-active_storage (0.1.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-active_support (~> 0.7) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-active_support (0.8.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-all (0.80.0) + opentelemetry-instrumentation-active_model_serializers (~> 0.22.0) + opentelemetry-instrumentation-aws_lambda (~> 0.3.0) + opentelemetry-instrumentation-aws_sdk (~> 0.8.0) + opentelemetry-instrumentation-bunny (~> 0.22.0) + opentelemetry-instrumentation-concurrent_ruby (~> 0.22.0) + opentelemetry-instrumentation-dalli (~> 0.27.0) + opentelemetry-instrumentation-delayed_job (~> 0.23.0) + opentelemetry-instrumentation-ethon (~> 0.23.0) + opentelemetry-instrumentation-excon (~> 0.24.0) + opentelemetry-instrumentation-faraday (~> 0.28.0) + opentelemetry-instrumentation-grape (~> 0.3.0) + opentelemetry-instrumentation-graphql (~> 0.29.0) + opentelemetry-instrumentation-grpc (~> 0.2.0) + opentelemetry-instrumentation-gruf (~> 0.3.0) + opentelemetry-instrumentation-http (~> 0.25.0) + opentelemetry-instrumentation-http_client (~> 0.24.0) + opentelemetry-instrumentation-httpx (~> 0.3.0) + opentelemetry-instrumentation-koala (~> 0.21.0) + opentelemetry-instrumentation-lmdb (~> 0.23.0) + opentelemetry-instrumentation-mongo (~> 0.23.0) + opentelemetry-instrumentation-mysql2 (~> 0.29.0) + opentelemetry-instrumentation-net_http (~> 0.23.0) + opentelemetry-instrumentation-pg (~> 0.30.0) + opentelemetry-instrumentation-que (~> 0.9.0) + opentelemetry-instrumentation-racecar (~> 0.4.0) + opentelemetry-instrumentation-rack (~> 0.27.0) + opentelemetry-instrumentation-rails (~> 0.37.0) + opentelemetry-instrumentation-rake (~> 0.3.1) + opentelemetry-instrumentation-rdkafka (~> 0.7.0) + opentelemetry-instrumentation-redis (~> 0.26.1) + opentelemetry-instrumentation-resque (~> 0.6.0) + opentelemetry-instrumentation-restclient (~> 0.24.0) + opentelemetry-instrumentation-ruby_kafka (~> 0.22.0) + opentelemetry-instrumentation-sidekiq (~> 0.26.0) + opentelemetry-instrumentation-sinatra (~> 0.26.0) + opentelemetry-instrumentation-trilogy (~> 0.61.0) + opentelemetry-instrumentation-aws_lambda (0.3.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-aws_sdk (0.8.2) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-base (0.23.0) + opentelemetry-api (~> 1.0) + opentelemetry-common (~> 0.21) + opentelemetry-registry (~> 0.1) + opentelemetry-instrumentation-bunny (0.22.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-concurrent_ruby (0.22.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-dalli (0.27.3) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-delayed_job (0.23.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-ethon (0.23.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-excon (0.24.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-faraday (0.28.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-grape (0.3.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-rack (~> 0.21) + opentelemetry-instrumentation-graphql (0.29.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-grpc (0.2.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-gruf (0.3.0) + opentelemetry-api (>= 1.0.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-http (0.25.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-http_client (0.24.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-httpx (0.3.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-koala (0.21.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-lmdb (0.23.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-mongo (0.23.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-mysql2 (0.29.1) + opentelemetry-api (~> 1.0) + opentelemetry-helpers-mysql + opentelemetry-helpers-sql + opentelemetry-helpers-sql-obfuscation + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-net_http (0.23.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-pg (0.30.1) + opentelemetry-api (~> 1.0) + opentelemetry-helpers-sql + opentelemetry-helpers-sql-obfuscation + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-que (0.9.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-racecar (0.4.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-rack (0.27.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-rails (0.37.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-action_mailer (~> 0.4.0) + opentelemetry-instrumentation-action_pack (~> 0.13.0) + opentelemetry-instrumentation-action_view (~> 0.9.0) + opentelemetry-instrumentation-active_job (~> 0.8.0) + opentelemetry-instrumentation-active_record (~> 0.9.0) + opentelemetry-instrumentation-active_storage (~> 0.1.0) + opentelemetry-instrumentation-active_support (~> 0.8.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-concurrent_ruby (~> 0.22.0) + opentelemetry-instrumentation-rake (0.3.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-rdkafka (0.7.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-redis (0.26.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-resque (0.6.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-restclient (0.24.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-ruby_kafka (0.22.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-sidekiq (0.26.1) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-sinatra (0.26.0) + opentelemetry-api (~> 1.0) + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-instrumentation-rack (~> 0.21) + opentelemetry-instrumentation-trilogy (0.61.1) + opentelemetry-api (~> 1.0) + opentelemetry-helpers-mysql + opentelemetry-helpers-sql + opentelemetry-helpers-sql-obfuscation + opentelemetry-instrumentation-base (~> 0.23.0) + opentelemetry-semantic_conventions (>= 1.8.0) + opentelemetry-registry (0.4.0) + opentelemetry-api (~> 1.1) + opentelemetry-sdk (1.8.1) + opentelemetry-api (~> 1.1) + opentelemetry-common (~> 0.20) + opentelemetry-registry (~> 0.2) + opentelemetry-semantic_conventions + opentelemetry-semantic_conventions (1.11.0) + opentelemetry-api (~> 1.0) + pony (1.13.1) + mail (>= 2.0) + puma (7.0.0) + nio4r (~> 2.0) + rack (3.1.15) + rack-protection (4.1.1) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rackup (2.2.1) + rack (>= 3) + rake (13.3.0) + ruby2_keywords (0.0.5) + sinatra (4.1.1) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.1.1) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + tilt (2.6.0) + timeout (0.4.3) + +PLATFORMS + aarch64-linux-musl + arm64-darwin + x86_64-darwin + x86_64-linux-musl + +DEPENDENCIES + google-protobuf (~> 4.32.0) + net-smtp (~> 0.5.1) + opentelemetry-exporter-otlp (~> 0.30.0) + opentelemetry-instrumentation-all (~> 0.80.0) + opentelemetry-sdk (~> 1.8) + pony (~> 1.13) + puma (~> 7.0) + rackup (~> 2.2) + sinatra (~> 4.1) + +BUNDLED WITH + 2.6.7 diff --git a/src/email/README.md b/src/email/README.md new file mode 100644 index 0000000..13533d8 --- /dev/null +++ b/src/email/README.md @@ -0,0 +1,23 @@ +# Email Service + +The Email service "sends" an email to the customer with their order details by +rendering it as a log message. It expects a JSON payload like: + +```json +{ + "email": "some.address@website.com", + "order": "" +} +``` + +## Local Build + +We use `bundler` to manage dependencies. To get started, simply `bundle install`. + +## Running locally + +You may run this service locally with `bundle exec ruby email_server.rb`. + +## Docker Build + +From `src/email`, run `docker build .` diff --git a/src/email/email_server.rb b/src/email/email_server.rb new file mode 100644 index 0000000..98a5259 --- /dev/null +++ b/src/email/email_server.rb @@ -0,0 +1,83 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +require "ostruct" +require "pony" +require "sinatra" +require "open_feature/sdk" +require "openfeature/flagd/provider" +# require "open_feature/flagd_provider" + +require "opentelemetry/sdk" +require "opentelemetry/exporter/otlp" +require "opentelemetry/instrumentation/sinatra" + +set :port, ENV["EMAIL_PORT"] + +# Initialize OpenFeature SDK with flagd provider +flagd_client = OpenFeature::Flagd::Provider.build_client +flagd_client.configure do |config| + config.host = ENV.fetch("FLAGD_HOST", "localhost") + config.port = ENV.fetch("FLAGD_PORT", 8013).to_i + config.tls = ENV.fetch("FLAGD_TLS", "false") == "true" +end + +OpenFeature::SDK.configure do |config| + config.set_provider(flagd_client) +end + +OpenTelemetry::SDK.configure do |c| + c.use "OpenTelemetry::Instrumentation::Sinatra" +end + +post "/send_order_confirmation" do + data = JSON.parse(request.body.read, object_class: OpenStruct) + + # get the current auto-instrumented span + current_span = OpenTelemetry::Trace.current_span + current_span.add_attributes({ + "app.order.id" => data.order.order_id, + }) + + send_email(data) + +end + +error do + OpenTelemetry::Trace.current_span.record_exception(env['sinatra.error']) +end + +def send_email(data) + # create and start a manual span + tracer = OpenTelemetry.tracer_provider.tracer('email') + tracer.in_span("send_email") do |span| + # Check if memory leak flag is enabled + client = OpenFeature::SDK.build_client + memory_leak_multiplier = client.fetch_number_value(flag_key: "emailMemoryLeak", default_value: 0) + + # To speed up the memory leak we create a long email body + confirmation_content = erb(:confirmation, locals: { order: data.order }) + whitespace_length = [0, confirmation_content.length * (memory_leak_multiplier-1)].max + + Pony.mail( + to: data.email, + from: "noreply@example.com", + subject: "Your confirmation email", + body: confirmation_content + " " * whitespace_length, + via: :test + ) + + # If not clearing the deliveries, the emails will accumulate in the test mailer + # We use this to create a memory leak. + if memory_leak_multiplier < 1 + Mail::TestMailer.deliveries.clear + end + + span.set_attribute("app.email.recipient", data.email) + puts "Order confirmation email sent to: #{data.email}" + end + # manually created spans need to be ended + # in Ruby, the method `in_span` ends it automatically + # check out the OpenTelemetry Ruby docs at: + # https://opentelemetry.io/docs/instrumentation/ruby/manual/#creating-new-spans +end diff --git a/src/email/views/confirmation.erb b/src/email/views/confirmation.erb new file mode 100644 index 0000000..aba297d --- /dev/null +++ b/src/email/views/confirmation.erb @@ -0,0 +1,53 @@ + + + + + + Your Order Confirmation + + + + +

Your Order Confirmation

+

Thanks for shopping with us!

+

Order ID

+

<%= order.order_id %>

+

Shipping

+

<%= order.shipping_tracking_id %>

+

<%= order.shipping_cost.units %>.<%= order.shipping_cost.nanos %> <%= order.shipping_cost.currency_code %>

+

<%= order.shipping_address.street_address_1 %>, <%= order.shipping_address.street_address_2 %>, <%= order.shipping_address.city %>, <%= order.shipping_address.country %> <%= order.shipping_address.zip_code %>

+

Items

+ + + + + + + <% order.items.each do |item| %> + + + + + + <% end %> +
Item No.QuantityPrice
<%= item.item.product_id %><%= item.item.quantity %><%= item.cost.units %>.<%= item.cost.nanos %> <%= item.cost.currency_code %>
+ + -- cgit v1.2.3