Skip to content

Commit

Permalink
Feature/incorporate upstream changes (#1)
Browse files Browse the repository at this point in the history
* Add ECS metadata allowing cloudwatch-logs to be linked with traces (aws#93)

* First step

* Add comment

* Typo

* Copy logic of EC2 plugin for ECS

* Typo

* Back to symbols

* Copy paste all EC2 tests as starting point for ECS

* Comments

* Somewhat working ?

* Backword compatible with prevous feature when not 1.4

* Add hint for fargate 1.4 in case of errors

---------

Co-authored-by: Etienne Chabert <[email protected]>

* release 0.15.0 (aws#94)

* Update version for 0.15.0 release (aws#95)

* Update continuous-build.yml (aws#97)

the latest macos-14 supports arm only. 
This PR using the previous version of macos image to unblock the release.

* Fix issue: Wrong duration for DB transaction event  on ROR 7.1 aws#92 (aws#96)

* Fix issue: Wrong duration for DB transaction event  on ROR 7.1 aws#92

* Added unit tests and restructured the code

* Fix unit tests

* Update continuous-build.yml (aws#97)

the latest macos-14 supports arm only. 
This PR using the previous version of macos image to unblock the release.

* Worked on the jj22ee's comment and added logic that convert in seconds only for rails 7.1 versions.

* Conditionally handle for ruby 7.1

---------

Co-authored-by: Lei Wang <[email protected]>

* Release 0.16.0 (aws#98)

---------

Co-authored-by: Chabert Etienne <[email protected]>
Co-authored-by: Etienne Chabert <[email protected]>
Co-authored-by: Prashant Srivastava <[email protected]>
Co-authored-by: Lei Wang <[email protected]>
Co-authored-by: Osama Bin Junaid <[email protected]>
Co-authored-by: Min Xia <[email protected]>
  • Loading branch information
7 people authored Oct 15, 2024
1 parent 0514aff commit c90fd1a
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/continuous-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
os:
- macos-latest
- macos-13
- ubuntu-latest
ruby:
- 2.4
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
0.16.0 (2024-09-05)
-------------------
* Update - Fix issue: Wrong duration for DB transaction event on ROR 7.1 [PR #96](https://github.com/aws/aws-xray-sdk-ruby/pull/96)

0.15.0 (2023-10-18)
-------------------
* Update - Add ECS metadata allowing cloudwatch-logs to be linked with traces [PR #93](https://github.com/aws/aws-xray-sdk-ruby/pull/93)

0.14.0 (2023-04-05)
-------------------
* Added - Allow list TopicArn for SNS PublishBatch request [PR #82](https://github.com/aws/aws-xray-sdk-ruby/pull/82).
Expand Down
6 changes: 4 additions & 2 deletions lib/aws-xray-sdk/facets/rails/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ def record(transaction)
subsegment = XRay.recorder.begin_subsegment name, namespace: 'remote'
# subsegment is nil in case of context missing
return if subsegment.nil?
subsegment.start_time = transaction.time.to_f / 1000.0
# Rails 7.1 introduced time measurement in milliseconds instead seconds of causing xray-sdk to report wrong duration for transaction calls.
# This is being handled in rails 7.2 and later. https://github.com/rails/rails/pull/50779
subsegment.start_time = (::Rails::VERSION::MAJOR == 7 and ::Rails::VERSION::MINOR == 1) ? transaction.time.to_f/1000 : transaction.time.to_f
subsegment.sql = sql
XRay.recorder.end_subsegment end_time: transaction.end.to_f / 1000.0
XRay.recorder.end_subsegment end_time: (::Rails::VERSION::MAJOR == 7 and ::Rails::VERSION::MINOR == 1) ? transaction.end.to_f/1000 : transaction.end.to_f
end

private
Expand Down
73 changes: 68 additions & 5 deletions lib/aws-xray-sdk/plugins/ecs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,82 @@

module XRay
module Plugins
# Due to lack of ECS container metadata service, the only host information
# available is the host name.
module ECS
include Logging

ORIGIN = 'AWS::ECS::Container'.freeze

# Only compatible with v4!
# The v3 metadata url does not contain cloudwatch informations
METADATA_ENV_KEY = 'ECS_CONTAINER_METADATA_URI_V4'

def self.aws
@@aws ||= begin
{ ecs: { container: Socket.gethostname } }
metadata = get_metadata()

begin
metadata[:ecs][:container] = Socket.gethostname
rescue StandardError => e
@@aws = {}
Logging.logger.warn %(cannot get the ecs container hostname due to: #{e.message}.)
metadata[:ecs][:container] = nil
end

@@aws = {
ecs: metadata[:ecs],
cloudwatch_logs: metadata[:cloudwatch_logs]
}
end

private

def self.get_metadata()
begin
metadata_uri = URI(ENV[METADATA_ENV_KEY])
req = Net::HTTP::Get.new(metadata_uri)
metadata_json = do_request(req)
return parse_metadata(metadata_json)
rescue StandardError => e
Logging.logger.warn %(cannot get the ecs instance metadata due to: #{e.message}. Make sure you are using Fargate platform version >=1.4.0)
{ ecs: {}, cloudwatch_logs: {} }
end
end

def self.parse_metadata(json_str)
data = JSON(json_str)

metadata = {
ecs: {
container_arn: data['ContainerARN'],
},
cloudwatch_logs: {
log_group: data["LogOptions"]['awslogs-group'],
log_region: data["LogOptions"]['awslogs-region'],
arn: data['ContainerARN']
}
}
metadata
end

def self.do_request(request)
begin
response = Net::HTTP.start(request.uri.hostname, read_timeout: 1) { |http|
http.request(request)
}

if response.code == '200'
return response.body
else
raise(StandardError.new('Unsuccessful response::' + response.code + '::' + response.message))
end
rescue StandardError => e
# Two attempts in total to complete the request successfully
@retries ||= 0
if @retries < 1
@retries += 1
retry
else
Logging.logger.warn %(Failed to complete request due to: #{e.message}.)
raise e
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/aws-xray-sdk/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module XRay
VERSION = '0.14.0'
VERSION = '0.16.0'
end
51 changes: 51 additions & 0 deletions test/aws-xray-sdk/tc_plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def test_get_runtime_context
WebMock.reset!
end

# EC2 Plugin
def test_ec2_metadata_v2_successful
dummy_json = '{\"availabilityZone\" : \"us-east-2a\", \"imageId\" : \"ami-03cca83dd001d4666\",
\"instanceId\" : \"i-07a181803de94c666\", \"instanceType\" : \"t3.xlarge\"}'
Expand All @@ -43,6 +44,7 @@ def test_ec2_metadata_v2_successful
ami_id: 'ami-03cca83dd001d4666'
}
}
# We should probably use `assert_equal` here ? Always true otherwise...
assert expected, XRay::Plugins::EC2.aws
WebMock.reset!
end
Expand Down Expand Up @@ -80,4 +82,53 @@ def test_ec2_metadata_fail
assert expected, XRay::Plugins::EC2.aws
WebMock.reset!
end

# ECS Plugin
def test_ecs_metadata_successful
dummy_metadata_uri = 'http://169.254.170.2/v4/a_random_id'
dummy_json = {
"ContainerARN"=>"arn:aws:ecs:eu-central-1:an_id:container/a_cluster/a_cluster_id/a_task_id",
"LogOptions"=>{"awslogs-group"=>"/ecs/a_service_name", "awslogs-region"=>"eu-central-1", "awslogs-stream"=>"ecs/a_service_name/a_task_id"},
}

ENV[XRay::Plugins::ECS::METADATA_ENV_KEY] = dummy_metadata_uri
stub_request(:get, dummy_metadata_uri)
.to_return(status: 200, body: dummy_json.to_json, headers: {})

expected = {
ecs: {
container: Socket.gethostname,
container_arn: 'arn:aws:ecs:eu-central-1:an_id:container/a_cluster/a_cluster_id/a_task_id',
},
cloudwatch_logs: {:log_group=>"/ecs/a_service_name", :log_region=>"eu-central-1", :arn=>"arn:aws:ecs:eu-central-1:an_id:container/a_cluster/a_cluster_id/a_task_id"}
}
assert_equal expected, XRay::Plugins::ECS.aws
WebMock.reset!
ENV.delete(XRay::Plugins::ECS::METADATA_ENV_KEY)
end

def test_ecs_metadata_fail
dummy_metadata_uri = 'http://169.254.170.2/v4/a_random_id'
ENV['ECS_CONTAINER_METADATA_URI_V4'] = dummy_metadata_uri

stub_request(:get, dummy_metadata_uri)
.to_raise(StandardError)

expected = {
ecs: {container: Socket.gethostname},
cloudwatch_logs: {}
}
assert_equal expected, XRay::Plugins::ECS.aws
WebMock.reset!
ENV.delete(XRay::Plugins::ECS::METADATA_ENV_KEY)
end

def test_ecs_metadata_not_defined
expected = {
ecs: {container: Socket.gethostname},
cloudwatch_logs: {}
}
assert_equal expected, XRay::Plugins::ECS.aws
WebMock.reset!
end
end

0 comments on commit c90fd1a

Please sign in to comment.