├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ ├── continuous-monitoring.yml │ ├── continuous_build.yml │ └── release-build.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── THIRD-PARTY ├── aws-xray-agent-benchmark ├── README.md ├── build.gradle.kts ├── results │ ├── 2.18.x │ │ └── jmh │ │ │ ├── auto-instrumentation.txt │ │ │ ├── no-instrumentation.txt │ │ │ └── sdk-instrumentation.txt │ ├── 2.7.x │ │ └── jmh │ │ │ ├── auto-instrumentation.txt │ │ │ ├── no-instrumentation.txt │ │ │ └── sdk-instrumentation.txt │ ├── 2.8.x │ │ └── jmh │ │ │ ├── auto-instrumentation.txt │ │ │ ├── no-instrumentation.txt │ │ │ └── sdk-instrumentation.txt │ └── 2.9.x │ │ └── jmh │ │ ├── auto-instrumentation.txt │ │ ├── no-instrumentation.txt │ │ └── sdk-instrumentation.txt ├── runAllBenchmarks.sh └── src │ └── jmh │ ├── java │ └── com │ │ └── amazonaws │ │ └── xray │ │ └── agent │ │ ├── benchmark │ │ ├── AwsSdkBenchmark.java │ │ ├── HttpDownstreamBenchmark.java │ │ ├── ServletBenchmark.java │ │ ├── SqlBenchmark.java │ │ └── source │ │ │ └── StatementImpl.java │ │ └── utils │ │ ├── BenchmarkUtils.java │ │ ├── ClientProvider.java │ │ └── SimpleJettyServer.java │ └── resources │ └── com │ └── amazonaws │ └── xray │ └── agent │ └── agent-config.json ├── aws-xray-agent-plugin ├── build.gradle.kts └── src │ └── test │ ├── java │ └── com │ │ └── amazonaws │ │ └── xray │ │ └── agent │ │ └── runtime │ │ └── handlers │ │ ├── downstream │ │ ├── AWSHandlerIntegTest.java │ │ ├── AWSV2HandlerIntegTest.java │ │ ├── HttpClientHandlerIntegTest.java │ │ ├── SqlHandlerIntegTest.java │ │ ├── SqlPrepareHandlerIntegTest.java │ │ └── source │ │ │ ├── http │ │ │ └── MockHttpClient.java │ │ │ └── sql │ │ │ ├── MyConnectionImpl.java │ │ │ └── MyStatementImpl.java │ │ └── upstream │ │ ├── MockHttpServletRequest.java │ │ ├── ServletHandlerIntegTest.java │ │ └── source │ │ └── SimpleHttpServlet.java │ └── resources │ └── xray-agent.json ├── aws-xray-agent ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── com │ │ └── amazonaws │ │ └── xray │ │ └── agent │ │ └── runtime │ │ ├── AgentRuntimeLoader.java │ │ ├── config │ │ ├── AgentConfiguration.java │ │ ├── InvalidAgentConfigException.java │ │ └── XRaySDKConfiguration.java │ │ ├── dispatcher │ │ └── EventDispatcher.java │ │ ├── handlers │ │ ├── XRayHandler.java │ │ ├── XRayHandlerInterface.java │ │ ├── downstream │ │ │ ├── AWSHandler.java │ │ │ ├── AWSV2Handler.java │ │ │ ├── HttpClientHandler.java │ │ │ ├── SqlHandler.java │ │ │ └── SqlPrepareHandler.java │ │ └── upstream │ │ │ └── ServletHandler.java │ │ ├── listeners │ │ ├── ListenerFactory.java │ │ ├── XRayListener.java │ │ └── XRayListenerFactory.java │ │ ├── models │ │ ├── XRayTransactionContext.java │ │ ├── XRayTransactionContextResolver.java │ │ └── XRayTransactionState.java │ │ └── package-info.java │ └── test │ ├── java │ └── com │ │ └── amazonaws │ │ └── xray │ │ └── agent │ │ └── runtime │ │ ├── AgentRuntimeLoaderTest.java │ │ ├── config │ │ ├── AgentConfigurationTest.java │ │ └── XRaySDKConfigurationTest.java │ │ ├── dispatcher │ │ └── EventDispatcherTest.java │ │ ├── handlers │ │ ├── XRayHandlerTest.java │ │ ├── downstream │ │ │ ├── AWSHandlerTest.java │ │ │ ├── HttpClientHandlerTest.java │ │ │ ├── SqlHandlerTest.java │ │ │ └── SqlPrepareHandlerTest.java │ │ └── upstream │ │ │ └── ServletHandlerTest.java │ │ └── listeners │ │ └── XRayListenerTest.java │ └── resources │ ├── com │ └── amazonaws │ │ └── xray │ │ └── agent │ │ ├── awsV1AgentConfig.json │ │ ├── awsV2AgentConfig.json │ │ ├── collectSqlConfig.json │ │ ├── emptyAgentConfig.json │ │ ├── malformedAgentConfig.json │ │ └── validAgentConfig.json │ └── xray-agent.json ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images └── xray-agent-sample.png └── settings.gradle.kts /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://help.github.com/articles/about-codeowners/ 2 | 3 | * @aws/aws-x-ray 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 7 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 30 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Limit to only `issues` or `pulls` 6 | only: issues 7 | # Issues with these labels will never be considered stale 8 | exemptLabels: 9 | - pinned 10 | - bug 11 | - enhancement 12 | - feature-request 13 | - help wanted 14 | - work-in-progress 15 | - pending release 16 | # Label to use when marking an issue as stale 17 | staleLabel: stale 18 | # Comment to post when marking an issue as stale. Set to `false` to disable 19 | markComment: > 20 | This issue has been automatically marked as stale because it has not had 21 | recent activity. It will be closed if no further activity occurs in next 7 days. Thank you 22 | for your contributions. 23 | # Comment to post when closing a stale issue. Set to `false` to disable 24 | closeComment: false 25 | -------------------------------------------------------------------------------- /.github/workflows/continuous-monitoring.yml: -------------------------------------------------------------------------------- 1 | name: Continuous monitoring of distribution channels 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '*/10 * * * *' 6 | 7 | permissions: 8 | id-token: write 9 | contents: read 10 | 11 | jobs: 12 | pull-agent: 13 | name: Pull X-Ray java agent from Maven Central and Github 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout X-Ray Java agent repository 17 | uses: actions/checkout@v2 18 | 19 | - name: Configure AWS Credentials 20 | uses: aws-actions/configure-aws-credentials@v4 21 | with: 22 | role-to-assume: ${{ secrets.AWS_INTEG_TEST_ROLE_ARN }} 23 | aws-region: us-east-1 24 | 25 | - name: Pull Java agent from Github 26 | id: distribution-availability-github 27 | run: wget https://github.com/aws/aws-xray-java-agent/releases/latest/download/xray-agent.zip 28 | 29 | - name: Publish metric on X-Ray Java agent distribution availability (Github) 30 | if: ${{ always() }} 31 | run: | 32 | if [[ "${{ steps.distribution-availability-github.outcome }}" == "failure" ]]; then 33 | aws cloudwatch put-metric-data --metric-name XRayJavaAgentGithubDistributionUnavailability --dimensions failure=rate --namespace MonitorAgent --value 1 --timestamp $(date +%s) 34 | else 35 | aws cloudwatch put-metric-data --metric-name XRayJavaAgentGithubDistributionUnavailability --dimensions failure=rate --namespace MonitorAgent --value 0 --timestamp $(date +%s) 36 | fi 37 | 38 | - name: Pull Java agent from Maven 39 | id: distribution-availability-maven 40 | run: | 41 | git fetch --prune --unshallow --tags 42 | version=$(git tag -l | sort -rV | head -1 | tr -d 'v') 43 | wget https://repo.maven.apache.org/maven2/com/amazonaws/aws-xray-agent-plugin/$version/aws-xray-agent-plugin-$version.jar 44 | 45 | - name: Publish metric on X-Ray Java agent distribution availability (Maven) 46 | if: ${{ always() }} 47 | run: | 48 | if [[ "${{ steps.distribution-availability-maven.outcome }}" == "failure" ]]; then 49 | aws cloudwatch put-metric-data --metric-name XRayJavaAgentMavenDistributionUnavailability --dimensions failure=rate --namespace MonitorAgent --value 1 --timestamp $(date +%s) 50 | else 51 | aws cloudwatch put-metric-data --metric-name XRayJavaAgentMavenDistributionUnavailability --dimensions failure=rate --namespace MonitorAgent --value 0 --timestamp $(date +%s) 52 | fi 53 | -------------------------------------------------------------------------------- /.github/workflows/continuous_build.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Build 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | build: 12 | name: Build Java ${{ matrix.java }} on ${{ matrix.os }} 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: 17 | - macos-latest 18 | - ubuntu-latest 19 | java: 20 | - 8 21 | - 11 22 | include: 23 | - os: ubuntu-latest 24 | java: 11 25 | coverage: true 26 | steps: 27 | - name: Checkout Repository 28 | uses: actions/checkout@v2 29 | 30 | - name: Setup java 31 | uses: actions/setup-java@v1 32 | with: 33 | java-version: ${{ matrix.java }} 34 | 35 | - name: Cache Gradle Modules 36 | uses: actions/cache@v4 37 | with: 38 | path: ~/.gradle/caches 39 | key: gradle-caches-${{ hashFiles('**/*.gradle.kts') }} 40 | 41 | - name: Cache Gradle Wrapper 42 | uses: actions/cache@v4 43 | with: 44 | path: ~/.gradle/wrapper 45 | key: gradle-wrapper-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} 46 | 47 | - name: Execute Gradle build 48 | run: ./gradlew build ${{ matrix.coverage && 'jacocoTestReport' || '' }} --stacktrace 49 | shell: bash 50 | 51 | - uses: codecov/codecov-action@v1 52 | if: ${{ matrix.coverage }} 53 | with: 54 | files: ./aws-xray-agent/build/reports/jacoco/test/jacocoTestReport.xml 55 | 56 | - uses: actions/upload-artifact@v4 57 | if: ${{ matrix.coverage }} 58 | with: 59 | name: coverage-report 60 | path: ./aws-xray-agent/build/reports/jacoco/test/html 61 | -------------------------------------------------------------------------------- /.github/workflows/release-build.yml: -------------------------------------------------------------------------------- 1 | name: Release X-Ray Java Agent 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | version: 6 | description: The version to tag the release with, e.g., 1.2.0, 1.2.1-alpha.1 7 | required: true 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-java@v1 15 | with: 16 | java-version: 11 17 | - uses: gradle/wrapper-validation-action@v1 18 | 19 | - name: Publish release with Gradle 20 | uses: burrunan/gradle-cache-action@v1 21 | with: 22 | arguments: build final closeAndReleaseSonatypeStagingRepository -Prelease.version=${{ github.event.inputs.version }} --stacktrace 23 | env: 24 | CI: true 25 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 26 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 27 | GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }} 28 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 29 | GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} 30 | GRGIT_USER: ${{ github.actor }} 31 | GRGIT_PASS: ${{ secrets.GITHUB_TOKEN }} 32 | 33 | - name: Create Release 34 | id: create_release 35 | uses: actions/create-release@v1 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | with: 39 | tag_name: v${{ github.event.inputs.version }} 40 | release_name: Release ${{ github.event.inputs.version }} 41 | body: Releasing version ${{ github.event.inputs.version }} of the AWS X-Ray Auto-Instrumentation agent for Java. Download it below. Please see [CHANGELOG](https://github.com/aws/aws-xray-java-agent/blob/master/CHANGELOG.md) for details. 42 | draft: false 43 | prerelease: false 44 | 45 | - name: Upload Release Asset 46 | id: upload-release-asset 47 | uses: actions/upload-release-asset@v1 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | with: 51 | upload_url: ${{ steps.create_release.outputs.upload_url }} 52 | asset_path: aws-xray-agent-plugin/build/dist/xray-agent.zip 53 | asset_name: xray-agent.zip 54 | asset_content_type: application/zip 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Remove .DS_Store 2 | .DS_Store 3 | **/.DS_Store 4 | 5 | # Ignore Gradle project-specific cache directory 6 | .gradle 7 | 8 | # Ignore Gradle build output directory 9 | build 10 | target 11 | 12 | # Dependency reduced POMs for building local dependencies 13 | dependency-reduced-pom.xml 14 | 15 | # IDEA stuffs 16 | *.iml 17 | .idea 18 | .settings/ 19 | .project 20 | .classpath 21 | 22 | # Don't include personal scripts 23 | sample/*.sh 24 | lib 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 2.18.2 - 2025-02-26 4 | * Fixed a list of CVE violations [PR #123](https://github.com/aws/aws-xray-java-agent/pull/123) 5 | 6 | ## 2.9.1 - 2021-06-03 7 | * Updated dependencies to latest [PR #104](https://github.com/aws/aws-xray-java-agent/pull/104) 8 | 9 | ## 2.9.0 - 2021-04-27 10 | * Fixed trace ID injection for Spring Boot apps [PR #75](https://github.com/aws/aws-xray-java-agent/pull/75) 11 | * Added default Spring Boot config location [PR #77](https://github.com/aws/aws-xray-java-agent/pull/77) 12 | * Prefer `X-Forwarded-For` for Client IP [PR #79](https://github.com/aws/aws-xray-java-agent/pull/79) 13 | * Added capturing of SQL prepare events [PR #92](https://github.com/aws/aws-xray-java-agent/pull/92) 14 | 15 | ## 2.8.0 - 2020-11-25 16 | * Fixed NPE in Servlet Response Handler [PR #63](https://github.com/aws/aws-xray-java-agent/pull/63) 17 | * Fixed bug in parsing sampling decision from upstream header [PR #66](https://github.com/aws/aws-xray-java-agent/pull/66) 18 | 19 | ## 2.7.1 - 2020-09-03 20 | * Added build steps to compile X-Ray agent ZIP [PR #55](https://github.com/aws/aws-xray-java-agent/pull/55) 21 | * Added Benchmarking tests [PR #57](https://github.com/aws/aws-xray-java-agent/pull/57) 22 | * Added support for trace ID injection and plugins [PR #52](https://github.com/aws/aws-xray-java-agent/pull/52) 23 | * Added SQL instrumentation [PR #52](https://github.com/aws/aws-xray-java-agent/pull/52) 24 | * Converted agent architecture to be a DiSCo plugin rather than monolith [PR #52](https://github.com/aws/aws-xray-java-agent/pull/52) 25 | * Converted project to Gradle [PR #52](https://github.com/aws/aws-xray-java-agent/pull/52) 26 | * Added ability to configure agent via external JSON file [PR #33](https://github.com/aws/aws-xray-java-agent/pull/33) 27 | * Switched to use Apache Commons Logging [PR #32](https://github.com/aws/aws-xray-java-agent/pull/32) 28 | 29 | ## 2.4.0-beta - 2019-12-2 30 | Initial commit 31 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | AWS X-Ray SDK Java Agent 2 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/README.md: -------------------------------------------------------------------------------- 1 | ## AWS X-Ray Agent Benchmarks 2 | 3 | This package contains benchmarking tests to compare the performance of common scenarios in a distributed application. 4 | The scenarios can be run with instrumentation by the AWS X-Ray Auto-Instrumentation Agent, the AWS X-Ray SDK for Java, 5 | and no instrumentation at all as a baseline. A local server is used to mitigate unpredictable network latencies. 6 | 7 | ## Running the Benchmarks 8 | 9 | The officially recorded benchmark results are run on an m5.xlarge Amazon EC2 instance with 4 vCPUs and 16 GB 10 | of memory running Amazon Linux 2. It is recommended you run them in a similar environment for comparable results. 11 | 12 | The benchmarks can be run in 3 modes: `agent`, `SDK`, or `normal`. When run in `normal` mode, the benchmark tests are ran without 13 | any instrumentation as a baseline. When run in `SDK` mode, the benchmark tests are ran with instrumentation by the AWS X-Ray SDK. 14 | When run in `agent` mode, the benchmark tests are ran with the X-Ray Agent included on the benchmarking JVM (these can take 15 | quite a while to complete because the agent must re-initialize before each benchmark trial). 16 | 17 | To run in Agent mode, run from the root of this repo: 18 | 19 | ```shell script 20 | ./gradlew clean jmh -Pagent 21 | ``` 22 | 23 | To run in SDK mode, run from the root of this repo: 24 | 25 | ```shell script 26 | ./gradlew clean jmh -Psdk 27 | ``` 28 | 29 | To run in normal mode, run from the root of this repo: 30 | 31 | ```shell script 32 | ./gradlew clean jmh 33 | ``` 34 | 35 | The results will be output into the `build/reports/jmh` directory after the tests are completed. 36 | 37 | ## Benchmark Results 38 | 39 | The below table summarizes the **approximate** latency added using both manual X-Ray SDK and automatic 40 | X-Ray agent-based instrumentation for different activities in microseconds. These numbers should not be 41 | considered precisely accurate in all applications, they are just to give an idea of added latency. 42 | Overall, you can see that in a typical application the SDK or the agent would not add more than a single-digit 43 | amount of milliseconds to a request. 44 | 45 | | | SDK Instrumentation | Auto Instrumentation | 46 | |--------------------------|---------------------|----------------------| 47 | | Service incoming request | +100 us | +110 us | 48 | | SQL Query | +70 us | +60 us | 49 | | AWS SDK V1 Request | +30 us | +60 us | 50 | | AWS SDK V2 Request | +30 us | +90 us | 51 | | Apache HTTP Request | +20 us | +40 us | 52 | 53 | You can also take a look the [results directory](https://github.com/aws/aws-xray-java-agent/tree/main/aws-xray-agent-benchmark/results) 54 | for detailed benchmarking data from previous versions of the agent. Since we use an arbitrary delay to simulate the effect 55 | of a network, the *absolute* values of each individual benchmark are not particularly meaningful. The results are more 56 | useful when analyzed in context, that is comparing the times of the same scenario in all 3 modes, and noticing 57 | the difference between those times. 58 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | plugins { 3 | id("me.champeau.jmh") version "0.7.1" 4 | } 5 | 6 | 7 | val JMH_VERSION = "1.37" 8 | 9 | sourceSets { 10 | named("jmh") { 11 | java { 12 | srcDir("src/jmh/java") 13 | 14 | } 15 | } 16 | } 17 | 18 | dependencies { 19 | jmh("com.amazonaws:aws-xray-recorder-sdk-core") 20 | jmh("com.amazonaws:aws-xray-recorder-sdk-sql") 21 | jmh("com.amazonaws:aws-xray-recorder-sdk-aws-sdk") { 22 | isTransitive = false // Don't bring in all clients 23 | } 24 | jmh("com.amazonaws:aws-java-sdk-dynamodb:${rootProject.extra["awsSdkV1Version"]}") 25 | jmh("com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2") 26 | jmh("software.amazon.awssdk:dynamodb:${rootProject.extra["awsSdkV2Version"]}") 27 | jmh("com.amazonaws:aws-xray-recorder-sdk-apache-http") 28 | jmh("com.blogspot.mydailyjava:weak-lock-free:0.18") 29 | 30 | jmh("org.apache.httpcomponents:httpclient:4.5.12") 31 | jmh("javax.servlet:javax.servlet-api:4.0.1") 32 | jmh("org.eclipse.jetty:jetty-server:9.4.1.v20170120") 33 | jmh("org.eclipse.jetty:jetty-servlet:9.4.1.v20170120") 34 | 35 | jmh("org.mockito:mockito-core:2.28.2") 36 | jmh("org.openjdk.jmh:jmh-generator-annprocess:${JMH_VERSION}") 37 | jmhAnnotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:${JMH_VERSION}") 38 | 39 | jmh(platform("com.amazonaws:aws-xray-recorder-sdk-bom:${rootProject.extra["xraySdkVersion"]}")) 40 | } 41 | 42 | // JMH plugin docs: https://github.com/melix/jmh-gradle-plugin 43 | jmh { 44 | benchmarkMode = listOf("thrpt", "sample") 45 | fork = 1 46 | timeUnit = "ms" 47 | 48 | warmupIterations = 10 49 | warmup = "1s" 50 | 51 | iterations = 5 52 | timeOnIteration = "1s" 53 | 54 | if (project.hasProperty("agent")) { 55 | val discoPath = "${rootProject.projectDir}/aws-xray-agent-plugin/build/libs/disco" 56 | jvmArgs = listOf("-javaagent:$discoPath/disco-java-agent.jar=pluginPath=$discoPath/disco-plugins", 57 | "-Dcom.amazonaws.xray.strategy.tracingName=Benchmark") 58 | 59 | resultsFile = project.file("$buildDir/reports/jmh/auto-instrumentation.txt") 60 | } else if (project.hasProperty("sdk")) { 61 | jvmArgs = listOf("-Dcom.amazonaws.xray.sdk=true") // Propagate the system property into testing environment to use appropriate clients 62 | resultsFile = project.file("$buildDir/reports/jmh/sdk-instrumentation.txt") 63 | } else { 64 | resultsFile = project.file("$buildDir/reports/jmh/no-instrumentation.txt") 65 | } 66 | 67 | duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE 68 | } 69 | 70 | // Need to have the disco directory assembled to run benchmarks with X-Ray agent 71 | tasks.jmh { 72 | if (project.hasProperty("agent")) { 73 | dependsOn(":aws-xray-agent-plugin:build") 74 | } 75 | } 76 | tasks.withType().configureEach { 77 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 78 | } 79 | 80 | tasks.withType().configureEach { 81 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 82 | } 83 | 84 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.18.x/jmh/auto-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.409 ± 0.008 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.383 ± 0.052 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.412 ± 0.009 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.459 ± 0.002 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.464 ± 0.024 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2038 2.453 ± 0.007 ms/op 8 | AwsSdkBenchmark.awsV1Request:p0.00 sample 2.363 ms/op 9 | AwsSdkBenchmark.awsV1Request:p0.50 sample 2.441 ms/op 10 | AwsSdkBenchmark.awsV1Request:p0.90 sample 2.511 ms/op 11 | AwsSdkBenchmark.awsV1Request:p0.95 sample 2.560 ms/op 12 | AwsSdkBenchmark.awsV1Request:p0.99 sample 2.630 ms/op 13 | AwsSdkBenchmark.awsV1Request:p0.999 sample 3.001 ms/op 14 | AwsSdkBenchmark.awsV1Request:p0.9999 sample 6.406 ms/op 15 | AwsSdkBenchmark.awsV1Request:p1.00 sample 6.406 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 1927 2.594 ± 0.008 ms/op 17 | AwsSdkBenchmark.awsV2Request:p0.00 sample 2.462 ms/op 18 | AwsSdkBenchmark.awsV2Request:p0.50 sample 2.556 ms/op 19 | AwsSdkBenchmark.awsV2Request:p0.90 sample 2.745 ms/op 20 | AwsSdkBenchmark.awsV2Request:p0.95 sample 2.793 ms/op 21 | AwsSdkBenchmark.awsV2Request:p0.99 sample 2.936 ms/op 22 | AwsSdkBenchmark.awsV2Request:p0.999 sample 3.334 ms/op 23 | AwsSdkBenchmark.awsV2Request:p0.9999 sample 3.805 ms/op 24 | AwsSdkBenchmark.awsV2Request:p1.00 sample 3.805 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2063 2.424 ± 0.007 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:p0.00 sample 2.347 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:p0.50 sample 2.413 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:p0.90 sample 2.470 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:p0.95 sample 2.494 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:p0.99 sample 2.578 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:p0.999 sample 2.857 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:p0.9999 sample 6.488 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:p1.00 sample 6.488 ms/op 34 | ServletBenchmark.serviceRequest sample 2294 2.179 ± 0.001 ms/op 35 | ServletBenchmark.serviceRequest:p0.00 sample 2.134 ms/op 36 | ServletBenchmark.serviceRequest:p0.50 sample 2.175 ms/op 37 | ServletBenchmark.serviceRequest:p0.90 sample 2.187 ms/op 38 | ServletBenchmark.serviceRequest:p0.95 sample 2.195 ms/op 39 | ServletBenchmark.serviceRequest:p0.99 sample 2.298 ms/op 40 | ServletBenchmark.serviceRequest:p0.999 sample 2.373 ms/op 41 | ServletBenchmark.serviceRequest:p0.9999 sample 2.380 ms/op 42 | ServletBenchmark.serviceRequest:p1.00 sample 2.380 ms/op 43 | SqlBenchmark.sqlQuery sample 2343 2.135 ± 0.001 ms/op 44 | SqlBenchmark.sqlQuery:p0.00 sample 2.085 ms/op 45 | SqlBenchmark.sqlQuery:p0.50 sample 2.130 ms/op 46 | SqlBenchmark.sqlQuery:p0.90 sample 2.142 ms/op 47 | SqlBenchmark.sqlQuery:p0.95 sample 2.178 ms/op 48 | SqlBenchmark.sqlQuery:p0.99 sample 2.226 ms/op 49 | SqlBenchmark.sqlQuery:p0.999 sample 2.292 ms/op 50 | SqlBenchmark.sqlQuery:p0.9999 sample 2.482 ms/op 51 | SqlBenchmark.sqlQuery:p1.00 sample 2.482 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.18.x/jmh/no-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.420 ± 0.008 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.405 ± 0.026 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.420 ± 0.010 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.483 ± 0.001 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.484 ± 0.002 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2096 2.385 ± 0.012 ms/op 8 | AwsSdkBenchmark.awsV1Request:p0.00 sample 2.302 ms/op 9 | AwsSdkBenchmark.awsV1Request:p0.50 sample 2.372 ms/op 10 | AwsSdkBenchmark.awsV1Request:p0.90 sample 2.425 ms/op 11 | AwsSdkBenchmark.awsV1Request:p0.95 sample 2.466 ms/op 12 | AwsSdkBenchmark.awsV1Request:p0.99 sample 2.540 ms/op 13 | AwsSdkBenchmark.awsV1Request:p0.999 sample 6.357 ms/op 14 | AwsSdkBenchmark.awsV1Request:p0.9999 sample 8.086 ms/op 15 | AwsSdkBenchmark.awsV1Request:p1.00 sample 8.086 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2026 2.468 ± 0.012 ms/op 17 | AwsSdkBenchmark.awsV2Request:p0.00 sample 2.380 ms/op 18 | AwsSdkBenchmark.awsV2Request:p0.50 sample 2.449 ms/op 19 | AwsSdkBenchmark.awsV2Request:p0.90 sample 2.523 ms/op 20 | AwsSdkBenchmark.awsV2Request:p0.95 sample 2.568 ms/op 21 | AwsSdkBenchmark.awsV2Request:p0.99 sample 2.691 ms/op 22 | AwsSdkBenchmark.awsV2Request:p0.999 sample 3.407 ms/op 23 | AwsSdkBenchmark.awsV2Request:p0.9999 sample 9.552 ms/op 24 | AwsSdkBenchmark.awsV2Request:p1.00 sample 9.552 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2057 2.430 ± 0.022 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:p0.00 sample 2.351 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:p0.50 sample 2.404 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:p0.90 sample 2.458 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:p0.95 sample 2.515 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:p0.99 sample 2.771 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:p0.999 sample 11.164 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:p0.9999 sample 11.846 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:p1.00 sample 11.846 ms/op 34 | ServletBenchmark.serviceRequest sample 2416 2.070 ± 0.001 ms/op 35 | ServletBenchmark.serviceRequest:p0.00 sample 2.025 ms/op 36 | ServletBenchmark.serviceRequest:p0.50 sample 2.068 ms/op 37 | ServletBenchmark.serviceRequest:p0.90 sample 2.073 ms/op 38 | ServletBenchmark.serviceRequest:p0.95 sample 2.079 ms/op 39 | ServletBenchmark.serviceRequest:p0.99 sample 2.105 ms/op 40 | ServletBenchmark.serviceRequest:p0.999 sample 2.126 ms/op 41 | ServletBenchmark.serviceRequest:p0.9999 sample 2.363 ms/op 42 | ServletBenchmark.serviceRequest:p1.00 sample 2.363 ms/op 43 | SqlBenchmark.sqlQuery sample 2424 2.064 ± 0.001 ms/op 44 | SqlBenchmark.sqlQuery:p0.00 sample 2.023 ms/op 45 | SqlBenchmark.sqlQuery:p0.50 sample 2.062 ms/op 46 | SqlBenchmark.sqlQuery:p0.90 sample 2.068 ms/op 47 | SqlBenchmark.sqlQuery:p0.95 sample 2.075 ms/op 48 | SqlBenchmark.sqlQuery:p0.99 sample 2.091 ms/op 49 | SqlBenchmark.sqlQuery:p0.999 sample 2.118 ms/op 50 | SqlBenchmark.sqlQuery:p0.9999 sample 2.183 ms/op 51 | SqlBenchmark.sqlQuery:p1.00 sample 2.183 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.18.x/jmh/sdk-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.413 ± 0.009 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.392 ± 0.085 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.416 ± 0.007 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.462 ± 0.012 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.465 ± 0.022 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2072 2.412 ± 0.010 ms/op 8 | AwsSdkBenchmark.awsV1Request:p0.00 sample 2.314 ms/op 9 | AwsSdkBenchmark.awsV1Request:p0.50 sample 2.404 ms/op 10 | AwsSdkBenchmark.awsV1Request:p0.90 sample 2.465 ms/op 11 | AwsSdkBenchmark.awsV1Request:p0.95 sample 2.504 ms/op 12 | AwsSdkBenchmark.awsV1Request:p0.99 sample 2.562 ms/op 13 | AwsSdkBenchmark.awsV1Request:p0.999 sample 2.739 ms/op 14 | AwsSdkBenchmark.awsV1Request:p0.9999 sample 8.331 ms/op 15 | AwsSdkBenchmark.awsV1Request:p1.00 sample 8.331 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 1975 2.532 ± 0.086 ms/op 17 | AwsSdkBenchmark.awsV2Request:p0.00 sample 2.413 ms/op 18 | AwsSdkBenchmark.awsV2Request:p0.50 sample 2.486 ms/op 19 | AwsSdkBenchmark.awsV2Request:p0.90 sample 2.589 ms/op 20 | AwsSdkBenchmark.awsV2Request:p0.95 sample 2.634 ms/op 21 | AwsSdkBenchmark.awsV2Request:p0.99 sample 2.819 ms/op 22 | AwsSdkBenchmark.awsV2Request:p0.999 sample 5.522 ms/op 23 | AwsSdkBenchmark.awsV2Request:p0.9999 sample 53.871 ms/op 24 | AwsSdkBenchmark.awsV2Request:p1.00 sample 53.871 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2088 2.394 ± 0.018 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:p0.00 sample 2.322 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:p0.50 sample 2.380 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:p0.90 sample 2.421 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:p0.95 sample 2.437 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:p0.99 sample 2.544 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:p0.999 sample 9.448 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:p0.9999 sample 10.420 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:p1.00 sample 10.420 ms/op 34 | ServletBenchmark.serviceRequest sample 2309 2.166 ± 0.002 ms/op 35 | ServletBenchmark.serviceRequest:p0.00 sample 2.126 ms/op 36 | ServletBenchmark.serviceRequest:p0.50 sample 2.154 ms/op 37 | ServletBenchmark.serviceRequest:p0.90 sample 2.208 ms/op 38 | ServletBenchmark.serviceRequest:p0.95 sample 2.232 ms/op 39 | ServletBenchmark.serviceRequest:p0.99 sample 2.273 ms/op 40 | ServletBenchmark.serviceRequest:p0.999 sample 2.326 ms/op 41 | ServletBenchmark.serviceRequest:p0.9999 sample 2.331 ms/op 42 | ServletBenchmark.serviceRequest:p1.00 sample 2.331 ms/op 43 | SqlBenchmark.sqlQuery sample 2333 2.143 ± 0.029 ms/op 44 | SqlBenchmark.sqlQuery:p0.00 sample 2.085 ms/op 45 | SqlBenchmark.sqlQuery:p0.50 sample 2.126 ms/op 46 | SqlBenchmark.sqlQuery:p0.90 sample 2.159 ms/op 47 | SqlBenchmark.sqlQuery:p0.95 sample 2.191 ms/op 48 | SqlBenchmark.sqlQuery:p0.99 sample 2.236 ms/op 49 | SqlBenchmark.sqlQuery:p0.999 sample 2.280 ms/op 50 | SqlBenchmark.sqlQuery:p0.9999 sample 22.610 ms/op 51 | SqlBenchmark.sqlQuery:p1.00 sample 22.610 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.7.x/jmh/auto-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.416 ± 0.007 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.402 ± 0.015 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.419 ± 0.012 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.460 ± 0.001 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.469 ± 0.003 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2069 2.417 ± 0.004 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.339 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.408 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.454 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.494 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.572 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 2.736 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 4.211 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 4.211 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2011 2.486 ± 0.005 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.400 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.474 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.552 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.580 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.682 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 2.863 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 4.588 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 4.588 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2098 2.383 ± 0.020 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.277 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.367 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.413 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.433 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.490 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 9.244 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 10.207 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 10.207 ms/op 34 | ServletBenchmark.serviceRequest sample 2277 2.196 ± 0.064 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.163 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.171 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.183 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.208 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.295 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.358 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 46.596 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 46.596 ms/op 43 | SqlBenchmark.sqlQuery sample 2350 2.129 ± 0.001 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.101 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.126 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.134 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.142 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.220 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.270 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 2.310 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 2.310 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.7.x/jmh/no-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.426 ± 0.008 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.419 ± 0.008 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.429 ± 0.009 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.482 ± 0.011 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.484 ± 0.001 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2132 2.345 ± 0.007 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.265 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.339 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.380 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.414 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.488 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 3.999 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 5.964 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 5.964 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2099 2.383 ± 0.008 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.294 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.376 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.421 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.445 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.540 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 2.944 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 7.135 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 7.135 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2140 2.335 ± 0.024 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.253 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.306 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.339 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.359 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.608 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 9.664 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 10.715 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 10.715 ms/op 34 | ServletBenchmark.serviceRequest sample 2419 2.068 ± 0.001 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.023 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.066 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.073 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.083 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.101 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.123 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 2.310 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 2.310 ms/op 43 | SqlBenchmark.sqlQuery sample 2424 2.063 ± 0.001 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.025 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.062 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.066 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.073 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.087 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.128 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 2.142 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 2.142 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.7.x/jmh/sdk-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.419 ± 0.007 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.414 ± 0.010 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.426 ± 0.009 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.461 ± 0.016 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.468 ± 0.015 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2101 2.380 ± 0.009 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.306 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.367 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.420 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.462 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.531 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 3.568 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 7.447 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 7.447 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2071 2.413 ± 0.009 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.327 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.404 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.454 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.478 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.578 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 3.355 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 7.315 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 7.315 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2126 2.351 ± 0.025 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.261 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.327 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.363 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.380 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.482 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 10.024 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 10.699 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 10.699 ms/op 34 | ServletBenchmark.serviceRequest sample 2305 2.169 ± 0.027 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.142 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.154 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.167 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.212 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.269 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.340 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 20.808 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 20.808 ms/op 43 | SqlBenchmark.sqlQuery sample 2343 2.134 ± 0.025 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.114 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.122 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.130 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.178 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.212 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.501 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 20.021 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 20.021 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.8.x/jmh/auto-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.411 ± 0.007 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.400 ± 0.010 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.418 ± 0.007 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.453 ± 0.046 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.468 ± 0.003 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2060 2.426 ± 0.005 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.339 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.417 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.466 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.499 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.593 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 3.751 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 4.325 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 4.325 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2011 2.487 ± 0.004 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.396 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.478 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.523 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.553 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.671 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 3.070 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 3.506 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 3.506 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2091 2.391 ± 0.020 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.310 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.372 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.417 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.445 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.577 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 9.083 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 10.043 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 10.043 ms/op 34 | ServletBenchmark.serviceRequest sample 2274 2.199 ± 0.067 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.163 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.175 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.187 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.195 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.225 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.343 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 48.628 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 48.628 ms/op 43 | SqlBenchmark.sqlQuery sample 2345 2.132 ± 0.001 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.091 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.130 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.138 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.142 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.214 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.273 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 2.281 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 2.281 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.8.x/jmh/no-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.425 ± 0.008 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.417 ± 0.005 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.428 ± 0.014 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.482 ± 0.002 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.484 ± 0.002 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2120 2.358 ± 0.003 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.281 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.351 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.396 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.441 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.519 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 2.711 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 2.867 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 2.867 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2086 2.397 ± 0.009 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.327 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.388 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.430 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.462 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.568 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 3.064 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 7.569 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 7.569 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2138 2.337 ± 0.018 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.265 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.322 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.359 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.376 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.448 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 9.182 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 10.142 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 10.142 ms/op 34 | ServletBenchmark.serviceRequest sample 2414 2.072 ± 0.001 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.032 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.071 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.079 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.091 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.101 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.124 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 2.359 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 2.359 ms/op 43 | SqlBenchmark.sqlQuery sample 2419 2.069 ± 0.008 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.019 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.064 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.071 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.075 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.093 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.166 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 8.012 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 8.012 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.8.x/jmh/sdk-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.419 ± 0.007 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.413 ± 0.008 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.425 ± 0.002 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.459 ± 0.015 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.466 ± 0.014 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2092 2.389 ± 0.008 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.298 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.380 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.425 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.470 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.528 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 3.631 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 6.619 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 6.619 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2065 2.421 ± 0.010 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.335 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.413 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.462 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.482 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.564 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 3.754 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 7.897 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 7.897 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2129 2.348 ± 0.021 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.265 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.327 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.363 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.388 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.465 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 9.896 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 11.158 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 11.158 ms/op 34 | ServletBenchmark.serviceRequest sample 2298 2.175 ± 0.032 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.142 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.154 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.208 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.249 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.269 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.411 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 24.150 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 24.150 ms/op 43 | SqlBenchmark.sqlQuery sample 2324 2.153 ± 0.036 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.093 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.138 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.179 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.204 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.241 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.377 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 27.361 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 27.361 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.9.x/jmh/auto-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.411 ± 0.012 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.401 ± 0.021 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.415 ± 0.011 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.458 ± 0.004 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.465 ± 0.020 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2060 2.427 ± 0.006 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.347 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.417 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.466 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.490 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.562 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 3.946 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 4.596 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 4.596 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2003 2.497 ± 0.006 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.413 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.486 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.552 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.593 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.720 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 3.026 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 5.407 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 5.407 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2085 2.399 ± 0.014 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.318 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.376 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.437 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.458 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.573 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 5.492 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 8.077 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 8.077 ms/op 34 | ServletBenchmark.serviceRequest sample 2294 2.180 ± 0.001 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.167 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.179 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.187 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.191 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.232 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.331 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 2.347 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 2.347 ms/op 43 | SqlBenchmark.sqlQuery sample 2329 2.148 ± 0.035 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.122 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.130 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.146 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.171 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.220 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.417 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 27.132 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 27.132 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.9.x/jmh/no-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.422 ± 0.011 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.416 ± 0.007 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.424 ± 0.009 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.482 ± 0.003 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.483 ± 0.005 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2109 2.371 ± 0.010 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.298 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.355 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.413 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.458 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.519 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 6.210 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 7.176 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 7.176 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2076 2.408 ± 0.009 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.335 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.400 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.445 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.478 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.573 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 2.885 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 7.438 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 7.438 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2120 2.358 ± 0.022 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.265 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.335 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.372 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.392 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.469 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 10.463 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 11.125 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 11.125 ms/op 34 | ServletBenchmark.serviceRequest sample 2413 2.073 ± 0.001 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.032 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.071 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.079 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.085 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.109 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.134 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 2.380 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 2.380 ms/op 43 | SqlBenchmark.sqlQuery sample 2414 2.072 ± 0.012 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.036 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.066 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.075 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.077 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.095 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.184 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 11.059 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 11.059 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/results/2.9.x/jmh/sdk-instrumentation.txt: -------------------------------------------------------------------------------- 1 | Benchmark Mode Cnt Score Error Units 2 | AwsSdkBenchmark.awsV1Request thrpt 5 0.417 ± 0.005 ops/ms 3 | AwsSdkBenchmark.awsV2Request thrpt 5 0.412 ± 0.009 ops/ms 4 | HttpDownstreamBenchmark.makeHttpRequest thrpt 5 0.423 ± 0.009 ops/ms 5 | ServletBenchmark.serviceRequest thrpt 5 0.459 ± 0.019 ops/ms 6 | SqlBenchmark.sqlQuery thrpt 5 0.466 ± 0.015 ops/ms 7 | AwsSdkBenchmark.awsV1Request sample 2089 2.392 ± 0.009 ms/op 8 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.00 sample 2.294 ms/op 9 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.50 sample 2.384 ms/op 10 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.90 sample 2.425 ms/op 11 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.95 sample 2.449 ms/op 12 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.99 sample 2.548 ms/op 13 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.999 sample 4.759 ms/op 14 | AwsSdkBenchmark.awsV1Request:awsV1Request·p0.9999 sample 6.971 ms/op 15 | AwsSdkBenchmark.awsV1Request:awsV1Request·p1.00 sample 6.971 ms/op 16 | AwsSdkBenchmark.awsV2Request sample 2063 2.424 ± 0.010 ms/op 17 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.00 sample 2.331 ms/op 18 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.50 sample 2.413 ms/op 19 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.90 sample 2.466 ms/op 20 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.95 sample 2.494 ms/op 21 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.99 sample 2.634 ms/op 22 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.999 sample 3.390 ms/op 23 | AwsSdkBenchmark.awsV2Request:awsV2Request·p0.9999 sample 8.102 ms/op 24 | AwsSdkBenchmark.awsV2Request:awsV2Request·p1.00 sample 8.102 ms/op 25 | HttpDownstreamBenchmark.makeHttpRequest sample 2111 2.367 ± 0.023 ms/op 26 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.00 sample 2.277 ms/op 27 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.50 sample 2.343 ms/op 28 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.90 sample 2.388 ms/op 29 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.95 sample 2.408 ms/op 30 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.99 sample 2.485 ms/op 31 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.999 sample 10.281 ms/op 32 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p0.9999 sample 12.157 ms/op 33 | HttpDownstreamBenchmark.makeHttpRequest:makeHttpRequest·p1.00 sample 12.157 ms/op 34 | ServletBenchmark.serviceRequest sample 2298 2.176 ± 0.030 ms/op 35 | ServletBenchmark.serviceRequest:serviceRequest·p0.00 sample 2.142 ms/op 36 | ServletBenchmark.serviceRequest:serviceRequest·p0.50 sample 2.159 ms/op 37 | ServletBenchmark.serviceRequest:serviceRequest·p0.90 sample 2.208 ms/op 38 | ServletBenchmark.serviceRequest:serviceRequest·p0.95 sample 2.224 ms/op 39 | ServletBenchmark.serviceRequest:serviceRequest·p0.99 sample 2.269 ms/op 40 | ServletBenchmark.serviceRequest:serviceRequest·p0.999 sample 2.440 ms/op 41 | ServletBenchmark.serviceRequest:serviceRequest·p0.9999 sample 22.807 ms/op 42 | ServletBenchmark.serviceRequest:serviceRequest·p1.00 sample 22.807 ms/op 43 | SqlBenchmark.sqlQuery sample 2332 2.144 ± 0.028 ms/op 44 | SqlBenchmark.sqlQuery:sqlQuery·p0.00 sample 2.105 ms/op 45 | SqlBenchmark.sqlQuery:sqlQuery·p0.50 sample 2.130 ms/op 46 | SqlBenchmark.sqlQuery:sqlQuery·p0.90 sample 2.150 ms/op 47 | SqlBenchmark.sqlQuery:sqlQuery·p0.95 sample 2.195 ms/op 48 | SqlBenchmark.sqlQuery:sqlQuery·p0.99 sample 2.224 ms/op 49 | SqlBenchmark.sqlQuery:sqlQuery·p0.999 sample 2.392 ms/op 50 | SqlBenchmark.sqlQuery:sqlQuery·p0.9999 sample 21.955 ms/op 51 | SqlBenchmark.sqlQuery:sqlQuery·p1.00 sample 21.955 ms/op 52 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/runAllBenchmarks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "" ]; then 4 | echo "Must provide a version number argument, e.g. 2.7.x" 5 | exit 0 6 | fi 7 | 8 | echo "**************************************" 9 | echo "Starting Baseline Benchmarks" 10 | echo "**************************************" 11 | 12 | ./gradlew clean jmh --stacktrace 13 | 14 | echo "**************************************" 15 | echo "Starting SDK Benchmarks" 16 | echo "**************************************" 17 | 18 | ./gradlew jmh -Psdk --stacktrace 19 | 20 | echo "**************************************" 21 | echo "Starting SDK Benchmarks" 22 | echo "**************************************" 23 | 24 | ./gradlew jmh -Pagent -x test --stacktrace # We don't care about agent integ tests here 25 | 26 | echo "**************************************" 27 | echo "Finished all benchmarks" 28 | echo "**************************************" 29 | 30 | mkdir -p "aws-xray-agent-benchmark/results/$1" 31 | cp -Rf aws-xray-agent-benchmark/build/reports/jmh/ "aws-xray-agent-benchmark/results/$1" 32 | git add aws-xray-agent-benchmark/results 33 | 34 | echo "Inspect the results in aws-xray-agent-benchmark/results/$1 then commit!" 35 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/benchmark/AwsSdkBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.benchmark; 2 | 3 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; 4 | import com.amazonaws.xray.AWSXRay; 5 | import com.amazonaws.xray.AWSXRayRecorder; 6 | import com.amazonaws.xray.agent.utils.BenchmarkUtils; 7 | import com.amazonaws.xray.agent.utils.ClientProvider; 8 | import com.amazonaws.xray.agent.utils.SimpleJettyServer; 9 | import org.eclipse.jetty.server.Server; 10 | import org.openjdk.jmh.annotations.Benchmark; 11 | import org.openjdk.jmh.annotations.Fork; 12 | import org.openjdk.jmh.annotations.Level; 13 | import org.openjdk.jmh.annotations.Scope; 14 | import org.openjdk.jmh.annotations.Setup; 15 | import org.openjdk.jmh.annotations.State; 16 | import org.openjdk.jmh.annotations.TearDown; 17 | import software.amazon.awssdk.services.dynamodb.DynamoDbClient; 18 | 19 | /** 20 | * For the AWS SDK benchmarks, we use the same trick as in {@link HttpDownstreamBenchmark} to stop the Agent from 21 | * attempting to create segments for our jetty server and mess up the timing. 22 | */ 23 | @Fork(jvmArgsAppend = "-Dcom.amazonaws.xray.configFile=/com/amazonaws/xray/agent/agent-config.json") 24 | public class AwsSdkBenchmark { 25 | private static final int PORT = 20808; 26 | private static final String PATH = "/"; // path for ListTables API 27 | 28 | @State(Scope.Benchmark) 29 | public static class BenchmarkState { 30 | AmazonDynamoDB v1Client; 31 | DynamoDbClient v2Client; 32 | AWSXRayRecorder recorder; 33 | Server jettyServer; 34 | 35 | @Setup(Level.Trial) 36 | public void setup() { 37 | recorder = BenchmarkUtils.configureXRayRecorder(); 38 | 39 | if (System.getProperty("com.amazonaws.xray.sdk") != null) { 40 | v1Client = ClientProvider.instrumentedV1Client(recorder); 41 | v2Client = ClientProvider.instrumentedV2Client(); 42 | } else { 43 | v1Client = ClientProvider.normalV1Client(); 44 | v2Client = ClientProvider.normalV2Client(); 45 | } 46 | 47 | jettyServer = SimpleJettyServer.create(PORT, PATH); 48 | } 49 | 50 | @TearDown(Level.Trial) 51 | public void cleanup() { 52 | try { 53 | jettyServer.stop(); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } finally { 57 | jettyServer.destroy(); 58 | } 59 | } 60 | } 61 | 62 | @Benchmark 63 | public void awsV1Request(BenchmarkState state) { 64 | AWSXRay.beginSegment("Benchmark"); 65 | state.v1Client.listTables(); 66 | AWSXRay.endSegment(); 67 | } 68 | 69 | @Benchmark 70 | public void awsV2Request(BenchmarkState state) { 71 | AWSXRay.beginSegment("Benchmark"); 72 | state.v2Client.listTables(); 73 | AWSXRay.endSegment(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/benchmark/HttpDownstreamBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.benchmark; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.AWSXRayRecorder; 5 | import com.amazonaws.xray.agent.utils.BenchmarkUtils; 6 | import com.amazonaws.xray.agent.utils.ClientProvider; 7 | import com.amazonaws.xray.agent.utils.SimpleJettyServer; 8 | import com.amazonaws.xray.entities.TraceHeader; 9 | import org.apache.http.client.methods.HttpGet; 10 | import org.apache.http.impl.client.CloseableHttpClient; 11 | import org.eclipse.jetty.server.Server; 12 | import org.openjdk.jmh.annotations.Benchmark; 13 | import org.openjdk.jmh.annotations.Fork; 14 | import org.openjdk.jmh.annotations.Level; 15 | import org.openjdk.jmh.annotations.Scope; 16 | import org.openjdk.jmh.annotations.Setup; 17 | import org.openjdk.jmh.annotations.State; 18 | import org.openjdk.jmh.annotations.TearDown; 19 | 20 | import java.io.IOException; 21 | 22 | public class HttpDownstreamBenchmark { 23 | private static final int PORT = 20808; 24 | private static final String PATH = "/path/to/page"; 25 | 26 | @State(Scope.Benchmark) 27 | public static class BenchmarkState { 28 | CloseableHttpClient httpClient; 29 | HttpGet httpGet; 30 | AWSXRayRecorder recorder; 31 | Server jettyServer; 32 | 33 | @Setup(Level.Trial) 34 | public void setup() { 35 | recorder = BenchmarkUtils.configureXRayRecorder(); 36 | 37 | if (System.getProperty("com.amazonaws.xray.sdk") != null) { 38 | httpClient = ClientProvider.instrumentedApacheHttpClient(); 39 | } else { 40 | httpClient = ClientProvider.normalApacheHttpClient(); 41 | } 42 | httpGet = new HttpGet("http://localhost:" + PORT + PATH); 43 | 44 | jettyServer = SimpleJettyServer.create(PORT, PATH); 45 | } 46 | 47 | @TearDown(Level.Trial) 48 | public void cleanup() { 49 | try { 50 | jettyServer.stop(); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } finally { 54 | jettyServer.destroy(); 55 | } 56 | } 57 | } 58 | 59 | /** 60 | * This benchmark tests the time it takes to make a HTTP request with an Apache client wrapped in an X-Ray Segment. 61 | * It can be tested with or without the agent running on the JVM. The segment is necessary because we only want to 62 | * test the performance change introduced by the instrumentation of the Apache client, and without the segment we 63 | * get CMEs, which do not accurately represent the instrumentation latency. 64 | * 65 | * As something of a hack, we add an additional JVM arg pointing to an agent config file in the resources directory 66 | * that disables the agent's instrumentation of servlet requests. This prevents us from attempting to start a new 67 | * segment when the Jetty server handles these HTTP requests, which would add latency. 68 | */ 69 | @Benchmark 70 | @Fork(jvmArgsAppend = "-Dcom.amazonaws.xray.configFile=/com/amazonaws/xray/agent/agent-config.json") 71 | public void makeHttpRequest(BenchmarkState state) throws IOException { 72 | AWSXRay.beginSegment("Benchmark"); 73 | state.httpClient.execute(state.httpGet); 74 | state.httpGet.releaseConnection(); // Prevents overwhelming max connections 75 | state.httpGet.removeHeaders(TraceHeader.HEADER_KEY); // Prevents Trace ID headers stacking up 76 | AWSXRay.endSegment(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/benchmark/ServletBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.benchmark; 2 | 3 | import com.amazonaws.xray.agent.utils.BenchmarkUtils; 4 | import com.amazonaws.xray.agent.utils.ClientProvider; 5 | import org.mockito.Mock; 6 | import org.mockito.MockitoAnnotations; 7 | import org.openjdk.jmh.annotations.Benchmark; 8 | import org.openjdk.jmh.annotations.Level; 9 | import org.openjdk.jmh.annotations.Scope; 10 | import org.openjdk.jmh.annotations.Setup; 11 | import org.openjdk.jmh.annotations.State; 12 | 13 | import javax.servlet.ServletException; 14 | import javax.servlet.http.HttpServlet; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.IOException; 18 | 19 | import static org.mockito.Mockito.when; 20 | 21 | public class ServletBenchmark { 22 | @State(Scope.Benchmark) 23 | public static class BenchmarkState { 24 | HttpServlet servlet; 25 | 26 | @Mock 27 | HttpServletRequest servletRequest; 28 | 29 | @Mock 30 | HttpServletResponse servletResponse; 31 | 32 | @Setup(Level.Trial) 33 | public void setup() { 34 | MockitoAnnotations.initMocks(this); 35 | BenchmarkUtils.configureXRayRecorder(); 36 | 37 | when(servletRequest.getRequestURL()).thenReturn(new StringBuffer("http://example.com")); 38 | when(servletRequest.getMethod()).thenReturn("GET"); 39 | when(servletResponse.getStatus()).thenReturn(200); 40 | 41 | if (System.getProperty("com.amazonaws.xray.sdk") != null) { 42 | servlet = ClientProvider.instrumentedHttpServlet(); 43 | } else { 44 | servlet = ClientProvider.normalHttpServlet(); 45 | } 46 | } 47 | } 48 | 49 | @Benchmark 50 | public void serviceRequest(BenchmarkState state) throws IOException, ServletException { 51 | state.servlet.service(state.servletRequest, state.servletResponse); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/benchmark/SqlBenchmark.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.benchmark; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.agent.benchmark.source.StatementImpl; 5 | import com.amazonaws.xray.agent.utils.BenchmarkUtils; 6 | import com.amazonaws.xray.sql.TracingStatement; 7 | import org.openjdk.jmh.annotations.Benchmark; 8 | import org.openjdk.jmh.annotations.Level; 9 | import org.openjdk.jmh.annotations.Scope; 10 | import org.openjdk.jmh.annotations.Setup; 11 | import org.openjdk.jmh.annotations.State; 12 | 13 | import java.sql.SQLException; 14 | import java.sql.Statement; 15 | 16 | public class SqlBenchmark { 17 | @State(Scope.Benchmark) 18 | public static class BenchmarkState { 19 | Statement statement; 20 | 21 | @Setup(Level.Trial) 22 | public void setup() { 23 | BenchmarkUtils.configureXRayRecorder(); 24 | 25 | if (System.getProperty("com.amazonaws.xray.sdk") != null) { 26 | statement = TracingStatement.decorateStatement(new StatementImpl()); 27 | } else { 28 | statement = new StatementImpl(); 29 | } 30 | } 31 | } 32 | 33 | @Benchmark 34 | public void sqlQuery(BenchmarkState state) throws SQLException { 35 | AWSXRay.beginSegment("Benchmark"); 36 | state.statement.executeQuery("SQL"); 37 | AWSXRay.endSegment(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/benchmark/source/StatementImpl.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.benchmark.source; 2 | 3 | import org.mockito.Mock; 4 | import org.mockito.MockitoAnnotations; 5 | 6 | import java.sql.Connection; 7 | import java.sql.DatabaseMetaData; 8 | import java.sql.ResultSet; 9 | import java.sql.SQLException; 10 | import java.sql.SQLWarning; 11 | import java.sql.Statement; 12 | 13 | import static org.mockito.Mockito.when; 14 | 15 | public class StatementImpl implements Statement { 16 | @Mock 17 | private Connection connection; 18 | 19 | @Mock 20 | private DatabaseMetaData metaData; 21 | 22 | { 23 | try { 24 | MockitoAnnotations.initMocks(this); 25 | when(connection.getMetaData()).thenReturn(metaData); 26 | when(metaData.getURL()).thenReturn("http://example.com"); 27 | when(metaData.getUserName()).thenReturn("User"); 28 | when(metaData.getDriverVersion()).thenReturn("1.0"); 29 | when(metaData.getDatabaseProductName()).thenReturn("MyDb"); 30 | when(metaData.getDatabaseProductVersion()).thenReturn("1.0"); 31 | } catch (SQLException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | 36 | @Override 37 | public ResultSet executeQuery(String sql) throws SQLException { 38 | try { 39 | Thread.sleep(2); 40 | } catch (Exception e) { 41 | } 42 | 43 | return null; 44 | } 45 | 46 | @Override 47 | public int executeUpdate(String sql) throws SQLException { 48 | return 0; 49 | } 50 | 51 | @Override 52 | public void close() throws SQLException { 53 | 54 | } 55 | 56 | @Override 57 | public int getMaxFieldSize() throws SQLException { 58 | return 0; 59 | } 60 | 61 | @Override 62 | public void setMaxFieldSize(int max) throws SQLException { 63 | 64 | } 65 | 66 | @Override 67 | public int getMaxRows() throws SQLException { 68 | return 0; 69 | } 70 | 71 | @Override 72 | public void setMaxRows(int max) throws SQLException { 73 | 74 | } 75 | 76 | @Override 77 | public void setEscapeProcessing(boolean enable) throws SQLException { 78 | 79 | } 80 | 81 | @Override 82 | public int getQueryTimeout() throws SQLException { 83 | return 0; 84 | } 85 | 86 | @Override 87 | public void setQueryTimeout(int seconds) throws SQLException { 88 | 89 | } 90 | 91 | @Override 92 | public void cancel() throws SQLException { 93 | 94 | } 95 | 96 | @Override 97 | public SQLWarning getWarnings() throws SQLException { 98 | return null; 99 | } 100 | 101 | @Override 102 | public void clearWarnings() throws SQLException { 103 | 104 | } 105 | 106 | @Override 107 | public void setCursorName(String name) throws SQLException { 108 | 109 | } 110 | 111 | @Override 112 | public boolean execute(String sql) throws SQLException { 113 | return false; 114 | } 115 | 116 | @Override 117 | public ResultSet getResultSet() throws SQLException { 118 | return null; 119 | } 120 | 121 | @Override 122 | public int getUpdateCount() throws SQLException { 123 | return 0; 124 | } 125 | 126 | @Override 127 | public boolean getMoreResults() throws SQLException { 128 | return false; 129 | } 130 | 131 | @Override 132 | public void setFetchDirection(int direction) throws SQLException { 133 | 134 | } 135 | 136 | @Override 137 | public int getFetchDirection() throws SQLException { 138 | return 0; 139 | } 140 | 141 | @Override 142 | public void setFetchSize(int rows) throws SQLException { 143 | 144 | } 145 | 146 | @Override 147 | public int getFetchSize() throws SQLException { 148 | return 0; 149 | } 150 | 151 | @Override 152 | public int getResultSetConcurrency() throws SQLException { 153 | return 0; 154 | } 155 | 156 | @Override 157 | public int getResultSetType() throws SQLException { 158 | return 0; 159 | } 160 | 161 | @Override 162 | public void addBatch(String sql) throws SQLException { 163 | 164 | } 165 | 166 | @Override 167 | public void clearBatch() throws SQLException { 168 | 169 | } 170 | 171 | @Override 172 | public int[] executeBatch() throws SQLException { 173 | return new int[0]; 174 | } 175 | 176 | @Override 177 | public Connection getConnection() throws SQLException { 178 | return connection; 179 | } 180 | 181 | @Override 182 | public boolean getMoreResults(int current) throws SQLException { 183 | return false; 184 | } 185 | 186 | @Override 187 | public ResultSet getGeneratedKeys() throws SQLException { 188 | return null; 189 | } 190 | 191 | @Override 192 | public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { 193 | return 0; 194 | } 195 | 196 | @Override 197 | public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { 198 | return 0; 199 | } 200 | 201 | @Override 202 | public int executeUpdate(String sql, String[] columnNames) throws SQLException { 203 | return 0; 204 | } 205 | 206 | @Override 207 | public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { 208 | return false; 209 | } 210 | 211 | @Override 212 | public boolean execute(String sql, int[] columnIndexes) throws SQLException { 213 | return false; 214 | } 215 | 216 | @Override 217 | public boolean execute(String sql, String[] columnNames) throws SQLException { 218 | return false; 219 | } 220 | 221 | @Override 222 | public int getResultSetHoldability() throws SQLException { 223 | return 0; 224 | } 225 | 226 | @Override 227 | public boolean isClosed() throws SQLException { 228 | return false; 229 | } 230 | 231 | @Override 232 | public void setPoolable(boolean poolable) throws SQLException { 233 | 234 | } 235 | 236 | @Override 237 | public boolean isPoolable() throws SQLException { 238 | return false; 239 | } 240 | 241 | @Override 242 | public void closeOnCompletion() throws SQLException { 243 | 244 | } 245 | 246 | @Override 247 | public boolean isCloseOnCompletion() throws SQLException { 248 | return false; 249 | } 250 | 251 | @Override 252 | public T unwrap(Class iface) throws SQLException { 253 | return null; 254 | } 255 | 256 | @Override 257 | public boolean isWrapperFor(Class iface) throws SQLException { 258 | return false; 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/utils/BenchmarkUtils.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.utils; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.AWSXRayRecorder; 5 | import com.amazonaws.xray.emitters.Emitter; 6 | import com.amazonaws.xray.entities.Segment; 7 | import com.amazonaws.xray.entities.Subsegment; 8 | import com.amazonaws.xray.strategy.sampling.AllSamplingStrategy; 9 | 10 | public final class BenchmarkUtils { 11 | private BenchmarkUtils() { 12 | } 13 | 14 | /** 15 | * This initializes the static recorder if the agent is not present, and ensures we don't actually emit 16 | * segments regardless of whether or not we're using the agent 17 | * 18 | * @return the configured X-Ray recorder, also retrievable by AWSXRay.getGlobalRecorder 19 | */ 20 | public static AWSXRayRecorder configureXRayRecorder() { 21 | AWSXRayRecorder recorder = AWSXRay.getGlobalRecorder(); 22 | recorder.setEmitter(new NoOpEmitter()); 23 | recorder.setSamplingStrategy(new AllSamplingStrategy()); 24 | return AWSXRay.getGlobalRecorder(); 25 | } 26 | 27 | private static class NoOpEmitter extends Emitter { 28 | @Override 29 | public boolean sendSegment(Segment segment) { 30 | return true; 31 | } 32 | 33 | @Override 34 | public boolean sendSubsegment(Subsegment subsegment) { 35 | return true; 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/utils/ClientProvider.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.utils; 2 | 3 | import com.amazonaws.ClientConfiguration; 4 | import com.amazonaws.auth.AWSCredentialsProvider; 5 | import com.amazonaws.auth.AWSStaticCredentialsProvider; 6 | import com.amazonaws.auth.BasicAWSCredentials; 7 | import com.amazonaws.client.builder.AwsClientBuilder; 8 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; 9 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; 10 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; 11 | import com.amazonaws.xray.AWSXRay; 12 | import com.amazonaws.xray.AWSXRayRecorder; 13 | import com.amazonaws.xray.handlers.TracingHandler; 14 | import com.amazonaws.xray.interceptors.TracingInterceptor; 15 | import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter; 16 | import com.amazonaws.xray.proxies.apache.http.HttpClientBuilder; 17 | import org.apache.http.impl.client.CloseableHttpClient; 18 | import org.apache.http.impl.client.HttpClients; 19 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; 20 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; 21 | import software.amazon.awssdk.core.client.builder.SdkClientBuilder; 22 | import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; 23 | import software.amazon.awssdk.regions.Region; 24 | import software.amazon.awssdk.services.dynamodb.DynamoDbClient; 25 | 26 | import javax.servlet.http.HttpServlet; 27 | import javax.servlet.http.HttpServletRequest; 28 | import javax.servlet.http.HttpServletResponse; 29 | import java.net.URI; 30 | import java.time.Duration; 31 | 32 | /** 33 | * Helper class to create various types of instrumented and non-instrumented clients for use in benchmark tests, 34 | * so that we can ensure the tests are exactly the same and the only variable is the type (or lack) of instrumentation 35 | * used. 36 | */ 37 | public final class ClientProvider { 38 | private static final String ENDPOINT = "http://localhost:20808"; 39 | 40 | public static CloseableHttpClient normalApacheHttpClient() { 41 | return HttpClients.createDefault(); 42 | } 43 | 44 | public static CloseableHttpClient instrumentedApacheHttpClient() { 45 | return HttpClientBuilder.create().build(); 46 | } 47 | 48 | public static HttpServlet normalHttpServlet() { 49 | return new NormalServlet(); 50 | } 51 | 52 | public static HttpServlet instrumentedHttpServlet() { 53 | return new InstrumentedServlet(); 54 | } 55 | 56 | public static AmazonDynamoDB normalV1Client() { 57 | return (AmazonDynamoDB) getTestableV1Client(AmazonDynamoDBClientBuilder.standard()).build(); 58 | } 59 | 60 | public static AmazonDynamoDB instrumentedV1Client(AWSXRayRecorder recorder) { 61 | return (AmazonDynamoDB) getTestableV1Client(AmazonDynamoDBClientBuilder.standard()) 62 | .withRequestHandlers(new TracingHandler(recorder)) 63 | .build(); 64 | } 65 | 66 | public static DynamoDbClient normalV2Client() { 67 | SdkClientBuilder builder = DynamoDbClient.builder() 68 | .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("x", "x"))) 69 | .region(Region.US_WEST_2); 70 | 71 | return (DynamoDbClient) getTestableV2Client(builder, false).build(); 72 | } 73 | 74 | public static DynamoDbClient instrumentedV2Client() { 75 | SdkClientBuilder builder = DynamoDbClient.builder() 76 | .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("x", "x"))) 77 | .region(Region.US_WEST_2); 78 | 79 | return (DynamoDbClient) getTestableV2Client(builder, true).build(); 80 | } 81 | 82 | private static AwsClientBuilder getTestableV1Client(AwsClientBuilder builder) { 83 | AWSCredentialsProvider fakeCredentials = new AWSStaticCredentialsProvider(new BasicAWSCredentials("fake", "fake")); 84 | AwsClientBuilder.EndpointConfiguration mockEndpoint = new AwsClientBuilder.EndpointConfiguration(ENDPOINT, "us-west-2"); 85 | ClientConfiguration clientConfiguration = new ClientConfiguration(); 86 | clientConfiguration.setMaxErrorRetry(0); 87 | clientConfiguration.setRequestTimeout(1000); 88 | 89 | return builder 90 | .withEndpointConfiguration(mockEndpoint) 91 | .withCredentials(fakeCredentials) 92 | .withClientConfiguration(clientConfiguration); 93 | } 94 | 95 | private static SdkClientBuilder getTestableV2Client(SdkClientBuilder builder, boolean instrumented) { 96 | ClientOverrideConfiguration.Builder configBuilder = ClientOverrideConfiguration.builder() 97 | .apiCallTimeout(Duration.ofSeconds(1)); 98 | 99 | if (instrumented) { 100 | configBuilder.addExecutionInterceptor(new TracingInterceptor()); 101 | } 102 | 103 | return builder 104 | .overrideConfiguration(configBuilder.build()) 105 | .endpointOverride(URI.create(ENDPOINT)); 106 | } 107 | 108 | /** 109 | * Simple servlet class that just waits 2 milliseconds to service a request then responds. Will be invoked by the "service" 110 | * method, which is instrumented by the Agent. No point in manipulating response since it's a mock. 111 | */ 112 | private static class NormalServlet extends HttpServlet { 113 | @Override 114 | public void doGet(HttpServletRequest request, HttpServletResponse response) { 115 | try { 116 | Thread.sleep(2); 117 | } catch (Exception e) { 118 | } 119 | } 120 | } 121 | 122 | /** 123 | * "Instrumented" servlet class that simulates the X-Ray SDK's filter by calling the pre-filter and post-filter 124 | * methods around the activity of the servlet. 125 | */ 126 | private static class InstrumentedServlet extends HttpServlet { 127 | private AWSXRayServletFilter filter = new AWSXRayServletFilter("Benchmark"); 128 | 129 | @Override 130 | public void doGet(HttpServletRequest request, HttpServletResponse response) { 131 | filter.preFilter(request, response); 132 | 133 | try { 134 | Thread.sleep(2); 135 | } catch (Exception e) { 136 | } 137 | 138 | filter.postFilter(request, response); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/java/com/amazonaws/xray/agent/utils/SimpleJettyServer.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.utils; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import org.eclipse.jetty.server.Server; 5 | import org.eclipse.jetty.servlet.ServletContextHandler; 6 | import org.eclipse.jetty.util.component.AbstractLifeCycle; 7 | 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.net.InetSocketAddress; 13 | 14 | /** 15 | * Utility class used in benchmarking tests to simulate a web server and negate unpredictable network interaction's 16 | * impact on benchmarking results. 17 | * 18 | * Adapted from the OpenTelemetry benchmarking strategy 19 | * https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/benchmark/src/jmh/java/io/opentelemetry/benchmark/classes/HttpClass.java 20 | */ 21 | public final class SimpleJettyServer { 22 | private SimpleJettyServer() { 23 | } 24 | 25 | public static Server create(int port, String path) { 26 | System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog"); 27 | System.setProperty("org.eclipse.jetty.LEVEL", "WARN"); 28 | Server jettyServer = new Server(new InetSocketAddress("localhost", port)); 29 | ServletContextHandler servletContext = new ServletContextHandler(); 30 | 31 | try { 32 | servletContext.addServlet(MyServlet.class, path); 33 | jettyServer.setHandler(servletContext); 34 | jettyServer.start(); 35 | 36 | // Make sure the Server has started 37 | while (!AbstractLifeCycle.STARTED.equals(jettyServer.getState())) { 38 | Thread.sleep(500); 39 | } 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | 44 | return jettyServer; 45 | } 46 | 47 | public static class MyServlet extends HttpServlet { 48 | /** 49 | * Handles vanilla HTTP requests from Apache HTTP client benchmarks 50 | */ 51 | @Override 52 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { 53 | try { 54 | Thread.sleep(2); 55 | } catch (Exception e) { 56 | } 57 | 58 | response.setContentType("application/json"); 59 | response.setStatus(HttpServletResponse.SC_OK); 60 | response.getWriter().println("{ \"status\": \"ok\"}"); 61 | } 62 | 63 | /** 64 | * Handles ListTables requests from AWS SDK benchmarks 65 | */ 66 | @Override 67 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { 68 | try { 69 | Thread.sleep(2); 70 | } catch (Exception e) { 71 | } 72 | 73 | response.setContentType("application/json"); 74 | response.setStatus(HttpServletResponse.SC_OK); 75 | response.addHeader("x-amz-request-id", "12345"); 76 | response.getWriter().println("{\"TableNames\":[\"ATestTable\",\"dynamodb-user\",\"scorekeep-state\",\"scorekeep-user\"]}"); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /aws-xray-agent-benchmark/src/jmh/resources/com/amazonaws/xray/agent/agent-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "traceIncomingRequests": false 3 | } -------------------------------------------------------------------------------- /aws-xray-agent-plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | plugins { 4 | `java` 5 | `maven-publish` 6 | id("com.github.johnrengelman.shadow") 7 | } 8 | 9 | description = "AWS X-Ray Java Agent as a DiSCo Plugin" 10 | 11 | dependencies { 12 | // Runtime dependencies are those that we will pull in to create the X-Ray Agent Plugin jar 13 | // We pull in the latest version of the X-Ray SDK, its transitives, and other runtime deps for use by the agent. 14 | runtimeOnly("com.amazonaws:aws-xray-recorder-sdk-core") 15 | runtimeOnly("com.blogspot.mydailyjava:weak-lock-free:0.18") 16 | 17 | // Setting isTransitive to false ensures we do not pull in any transitive dependencies of these modules 18 | // and pollute our JAR with them 19 | val nonTransitiveDeps = listOf( 20 | "com.amazonaws:aws-xray-recorder-sdk-aws-sdk", 21 | "com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2", 22 | "com.amazonaws:aws-xray-recorder-sdk-aws-sdk-core", 23 | "com.amazonaws:aws-xray-recorder-sdk-sql" 24 | ) 25 | 26 | nonTransitiveDeps.forEach { 27 | runtimeOnly(it) { 28 | isTransitive = false 29 | } 30 | } 31 | 32 | // Project dependency that contains the actual source code of the X-Ray agent plugin 33 | runtimeOnly(project(":aws-xray-agent")) { 34 | isTransitive = false 35 | } 36 | 37 | testImplementation("org.powermock:powermock-api-mockito2:2.0.7") 38 | testImplementation("org.powermock:powermock-module-junit4:2.0.7") 39 | testImplementation("com.github.tomakehurst:wiremock-jre8:2.27.0") 40 | 41 | testImplementation("com.amazonaws:aws-xray-recorder-sdk-core") 42 | testImplementation("com.amazonaws:aws-xray-recorder-sdk-sql") 43 | 44 | // These Disco artifacts will be packaged into the final X-Ray Agent distribution 45 | testImplementation("software.amazon.disco:disco-java-agent") 46 | testImplementation("software.amazon.disco:disco-java-agent-aws-plugin") 47 | testImplementation("software.amazon.disco:disco-java-agent-web-plugin") 48 | testImplementation("software.amazon.disco:disco-java-agent-sql-plugin") 49 | testImplementation("software.amazon.disco:disco-java-agent-api") 50 | 51 | testImplementation("com.amazonaws:aws-java-sdk-dynamodb") 52 | testImplementation("com.amazonaws:aws-java-sdk-lambda") 53 | testImplementation("com.amazonaws:aws-java-sdk-s3") 54 | testImplementation("com.amazonaws:aws-java-sdk-sqs") 55 | testImplementation("com.amazonaws:aws-java-sdk-sns") 56 | testImplementation("software.amazon.awssdk:dynamodb") 57 | testImplementation("software.amazon.awssdk:lambda") 58 | testImplementation("software.amazon.awssdk:s3") 59 | testImplementation("javax.servlet:javax.servlet-api:3.1.0") 60 | } 61 | 62 | tasks { 63 | shadowJar { 64 | // Decorate this artifact to indicate it is a Disco plugin 65 | manifest { 66 | attributes(mapOf( 67 | "Disco-Init-Class" to "com.amazonaws.xray.agent.runtime.AgentRuntimeLoader" 68 | )) 69 | } 70 | } 71 | 72 | // Copies Disco agent into our lib for convenience 73 | register("copyAgent") { 74 | val discoVer = rootProject.extra["discoVersion"] 75 | 76 | dependsOn(configurations.testRuntimeClasspath) 77 | from(configurations.testRuntimeClasspath.get()) 78 | include("disco-java-agent-$discoVer.jar") 79 | 80 | into("$buildDir/libs/disco") 81 | rename("disco-java-agent-$discoVer.jar", "disco-java-agent.jar") 82 | } 83 | 84 | // JARs are just archives, so we can unzip it to a tmp folder 85 | register("unzipAgent") { 86 | from(zipTree("$buildDir/libs/disco/disco-java-agent.jar")) 87 | into("$buildDir/libs/tmp") 88 | 89 | dependsOn("copyAgent") 90 | } 91 | 92 | // Inspect and rewrite the manifest in the tmp folder 93 | register("rewriteManifest") { 94 | val discoVer = rootProject.extra["discoVersion"] 95 | 96 | // Reads the old manifest with versioned jar, then rewrites the manifest with replaced jar name 97 | doFirst { 98 | val oldManifest: List = File("$buildDir/libs/tmp/META-INF/MANIFEST.MF").readLines() 99 | File("$buildDir/libs/tmp/META-INF/MANIFEST.MF").printWriter().use { out -> 100 | oldManifest.map { 101 | it.replace("disco-java-agent-$discoVer.jar", "disco-java-agent.jar") 102 | }.forEach { 103 | out.println(it) 104 | } 105 | } 106 | } 107 | 108 | dependsOn("unzipAgent") 109 | } 110 | 111 | // Re-zip the tmp folder into the new agent JAR and overwrite the agent JAR with the old manifest 112 | register("rezipAgent") { 113 | archiveFileName.set("disco-java-agent.jar") 114 | destinationDirectory.set(file("$buildDir/libs/disco")) 115 | from("$buildDir/libs/tmp") 116 | 117 | dependsOn("rewriteManifest") 118 | } 119 | 120 | register("copyPlugins") { 121 | val discoVer = rootProject.extra["discoVersion"] 122 | 123 | dependsOn(configurations.testRuntimeClasspath) 124 | from(configurations.testRuntimeClasspath.get()) 125 | include("disco-java-agent-*-plugin-$discoVer.jar") 126 | 127 | rename("(.+)-$discoVer(.+)", "$1$2") 128 | into("$buildDir/libs/disco/disco-plugins") 129 | } 130 | 131 | register("copyXRay") { 132 | dependsOn("shadowJar") 133 | from("$buildDir/libs") 134 | 135 | val regexSafeVersion: String = version.toString().replace("+", "\\+") 136 | include("aws-xray-agent-plugin-$version.jar") 137 | rename("(.+)-$regexSafeVersion(.+)", "$1$2") 138 | 139 | into("$buildDir/libs/disco/disco-plugins") 140 | } 141 | 142 | // The only tests that run in this module are integration tests, so configure them as the standard test task 143 | test { 144 | // Explicitly remove all disco plugins from the classpath since a customer's 145 | // application (which the integ tests simulate) should not be aware of any of those JARs 146 | classpath = classpath.filter { 147 | !(it.name.contains("disco-java-agent") 148 | || it.name.contains("aws-xray-recorder-sdk-aws-sdk") 149 | || it.name.contains("aws-xray-agent")) 150 | } 151 | 152 | // Integration tests run on Windows and Unix in GitHub actions 153 | jvmArgs("-javaagent:$buildDir/libs/disco/disco-java-agent.jar=pluginPath=$buildDir/libs/disco/disco-plugins:loggerfactory=software.amazon.disco.agent.reflect.logging.StandardOutputLoggerFactory", 154 | "-Dcom.amazonaws.xray.strategy.tracingName=IntegTest") 155 | 156 | // Cannot run tests until agent and all plugins are available 157 | dependsOn(withType()) 158 | dependsOn(named("rezipAgent")) 159 | finalizedBy("createAgentZip") 160 | } 161 | 162 | build { 163 | // Cannot run tests until agent and all plugins are available 164 | dependsOn(withType()) 165 | dependsOn(named("rezipAgent")) 166 | finalizedBy("createAgentZip") 167 | } 168 | 169 | register("createAgentZip") { 170 | archiveFileName.set("xray-agent.zip") 171 | destinationDirectory.set(file("$buildDir/dist")) 172 | from("$buildDir/libs") 173 | include("disco/**") 174 | 175 | dependsOn(withType()) 176 | dependsOn(named("rezipAgent")) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /aws-xray-agent-plugin/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/SqlHandlerIntegTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.agent.runtime.handlers.downstream.source.sql.MyStatementImpl; 5 | import com.amazonaws.xray.entities.Namespace; 6 | import com.amazonaws.xray.entities.Subsegment; 7 | import com.amazonaws.xray.sql.SqlSubsegments; 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.mockito.Mock; 12 | import org.mockito.MockitoAnnotations; 13 | import org.mockito.invocation.InvocationOnMock; 14 | import org.mockito.stubbing.Answer; 15 | 16 | import java.sql.CallableStatement; 17 | import java.sql.Connection; 18 | import java.sql.DatabaseMetaData; 19 | import java.sql.PreparedStatement; 20 | import java.sql.SQLException; 21 | import java.sql.Statement; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 25 | import static org.mockito.Mockito.when; 26 | 27 | /** 28 | * Integ testing class for SQL calls. We use a stubbed out implementation of the JDBC Statement classes rather 29 | * than mocks because mocking them interferes with Disco interception of their methods. 30 | */ 31 | public class SqlHandlerIntegTest { 32 | private static final String QUERY = "SQL"; 33 | private static final String DB = "MY_DB"; 34 | private static final String DB_URL = "http://example.com"; 35 | private static final String DOMAIN = "example.com"; 36 | 37 | private Statement statement; 38 | 39 | @Mock 40 | private PreparedStatement preparedStatement; 41 | 42 | @Mock 43 | private CallableStatement callableStatement; 44 | 45 | @Mock 46 | private Connection mockConnection; 47 | 48 | @Mock 49 | private DatabaseMetaData mockMetaData; 50 | 51 | @Before 52 | public void setup() throws SQLException { 53 | MockitoAnnotations.initMocks(this); 54 | 55 | when(mockConnection.getCatalog()).thenReturn(DB); 56 | when(mockConnection.getMetaData()).thenReturn(mockMetaData); 57 | 58 | when(preparedStatement.getConnection()).thenReturn(mockConnection); 59 | when(callableStatement.getConnection()).thenReturn(mockConnection); 60 | 61 | when(mockMetaData.getURL()).thenReturn(DB_URL); 62 | when(mockMetaData.getUserName()).thenReturn("user"); 63 | when(mockMetaData.getDriverVersion()).thenReturn("1.0"); 64 | when(mockMetaData.getDatabaseProductName()).thenReturn("MySQL"); 65 | when(mockMetaData.getDatabaseProductVersion()).thenReturn("2.0"); 66 | 67 | statement = new MyStatementImpl(mockConnection); 68 | 69 | AWSXRay.beginSegment("test"); 70 | } 71 | 72 | @After 73 | public void cleanup() { 74 | AWSXRay.clearTraceEntity(); 75 | } 76 | 77 | @Test 78 | public void testStatementCaptured() throws SQLException { 79 | statement.executeQuery(QUERY); 80 | 81 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 82 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 83 | verifySubsegment(sub); 84 | } 85 | 86 | @Test 87 | public void testPreparedStatementCaptured() throws SQLException { 88 | preparedStatement.execute(); 89 | 90 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 91 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 92 | verifySubsegment(sub); 93 | } 94 | 95 | @Test 96 | public void testCallableStatementCaptured() throws SQLException { 97 | callableStatement.execute(); 98 | 99 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 100 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 101 | verifySubsegment(sub); 102 | } 103 | 104 | @Test 105 | public void testSeveralQueriesOnStatement() throws SQLException { 106 | statement.execute(QUERY); 107 | statement.executeUpdate(QUERY); 108 | statement.executeQuery(QUERY); 109 | statement.executeLargeUpdate(QUERY); 110 | 111 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(4); 112 | 113 | for (Subsegment sub : AWSXRay.getCurrentSegment().getSubsegments()) { 114 | verifySubsegment(sub); 115 | } 116 | } 117 | 118 | @Test 119 | public void testExceptionIsRecordedAndThrown() { 120 | assertThatThrownBy(() -> { 121 | statement.executeUpdate(QUERY, 0); // Implemented to throw exception 122 | }).isInstanceOf(SQLException.class); 123 | 124 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 125 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 126 | verifySubsegment(sub); 127 | assertThat(sub.getCause().getExceptions()).hasSize(1); 128 | } 129 | 130 | @Test 131 | public void testInternalQueriesDontGetCaptured() throws SQLException { 132 | // Will be called by SqlSubsegments.forQuery 133 | String user = "username"; 134 | when(mockMetaData.getUserName()).thenAnswer(new AnswerUsingQuery(statement, user)); 135 | 136 | statement.executeQuery(QUERY); 137 | 138 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 139 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 140 | assertThat(sub.getSql()).containsEntry(SqlSubsegments.USER, user); 141 | verifySubsegment(sub); 142 | } 143 | 144 | private void verifySubsegment(Subsegment sub) { 145 | assertThat(sub.getName()).isEqualTo(DB + "@" + DOMAIN); 146 | assertThat(sub.getNamespace()).isEqualTo(Namespace.REMOTE.toString()); 147 | assertThat(sub.getSql()).containsEntry(SqlSubsegments.URL, DB_URL); // checking an arbitrary field in SQL namespace 148 | assertThat(sub.isInProgress()).isFalse(); 149 | } 150 | 151 | /** 152 | * "Helper" class to simulate a getUserName() method whose internal implementation makes a query 153 | */ 154 | private static class AnswerUsingQuery implements Answer { 155 | private final Statement statement; 156 | private final String user; 157 | 158 | AnswerUsingQuery(Statement statement, String user) { 159 | this.statement = statement; 160 | this.user = user; 161 | } 162 | 163 | @Override 164 | public String answer(InvocationOnMock invocationOnMock) throws Throwable { 165 | statement.executeQuery("SELECT USER"); 166 | return user; 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /aws-xray-agent-plugin/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/SqlPrepareHandlerIntegTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.agent.runtime.handlers.downstream.source.sql.MyConnectionImpl; 5 | import com.amazonaws.xray.entities.Subsegment; 6 | import com.amazonaws.xray.sql.SqlSubsegments; 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | 13 | import java.sql.CallableStatement; 14 | import java.sql.Connection; 15 | import java.sql.DatabaseMetaData; 16 | import java.sql.PreparedStatement; 17 | import java.sql.SQLException; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.mockito.Mockito.when; 21 | 22 | 23 | public class SqlPrepareHandlerIntegTest { 24 | private static final String SQL = "SELECT * FROM my_table"; 25 | private Connection connection; 26 | 27 | @Mock 28 | private PreparedStatement preparedStatement; 29 | 30 | @Mock 31 | private CallableStatement callableStatement; 32 | 33 | @Mock 34 | private DatabaseMetaData mockMetadata; 35 | 36 | @Before 37 | public void setup() throws SQLException { 38 | MockitoAnnotations.initMocks(this); 39 | connection = new MyConnectionImpl(preparedStatement, callableStatement, mockMetadata); 40 | when(preparedStatement.getConnection()).thenReturn(connection); 41 | when(preparedStatement.toString()).thenReturn(null); 42 | when(callableStatement.getConnection()).thenReturn(connection); 43 | when(callableStatement.toString()).thenReturn(null); 44 | when(mockMetadata.getURL()).thenReturn("http://example.com"); 45 | when(mockMetadata.getUserName()).thenReturn("user"); 46 | when(mockMetadata.getDriverVersion()).thenReturn("1.0"); 47 | when(mockMetadata.getDatabaseProductName()).thenReturn("MySQL"); 48 | when(mockMetadata.getDatabaseProductVersion()).thenReturn("2.0"); 49 | 50 | AWSXRay.beginSegment("test"); 51 | } 52 | 53 | @After 54 | public void cleanup() { 55 | AWSXRay.clearTraceEntity(); 56 | } 57 | 58 | @Test 59 | public void testPreparedStatementQueryCaptured() throws SQLException { 60 | connection.prepareStatement(SQL); // insert into map 61 | preparedStatement.execute(); 62 | 63 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 64 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 65 | assertThat(sub.getSql()).containsEntry(SqlSubsegments.SANITIZED_QUERY, SQL); 66 | } 67 | 68 | @Test 69 | public void testCallableStatementQueryCaptured() throws SQLException { 70 | connection.prepareCall(SQL); // insert into map 71 | callableStatement.execute(); 72 | 73 | assertThat(AWSXRay.getCurrentSegment().getSubsegments()).hasSize(1); 74 | Subsegment sub = AWSXRay.getCurrentSegment().getSubsegments().get(0); 75 | assertThat(sub.getSql()).containsEntry(SqlSubsegments.SANITIZED_QUERY, SQL); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /aws-xray-agent-plugin/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/source/http/MockHttpClient.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream.source.http; 2 | 3 | import com.amazonaws.http.apache.client.impl.ConnectionManagerAwareHttpClient; 4 | import org.apache.http.HttpHost; 5 | import org.apache.http.HttpRequest; 6 | import org.apache.http.HttpResponse; 7 | import org.apache.http.HttpVersion; 8 | import org.apache.http.client.ClientProtocolException; 9 | import org.apache.http.client.ResponseHandler; 10 | import org.apache.http.client.methods.HttpUriRequest; 11 | import org.apache.http.conn.ClientConnectionManager; 12 | import org.apache.http.conn.HttpClientConnectionManager; 13 | import org.apache.http.entity.BasicHttpEntity; 14 | import org.apache.http.impl.io.EmptyInputStream; 15 | import org.apache.http.message.BasicHttpResponse; 16 | import org.apache.http.message.BasicStatusLine; 17 | import org.apache.http.params.HttpParams; 18 | import org.apache.http.protocol.HttpContext; 19 | 20 | import java.io.ByteArrayInputStream; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.nio.charset.StandardCharsets; 24 | 25 | /** 26 | * TODO: When Disco removes its data accessor pattern in a future version, delete this & use a mock instead 27 | */ 28 | public class MockHttpClient implements ConnectionManagerAwareHttpClient { 29 | private String responseContent; 30 | private String responseRequestIdHeaderValue; 31 | 32 | private HttpUriRequest lastRequest; // Hacky way of spying on the last made request 33 | 34 | public void setResponseContent(String responseContent) { 35 | this.responseContent = responseContent; 36 | } 37 | 38 | public void setResponseRequestIdHeaderValue(String responseRequestId) { 39 | this.responseRequestIdHeaderValue = responseRequestId; 40 | } 41 | 42 | public HttpUriRequest getLastRequest() { 43 | return lastRequest; 44 | } 45 | 46 | @Override 47 | public HttpClientConnectionManager getHttpClientConnectionManager() { 48 | return null; 49 | } 50 | 51 | @Override 52 | public HttpParams getParams() { 53 | return null; 54 | } 55 | 56 | @Override 57 | public ClientConnectionManager getConnectionManager() { 58 | return null; 59 | } 60 | 61 | @Override 62 | public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException, ClientProtocolException { 63 | return null; 64 | } 65 | 66 | @Override 67 | public HttpResponse execute(HttpUriRequest httpUriRequest, HttpContext httpContext) throws IOException, ClientProtocolException { 68 | this.lastRequest = httpUriRequest; 69 | HttpResponse httpResponse = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK")); 70 | BasicHttpEntity responseBody = new BasicHttpEntity(); 71 | InputStream in = EmptyInputStream.INSTANCE; 72 | if(null != responseContent && !responseContent.isEmpty()) { 73 | in = new ByteArrayInputStream(responseContent.getBytes(StandardCharsets.UTF_8)); 74 | } 75 | responseBody.setContent(in); 76 | httpResponse.setEntity(responseBody); 77 | if (responseRequestIdHeaderValue != null) { 78 | httpResponse.setHeader("x-amzn-RequestId", responseRequestIdHeaderValue); 79 | } 80 | return httpResponse; 81 | } 82 | 83 | @Override 84 | public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest) throws IOException, ClientProtocolException { 85 | return null; 86 | } 87 | 88 | @Override 89 | public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) throws IOException, ClientProtocolException { 90 | return null; 91 | } 92 | 93 | @Override 94 | public T execute(HttpUriRequest httpUriRequest, ResponseHandler responseHandler) throws IOException, ClientProtocolException { 95 | return null; 96 | } 97 | 98 | @Override 99 | public T execute(HttpUriRequest httpUriRequest, ResponseHandler responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException { 100 | return null; 101 | } 102 | 103 | @Override 104 | public T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler responseHandler) throws IOException, ClientProtocolException { 105 | return null; 106 | } 107 | 108 | @Override 109 | public T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException { 110 | return (T) execute((HttpUriRequest) httpRequest, httpContext); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /aws-xray-agent-plugin/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/source/sql/MyStatementImpl.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream.source.sql; 2 | 3 | import java.sql.Connection; 4 | import java.sql.ResultSet; 5 | import java.sql.SQLException; 6 | import java.sql.SQLWarning; 7 | import java.sql.Statement; 8 | 9 | public class MyStatementImpl implements Statement { 10 | public static final String QUERY = "SQL"; 11 | private final Connection connection; 12 | 13 | public MyStatementImpl(Connection connection) { 14 | this.connection = connection; 15 | } 16 | 17 | @Override 18 | public ResultSet executeQuery(String sql) throws SQLException { 19 | return null; 20 | } 21 | 22 | @Override 23 | public int executeUpdate(String sql) throws SQLException { 24 | return 0; 25 | } 26 | 27 | @Override 28 | public void close() throws SQLException { 29 | 30 | } 31 | 32 | @Override 33 | public int getMaxFieldSize() throws SQLException { 34 | return 0; 35 | } 36 | 37 | @Override 38 | public void setMaxFieldSize(int max) throws SQLException { 39 | 40 | } 41 | 42 | @Override 43 | public int getMaxRows() throws SQLException { 44 | return 0; 45 | } 46 | 47 | @Override 48 | public void setMaxRows(int max) throws SQLException { 49 | 50 | } 51 | 52 | @Override 53 | public void setEscapeProcessing(boolean enable) throws SQLException { 54 | 55 | } 56 | 57 | @Override 58 | public int getQueryTimeout() throws SQLException { 59 | return 0; 60 | } 61 | 62 | @Override 63 | public void setQueryTimeout(int seconds) throws SQLException { 64 | 65 | } 66 | 67 | @Override 68 | public void cancel() throws SQLException { 69 | 70 | } 71 | 72 | @Override 73 | public SQLWarning getWarnings() throws SQLException { 74 | return null; 75 | } 76 | 77 | @Override 78 | public void clearWarnings() throws SQLException { 79 | 80 | } 81 | 82 | @Override 83 | public void setCursorName(String name) throws SQLException { 84 | 85 | } 86 | 87 | @Override 88 | public boolean execute(String sql) throws SQLException { 89 | return false; 90 | } 91 | 92 | @Override 93 | public ResultSet getResultSet() throws SQLException { 94 | return null; 95 | } 96 | 97 | @Override 98 | public int getUpdateCount() throws SQLException { 99 | return 0; 100 | } 101 | 102 | @Override 103 | public boolean getMoreResults() throws SQLException { 104 | return false; 105 | } 106 | 107 | @Override 108 | public void setFetchDirection(int direction) throws SQLException { 109 | 110 | } 111 | 112 | @Override 113 | public int getFetchDirection() throws SQLException { 114 | return 0; 115 | } 116 | 117 | @Override 118 | public void setFetchSize(int rows) throws SQLException { 119 | 120 | } 121 | 122 | @Override 123 | public int getFetchSize() throws SQLException { 124 | return 0; 125 | } 126 | 127 | @Override 128 | public int getResultSetConcurrency() throws SQLException { 129 | return 0; 130 | } 131 | 132 | @Override 133 | public int getResultSetType() throws SQLException { 134 | return 0; 135 | } 136 | 137 | @Override 138 | public void addBatch(String sql) throws SQLException { 139 | 140 | } 141 | 142 | @Override 143 | public void clearBatch() throws SQLException { 144 | 145 | } 146 | 147 | @Override 148 | public int[] executeBatch() throws SQLException { 149 | return new int[0]; 150 | } 151 | 152 | @Override 153 | public Connection getConnection() throws SQLException { 154 | return connection; 155 | } 156 | 157 | @Override 158 | public boolean getMoreResults(int current) throws SQLException { 159 | return false; 160 | } 161 | 162 | @Override 163 | public ResultSet getGeneratedKeys() throws SQLException { 164 | return null; 165 | } 166 | 167 | @Override 168 | public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { 169 | throw new SQLException(); 170 | } 171 | 172 | @Override 173 | public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { 174 | return 0; 175 | } 176 | 177 | @Override 178 | public int executeUpdate(String sql, String[] columnNames) throws SQLException { 179 | throw new SQLException(); 180 | } 181 | 182 | @Override 183 | public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { 184 | return false; 185 | } 186 | 187 | @Override 188 | public boolean execute(String sql, int[] columnIndexes) throws SQLException { 189 | return false; 190 | } 191 | 192 | @Override 193 | public boolean execute(String sql, String[] columnNames) throws SQLException { 194 | return false; 195 | } 196 | 197 | @Override 198 | public int getResultSetHoldability() throws SQLException { 199 | return 0; 200 | } 201 | 202 | @Override 203 | public boolean isClosed() throws SQLException { 204 | return false; 205 | } 206 | 207 | @Override 208 | public void setPoolable(boolean poolable) throws SQLException { 209 | 210 | } 211 | 212 | @Override 213 | public boolean isPoolable() throws SQLException { 214 | return false; 215 | } 216 | 217 | @Override 218 | public void closeOnCompletion() throws SQLException { 219 | 220 | } 221 | 222 | @Override 223 | public boolean isCloseOnCompletion() throws SQLException { 224 | return false; 225 | } 226 | 227 | @Override 228 | public long executeLargeUpdate(String sql) throws SQLException { 229 | return 0; 230 | } 231 | 232 | @Override 233 | public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException { 234 | return 0; 235 | } 236 | 237 | @Override 238 | public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException { 239 | return 0; 240 | } 241 | 242 | @Override 243 | public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException { 244 | return 0; 245 | } 246 | 247 | @Override 248 | public T unwrap(Class iface) throws SQLException { 249 | return null; 250 | } 251 | 252 | @Override 253 | public boolean isWrapperFor(Class iface) throws SQLException { 254 | return false; 255 | } 256 | 257 | @Override 258 | public String toString() { 259 | return QUERY; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /aws-xray-agent-plugin/src/test/java/com/amazonaws/xray/agent/runtime/handlers/upstream/source/SimpleHttpServlet.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.upstream.source; 2 | import javax.servlet.http.HttpServlet; 3 | 4 | public class SimpleHttpServlet extends HttpServlet { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /aws-xray-agent-plugin/src/test/resources/xray-agent.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectSqlQueries": true 3 | } 4 | -------------------------------------------------------------------------------- /aws-xray-agent/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java` 3 | `jacoco` 4 | } 5 | 6 | description = "AWS X-Ray Runtime Java Agent" 7 | 8 | dependencies { 9 | implementation("com.amazonaws:aws-xray-recorder-sdk-core") 10 | implementation("com.amazonaws:aws-xray-recorder-sdk-sql") 11 | implementation("com.amazonaws:aws-xray-recorder-sdk-aws-sdk") 12 | implementation("com.amazonaws:aws-xray-recorder-sdk-aws-sdk-core") 13 | implementation("com.amazonaws:aws-xray-recorder-sdk-aws-sdk-v2") 14 | implementation("software.amazon.disco:disco-java-agent-aws-api") 15 | implementation("com.fasterxml.jackson.core:jackson-core") 16 | 17 | implementation("software.amazon.disco:disco-java-agent-core") 18 | implementation("software.amazon.disco:disco-java-agent-web") 19 | implementation("software.amazon.disco:disco-java-agent-aws-api") 20 | implementation("com.blogspot.mydailyjava:weak-lock-free:0.18") 21 | 22 | testImplementation("org.powermock:powermock-api-mockito2:2.0.7") 23 | testImplementation("org.powermock:powermock-module-junit4:2.0.7") 24 | testImplementation("com.github.stefanbirkner:system-rules:1.16.0") 25 | testImplementation("com.amazonaws:aws-java-sdk-dynamodb") 26 | testImplementation("javax.servlet:javax.servlet-api:3.1.0") 27 | testImplementation("commons-io:commons-io:2.7") 28 | 29 | // For reflective Trace ID injection tests 30 | testImplementation("com.amazonaws:aws-xray-recorder-sdk-log4j") 31 | testImplementation("com.amazonaws:aws-xray-recorder-sdk-slf4j") 32 | testImplementation("org.apache.logging.log4j:log4j-api:2.17.0") 33 | testImplementation("ch.qos.logback:logback-classic:1.3.0-alpha5") 34 | } 35 | 36 | tasks.test { 37 | finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run 38 | } 39 | tasks.jacocoTestReport { 40 | dependsOn(tasks.test) // tests are required to run before generating the report 41 | } 42 | 43 | jacoco { 44 | toolVersion = "0.8.6" 45 | } 46 | tasks.jacocoTestReport { 47 | reports { 48 | html.required.set(true) 49 | xml.required.set(true) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/AgentRuntimeLoader.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime; 2 | 3 | import com.amazonaws.xray.agent.runtime.config.XRaySDKConfiguration; 4 | import com.amazonaws.xray.agent.runtime.listeners.ListenerFactory; 5 | import com.amazonaws.xray.agent.runtime.listeners.XRayListenerFactory; 6 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 7 | import org.apache.commons.logging.Log; 8 | import org.apache.commons.logging.LogFactory; 9 | import org.checkerframework.checker.nullness.qual.Nullable; 10 | import software.amazon.disco.agent.event.EventBus; 11 | import software.amazon.disco.agent.event.Listener; 12 | 13 | import java.io.File; 14 | import java.net.MalformedURLException; 15 | import java.net.URL; 16 | 17 | /** 18 | * Bridge between classes residing in the bootstrap classloader or application classloader; 19 | * basically, modules that need to be invoked during application runtime--not the Agent's premain. 20 | */ 21 | public class AgentRuntimeLoader { 22 | private static final String CONFIG_FILE_SYS_PROPERTY = "com.amazonaws.xray.configFile"; 23 | private static final String CONFIG_FILE_DEFAULT_LOCATION = "/xray-agent.json"; 24 | private static final String CONFIG_FILE_SPRING_BOOT_LOCATION = "/BOOT-INF/classes/xray-agent.json"; 25 | 26 | private static final Log log = LogFactory.getLog(AgentRuntimeLoader.class); 27 | private static ListenerFactory listenerFactory = new XRayListenerFactory(); 28 | 29 | // exposed for testing 30 | static void setListenerFactory(ListenerFactory factory) { 31 | listenerFactory = factory; 32 | } 33 | 34 | /** 35 | * Wrapper for main init method used by DiSCo Plugin model. 36 | */ 37 | public static void init() { 38 | init(null); 39 | } 40 | 41 | /** 42 | * Initialize the classes belonging in the runtime. 43 | * @param serviceName - The service name that this agent represents passed from the command line. 44 | */ 45 | public static void init(@Nullable String serviceName) { 46 | if (serviceName != null) { 47 | log.warn("Setting the X-Ray service name via JVM arguments is deprecated. Use the agent's " + 48 | "configuration file instead."); 49 | XRayTransactionState.setServiceName(serviceName); 50 | } 51 | 52 | // Configuration needs to be done before we initialize the listener because its handlers 53 | // rely on X-Ray configurations upon init. 54 | boolean enabled = configureXRay(); 55 | 56 | if (!enabled) { 57 | return; 58 | } 59 | 60 | Listener listener = listenerFactory.generateListener(); 61 | EventBus.addListener(listener); 62 | } 63 | 64 | /** 65 | * Helper method to configure the internal global recorder. It can throw exceptions to interrupt customer's 66 | * code at startup to notify them of invalid configuration rather than assuming defaults which might be unexpected. 67 | */ 68 | private static boolean configureXRay() { 69 | XRaySDKConfiguration configuration = XRaySDKConfiguration.getInstance(); 70 | 71 | URL configFile = getConfigFile(); 72 | if (configFile != null) { 73 | configuration.init(configFile); 74 | } else { 75 | configuration.init(); 76 | } 77 | 78 | return configuration.isEnabled(); 79 | } 80 | 81 | /** 82 | * Helper method to retrieve the xray-agent config file's URL. First checks the provided path on the file system, 83 | * then falls back to checking the system classpath, before giving up and returning null. 84 | * 85 | * @return the URL of config file or null if it wasn't found 86 | * 87 | * Visible for testing 88 | */ 89 | @Nullable 90 | static URL getConfigFile() { 91 | String customLocation = System.getProperty(CONFIG_FILE_SYS_PROPERTY); 92 | if (customLocation != null && !customLocation.isEmpty()) { 93 | try { 94 | File file = new File(customLocation); 95 | if (file.exists()) { 96 | return file.toURI().toURL(); 97 | } else { 98 | return AgentRuntimeLoader.class.getResource(customLocation); 99 | } 100 | } catch (MalformedURLException e) { 101 | log.error("X-Ray agent config file's custom location was malformed. " + 102 | "Falling back to default configuration."); 103 | return null; 104 | } 105 | } 106 | 107 | // Search root of classpath first, then check root of Spring Boot classpath 108 | URL defaultLocation = AgentRuntimeLoader.class.getResource(CONFIG_FILE_DEFAULT_LOCATION); 109 | if (defaultLocation == null) { 110 | defaultLocation = AgentRuntimeLoader.class.getResource(CONFIG_FILE_SPRING_BOOT_LOCATION); 111 | } 112 | return defaultLocation; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/config/InvalidAgentConfigException.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.config; 2 | 3 | public class InvalidAgentConfigException extends RuntimeException { 4 | public InvalidAgentConfigException(String msg) { 5 | super(msg); 6 | } 7 | 8 | public InvalidAgentConfigException(String msg, Throwable err) { 9 | super(msg, err); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/dispatcher/EventDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.dispatcher; 2 | 3 | import com.amazonaws.xray.agent.runtime.handlers.XRayHandlerInterface; 4 | import org.apache.commons.logging.Log; 5 | import org.apache.commons.logging.LogFactory; 6 | import software.amazon.disco.agent.event.Event; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * The dispatcher is the gateway between the listener and the handlers. It acts as the multiplexor 13 | * that delegates events to a handler, based solely on its origin. The event dispatcher should be 14 | * instantiated to represent the downstream or upstream dispatcher. 15 | */ 16 | public class EventDispatcher { 17 | private static final Log log = LogFactory.getLog(EventDispatcher.class); 18 | 19 | /** 20 | * Map that holds a reference between the origin and its handler 21 | */ 22 | private Map originHandlerMap; 23 | 24 | public EventDispatcher() { 25 | originHandlerMap = new HashMap<>(); 26 | } 27 | 28 | /** 29 | * Add a handler for a given origin. This handler is executed when an event is dispatched to it. 30 | * @param origin The event origin that corresponds to the handler 31 | * @param handler The handler that is executed for the given event origin. 32 | */ 33 | public void addHandler(String origin, XRayHandlerInterface handler) { 34 | originHandlerMap.put(origin, handler); 35 | } 36 | 37 | /** 38 | * Helper method to acquire the appropriate handler given the event; the origin is extracted from 39 | * this event to determine which handler to execute. 40 | * @param event Incoming event to acquire the handler. 41 | * @return The handler to execute, otherwise null if no handler exists for the event. 42 | */ 43 | private XRayHandlerInterface getHandler(Event event) { 44 | String eventOrigin = event.getOrigin(); 45 | 46 | XRayHandlerInterface xrayHandler = originHandlerMap.get(eventOrigin); 47 | if (xrayHandler == null && log.isDebugEnabled()) { 48 | log.debug("Unable to retrieve a handler from event " + event.toString() 49 | + " and origin " + event.getOrigin()); 50 | } 51 | return xrayHandler; 52 | 53 | } 54 | 55 | /** 56 | * Dispatches the request event to its corresponding handler if one exists. 57 | * If it doesn't, this method doesn't do anything. 58 | * @param event The request event to dispatch to its underlying handler if one exists 59 | */ 60 | public void dispatchRequestEvent(Event event) { 61 | XRayHandlerInterface xrayHandler = getHandler(event); 62 | if (xrayHandler != null) { 63 | xrayHandler.handleRequest(event); 64 | } 65 | } 66 | 67 | /** 68 | * Dispatches the response event to its corresponding handler if one exists. 69 | * If it doesn't, this method doesn't do anything. 70 | * @param event The response event to dispatch to its underlying handler if one exists 71 | */ 72 | public void dispatchResponseEvent(Event event) { 73 | XRayHandlerInterface xrayHandler = getHandler(event); 74 | if (xrayHandler != null) { 75 | xrayHandler.handleResponse(event); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/handlers/XRayHandlerInterface.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers; 2 | 3 | import software.amazon.disco.agent.event.Event; 4 | 5 | public interface XRayHandlerInterface { 6 | /** 7 | * Handle the incoming request event. The event should be type checked depending on the type of event 8 | * the handler is processing. There isn't a common interface yet that relates request/responses in DiSCo, 9 | * so type checking and handling should be done on a per-handler case. 10 | * @param event The request event dispatched from the dispatcher. 11 | */ 12 | void handleRequest(Event event); 13 | 14 | /** 15 | * Handle the incoming response event. The event should be type checked depending on the type of event 16 | * the handler is processing. There isn't a common interface yet that relates request/responses in DiSCo, 17 | * so type checking and handling should be done on a per-handler case. 18 | * 19 | * Errors resulting from calls made within the interception is passed to the response event. These should be 20 | * taken care of in this method. 21 | * @param event The response event dispatched from the dispatcher. 22 | */ 23 | void handleResponse(Event event); 24 | } 25 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/handlers/downstream/AWSHandler.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.Request; 4 | import com.amazonaws.Response; 5 | import com.amazonaws.xray.agent.runtime.handlers.XRayHandler; 6 | import com.amazonaws.xray.handlers.TracingHandler; 7 | import software.amazon.disco.agent.event.Event; 8 | import software.amazon.disco.agent.event.ServiceRequestEvent; 9 | import software.amazon.disco.agent.event.ServiceResponseEvent; 10 | 11 | import java.net.URL; 12 | 13 | /** 14 | * The AWS handler generates a subsegment from a given AWS downstream service event. 15 | * Due to a limitation in the AWS SDK V1 interceptor, S3 is currently not supported. 16 | */ 17 | public class AWSHandler extends XRayHandler { 18 | private TracingHandler tracingHandler; 19 | 20 | public AWSHandler() { 21 | // We internally re-use our tracing handler from our AWS SDK V1 instrumentor to do all the X-Ray handling. 22 | // The tracing handler's internal call to beforeExecution doesn't need to be done because this agent 23 | // uses its own context for propagating segments using the TransactionContext. 24 | tracingHandler = new TracingHandler(); 25 | } 26 | 27 | public AWSHandler(URL serviceHandlerManifest) { 28 | tracingHandler = new TracingHandler(serviceHandlerManifest); 29 | } 30 | 31 | @Override 32 | public void handleRequest(Event event) { 33 | ServiceRequestEvent requestEvent = (ServiceRequestEvent) event; 34 | Request awsRequest = (Request) requestEvent.getRequest(); 35 | 36 | // Avoid throwing if we can't get the service name because of an old version of AWS SDK 37 | // HTTP handler should pick it up instead. 38 | if (awsRequest.getServiceName() == null) { 39 | return; 40 | } 41 | 42 | tracingHandler.beforeRequest(awsRequest); 43 | } 44 | 45 | @Override 46 | public void handleResponse(Event event) { 47 | ServiceResponseEvent responseEvent = (ServiceResponseEvent) event; 48 | Request awsReq = (Request) responseEvent.getRequest().getRequest(); 49 | Response awsResp = (Response) responseEvent.getResponse(); 50 | 51 | if (responseEvent.getThrown() == null) { 52 | tracingHandler.afterResponse(awsReq, awsResp); 53 | } else { 54 | Throwable exception = responseEvent.getThrown(); 55 | tracingHandler.afterError(awsReq, awsResp, (Exception) exception); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/handlers/downstream/SqlHandler.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.agent.runtime.config.XRaySDKConfiguration; 5 | import com.amazonaws.xray.agent.runtime.handlers.XRayHandler; 6 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 7 | import com.amazonaws.xray.entities.Subsegment; 8 | import com.amazonaws.xray.sql.SqlSubsegments; 9 | import org.apache.commons.logging.Log; 10 | import org.apache.commons.logging.LogFactory; 11 | import software.amazon.disco.agent.concurrent.TransactionContext; 12 | import software.amazon.disco.agent.event.Event; 13 | import software.amazon.disco.agent.event.ServiceDownstreamRequestEvent; 14 | import software.amazon.disco.agent.event.ServiceDownstreamResponseEvent; 15 | 16 | import java.sql.Connection; 17 | import java.sql.PreparedStatement; 18 | import java.sql.SQLException; 19 | import java.sql.Statement; 20 | 21 | /** 22 | * Creates fully populated subsegments to represent downstream SQL queries. 23 | */ 24 | public class SqlHandler extends XRayHandler { 25 | private static final Log log = LogFactory.getLog(SqlHandler.class); 26 | 27 | // Visible for testing 28 | static final String SQL_SUBSEGMENT_COUNT_KEY = "XRaySQLSubsegmentCount"; 29 | 30 | /** 31 | * Uses the JDBC Statement from the Disco event to retrieve metadata about this query. Begins a subsegment 32 | * using that metadata. 33 | * 34 | * @param event The request event dispatched from the dispatcher. 35 | */ 36 | @Override 37 | public void handleRequest(Event event) { 38 | // If a parent SQL transaction is already in progress, we return to avoid an infinite loop. This is because 39 | // in order to populate a SQL subsegment, we make several calls to the JDBC Driver's DatabaseMetaData object. 40 | // For example, if a driver's implementation of DatabaseMetaData.getUserName() uses executeQuery("SELECT USER") 41 | // to get the DB user, executeQuery would be intercepted by the Disco JDBC plugin, trigger this handler to 42 | // create subegment, and we'd call getUserName to populate that subsegment and so on. 43 | if (incrementSqlTransactionCount() > 1) { 44 | return; 45 | } 46 | 47 | ServiceDownstreamRequestEvent requestEvent = (ServiceDownstreamRequestEvent) event; 48 | Statement statement = (Statement) requestEvent.getRequest(); 49 | String queryString = requestEvent.getOperation(); 50 | boolean recordSql = XRaySDKConfiguration.getInstance().shouldCollectSqlQueries(); 51 | final Connection connection; 52 | 53 | try { 54 | connection = statement.getConnection(); 55 | } catch (SQLException e) { 56 | log.debug("Encountered exception when creating subsegment for query of " 57 | + requestEvent.getService() + ", starting blank subsegment", e); 58 | AWSXRay.beginSubsegment(SqlSubsegments.DEFAULT_DATABASE_NAME); 59 | return; 60 | } 61 | 62 | // If the query string wasn't provided by current DiSCo event, check the preparedMap cache 63 | if (queryString == null && statement instanceof PreparedStatement) { 64 | queryString = XRayTransactionState.getPreparedQuery((PreparedStatement) statement); 65 | } 66 | 67 | // If user opted-in to record their Queries, include them in the subsegment 68 | SqlSubsegments.forQuery(connection, recordSql ? queryString : null); 69 | } 70 | 71 | /** 72 | * Closes the subsegment representing this SQL query, including the exception if one was raised. 73 | * 74 | * @param event The response event dispatched from the dispatcher. 75 | */ 76 | @Override 77 | public void handleResponse(Event event) { 78 | // If this SQL request is being ignored, we should also ignore the response 79 | if (decrementSqlTransactionCount() > 0) { 80 | return; 81 | } 82 | 83 | Subsegment subsegment = getSubsegment(); 84 | ServiceDownstreamResponseEvent responseEvent = (ServiceDownstreamResponseEvent) event; 85 | Throwable thrown = responseEvent.getThrown(); 86 | 87 | if (thrown != null) { 88 | subsegment.addException(thrown); 89 | } 90 | endSubsegment(); 91 | } 92 | 93 | // Visible for testing 94 | synchronized int getSqlTransactionCount() { 95 | Integer count = (Integer) TransactionContext.getMetadata(SQL_SUBSEGMENT_COUNT_KEY); 96 | if (count == null) { 97 | count = 0; 98 | setSqlTransactionCount(count); 99 | } 100 | 101 | return count; 102 | } 103 | 104 | private synchronized int incrementSqlTransactionCount() { 105 | int count = getSqlTransactionCount() + 1; 106 | TransactionContext.putMetadata(SQL_SUBSEGMENT_COUNT_KEY, count); 107 | return count; 108 | } 109 | 110 | private synchronized int decrementSqlTransactionCount() { 111 | int count = getSqlTransactionCount() - 1; 112 | TransactionContext.putMetadata(SQL_SUBSEGMENT_COUNT_KEY, count); 113 | return count; 114 | } 115 | 116 | // Visible for testing 117 | synchronized void setSqlTransactionCount(int val) { 118 | TransactionContext.putMetadata(SQL_SUBSEGMENT_COUNT_KEY, val); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/handlers/downstream/SqlPrepareHandler.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.agent.runtime.handlers.XRayHandler; 4 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 5 | import software.amazon.disco.agent.event.Event; 6 | import software.amazon.disco.agent.event.ServiceDownstreamResponseEvent; 7 | 8 | import java.sql.PreparedStatement; 9 | 10 | /** 11 | * This handler processes DiSCo events with origin "SqlPrepare." Such events are emitted when preparing 12 | * a statement or call to a remote SQL server using the {@code connection.prepareStatement()} or 13 | * {@code connection.prepareCall()} JDBC methods. We do NOT generate X-Ray entities here, we just store metadata 14 | * for later use. 15 | */ 16 | public class SqlPrepareHandler extends XRayHandler { 17 | /** 18 | * No-op because we can only meaningfully record the metadata when we have a reference to the returned statement. 19 | * 20 | * @param event The request event dispatched from the dispatcher. 21 | */ 22 | @Override 23 | public void handleRequest(Event event) { 24 | } 25 | 26 | /** 27 | * Stores the captured query string in a static map for later use by the SQL execution handler. 28 | * 29 | * @param event The response event dispatched from the dispatcher. 30 | */ 31 | @Override 32 | public void handleResponse(Event event) { 33 | ServiceDownstreamResponseEvent responseEvent = (ServiceDownstreamResponseEvent) event; 34 | if (responseEvent != null && 35 | responseEvent.getOperation() != null && 36 | responseEvent.getResponse() instanceof PreparedStatement) 37 | { 38 | XRayTransactionState 39 | .putPreparedQuery((PreparedStatement) responseEvent.getResponse(), responseEvent.getOperation()); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/handlers/upstream/ServletHandler.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.upstream; 2 | 3 | import com.amazonaws.xray.agent.runtime.config.XRaySDKConfiguration; 4 | import com.amazonaws.xray.agent.runtime.handlers.XRayHandler; 5 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 6 | import com.amazonaws.xray.entities.Segment; 7 | import com.amazonaws.xray.entities.TraceHeader; 8 | import software.amazon.disco.agent.event.Event; 9 | import software.amazon.disco.agent.event.HttpNetworkProtocolRequestEvent; 10 | import software.amazon.disco.agent.event.HttpServletNetworkRequestEvent; 11 | import software.amazon.disco.agent.event.HttpServletNetworkResponseEvent; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * This handler handles an HttpEvent usually retrieved as a result of servlet interception and generates a segment. 18 | * It populates this segment with HTTP metadata. 19 | */ 20 | public class ServletHandler extends XRayHandler { 21 | private static final String URL_KEY = "url"; 22 | private static final String METHOD_KEY = "method"; 23 | private static final String CLIENT_IP_KEY = "client_ip"; 24 | private static final String USER_AGENT_KEY = "user_agent"; 25 | private static final String FORWARDED_FOR_KEY_LOWER = "x-forwarded-for"; 26 | private static final String FORWARDED_FOR_KEY_UPPER = "X-Forwarded-For"; 27 | private static final String FORWARDED_FOR_ATTRIB = "x_forwarded_for"; 28 | 29 | private static final String RESPONSE_KEY = "response"; 30 | private static final String HTTP_REQUEST_KEY = "request"; 31 | private static final String STATUS_KEY = "status"; 32 | 33 | @Override 34 | public void handleRequest(Event event) { 35 | HttpServletNetworkRequestEvent requestEvent = (HttpServletNetworkRequestEvent) event; 36 | 37 | // For Spring Boot apps, the trace ID injection libraries will not be visible on classpath until after startup, 38 | // so we must try to lazy load them as early as possible 39 | XRaySDKConfiguration.getInstance().lazyLoadTraceIdInjection(getGlobalRecorder()); 40 | 41 | // HttpEvents are seen as servlet invocations, so in every request, we mark that we are serving an Http request 42 | // In X-Ray's context, this means that if we receive a activity event, to start generating a segment. 43 | XRayTransactionState transactionState = getTransactionState(); 44 | addRequestDataToTransactionState(requestEvent, transactionState); 45 | boolean ipForwarded = addClientIPToTransactionState(requestEvent, transactionState); 46 | 47 | // TODO Fix request event bug so that getHeaderData is lower cased. This needs to be case insensitive 48 | // See: https://github.com/awslabs/disco/issues/14 49 | String headerData = requestEvent.getHeaderData(HEADER_KEY.toLowerCase()); 50 | if (headerData == null) { 51 | headerData = requestEvent.getHeaderData(HEADER_KEY); 52 | } 53 | transactionState.withTraceheaderString(headerData); 54 | 55 | TraceHeader traceHeader = TraceHeader.fromString(transactionState.getTraceHeader()); 56 | Segment segment = beginSegment(XRayTransactionState.getServiceName(), traceHeader); 57 | 58 | // Obtain sampling decision 59 | boolean shouldSample = getSamplingDecision(transactionState); 60 | segment.setSampled(shouldSample); 61 | 62 | // Add HTTP Information 63 | Map requestAttributes = new HashMap<>(); 64 | requestAttributes.put(URL_KEY, transactionState.getURL()); 65 | requestAttributes.put(USER_AGENT_KEY, transactionState.getUserAgent()); 66 | requestAttributes.put(METHOD_KEY, transactionState.getMethod()); 67 | requestAttributes.put(CLIENT_IP_KEY, transactionState.getClientIP()); 68 | if (ipForwarded) requestAttributes.put(FORWARDED_FOR_ATTRIB, true); 69 | segment.putHttp(HTTP_REQUEST_KEY, requestAttributes); 70 | } 71 | 72 | @Override 73 | public void handleResponse(Event event) { 74 | HttpServletNetworkResponseEvent responseEvent = (HttpServletNetworkResponseEvent) event; 75 | Segment currentSegment = getSegment(); 76 | 77 | // No need to log since a Context Missing Error will already be recorded 78 | if (currentSegment == null) { 79 | return; 80 | } 81 | 82 | // Add the status code 83 | // Obtain the status code of the underlying http response. If it failed, it's a fault. 84 | Map responseAttributes = new HashMap<>(); 85 | int statusCode = responseEvent.getStatusCode(); 86 | 87 | // Check if the status code was a fault. 88 | switch (statusCode / 100) { 89 | case 2: 90 | // Server OK 91 | break; 92 | case 4: 93 | // Exception 94 | currentSegment.setError(true); 95 | if (statusCode == 429) { 96 | currentSegment.setThrottle(true); 97 | } 98 | break; 99 | case 5: 100 | // Fault 101 | currentSegment.setFault(true); 102 | break; 103 | } 104 | responseAttributes.put(STATUS_KEY, statusCode); 105 | currentSegment.putHttp(RESPONSE_KEY, responseAttributes); 106 | 107 | endSegment(); 108 | } 109 | 110 | /** 111 | * Helper method to put all the relevant Http information from the request event to our transaction state. 112 | * 113 | * @param requestEvent The HttpNetworkProtocolRequestEvent that was captured from the event bus. 114 | * @param transactionState The current XRay transactional state 115 | */ 116 | private void addRequestDataToTransactionState(HttpNetworkProtocolRequestEvent requestEvent, XRayTransactionState transactionState) { 117 | transactionState.withHost(requestEvent.getHost()) 118 | .withMethod(requestEvent.getMethod()) 119 | .withUrl(requestEvent.getURL()) 120 | .withUserAgent(requestEvent.getUserAgent()) 121 | .withTraceheaderString(requestEvent.getHeaderData(HEADER_KEY)); 122 | } 123 | 124 | private boolean addClientIPToTransactionState(HttpNetworkProtocolRequestEvent requestEvent, XRayTransactionState transactionState) { 125 | String clientIP = requestEvent.getHeaderData(FORWARDED_FOR_KEY_UPPER); 126 | boolean forwarded = true; 127 | 128 | if (clientIP == null || clientIP.isEmpty()) { 129 | clientIP = requestEvent.getHeaderData(FORWARDED_FOR_KEY_LOWER); 130 | } 131 | if (clientIP == null || clientIP.isEmpty()) { 132 | clientIP = requestEvent.getRemoteIPAddress(); 133 | forwarded = false; 134 | } 135 | 136 | transactionState.withClientIP(clientIP); 137 | return forwarded; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/listeners/ListenerFactory.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.listeners; 2 | 3 | import software.amazon.disco.agent.event.Listener; 4 | 5 | /** 6 | * Factory interface that produces a listener that can be used by Disco Agents to intercept relevant 7 | * events on the Disco event bus. 8 | */ 9 | public interface ListenerFactory { 10 | 11 | /** 12 | * Creates a Disco Event Bus listener but does not attach it to the event bus. 13 | * 14 | * @return the created Disco listener 15 | */ 16 | Listener generateListener(); 17 | } 18 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/listeners/XRayListener.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.listeners; 2 | 3 | import com.amazonaws.xray.agent.runtime.dispatcher.EventDispatcher; 4 | import org.apache.commons.logging.Log; 5 | import org.apache.commons.logging.LogFactory; 6 | import software.amazon.disco.agent.event.Event; 7 | import software.amazon.disco.agent.event.HttpServletNetworkRequestEvent; 8 | import software.amazon.disco.agent.event.HttpServletNetworkResponseEvent; 9 | import software.amazon.disco.agent.event.Listener; 10 | import software.amazon.disco.agent.event.ServiceEvent; 11 | import software.amazon.disco.agent.event.ServiceRequestEvent; 12 | import software.amazon.disco.agent.event.ServiceResponseEvent; 13 | 14 | public class XRayListener implements Listener { 15 | private static final Log log = LogFactory.getLog(XRayListener.class); 16 | 17 | private final EventDispatcher upstreamEventDispatcher; 18 | private final EventDispatcher downstreamEventDispatcher; 19 | 20 | public XRayListener(EventDispatcher upstreamEventDispatcher, EventDispatcher downstreamEventDispatcher) { 21 | this.upstreamEventDispatcher = upstreamEventDispatcher; 22 | this.downstreamEventDispatcher = downstreamEventDispatcher; 23 | } 24 | 25 | @Override 26 | public int getPriority() { 27 | return 0; 28 | } 29 | 30 | @Override 31 | public void listen(Event event) { 32 | try { 33 | EventDispatcher dispatcher = isEventDownstream(event) ? downstreamEventDispatcher : upstreamEventDispatcher; 34 | 35 | if (event instanceof ServiceRequestEvent || event instanceof HttpServletNetworkRequestEvent) { 36 | dispatcher.dispatchRequestEvent(event); 37 | } else if (event instanceof ServiceResponseEvent || event instanceof HttpServletNetworkResponseEvent) { 38 | dispatcher.dispatchResponseEvent(event); 39 | } else { 40 | // Other events we don't care about so return. 41 | return; 42 | } 43 | } catch (Exception e) { 44 | // We dont want to propagate any exceptions back to the bus nor the application code, so we 45 | // just log it and continue. 46 | log.error("The X-Ray Agent had encountered an unexpected exception for the following event: " 47 | + event.toString(), e); 48 | } 49 | } 50 | 51 | /** 52 | * Use the downstream or upstream event dispatcher depending on the type of event. 53 | * 54 | * Upstream dispatchers are invoked as a result of an incoming request in a service. They generally run handlers 55 | * that generate segments, populate them with request metadata, and end them. 56 | * 57 | * Downstream dispatchers usually deal with events relating to client-sided, send requests and run handlers 58 | * that generate subsegments, populate them with metadata, and then end the subsegments. 59 | */ 60 | private boolean isEventDownstream(Event e) { 61 | if (e instanceof ServiceEvent) { 62 | ServiceEvent serviceEvent = (ServiceEvent) e; 63 | return serviceEvent.getType() == ServiceEvent.Type.DOWNSTREAM; 64 | } 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/listeners/XRayListenerFactory.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.listeners; 2 | 3 | import com.amazonaws.xray.agent.runtime.config.XRaySDKConfiguration; 4 | import com.amazonaws.xray.agent.runtime.dispatcher.EventDispatcher; 5 | import com.amazonaws.xray.agent.runtime.handlers.downstream.AWSHandler; 6 | import com.amazonaws.xray.agent.runtime.handlers.downstream.AWSV2Handler; 7 | import com.amazonaws.xray.agent.runtime.handlers.downstream.HttpClientHandler; 8 | import com.amazonaws.xray.agent.runtime.handlers.downstream.SqlHandler; 9 | import com.amazonaws.xray.agent.runtime.handlers.downstream.SqlPrepareHandler; 10 | import com.amazonaws.xray.agent.runtime.handlers.upstream.ServletHandler; 11 | import software.amazon.disco.agent.event.Listener; 12 | 13 | import java.net.URL; 14 | 15 | /** 16 | * Factory class that produces an X-Ray listener with upstream and downstream dispatchers to intercept relevant 17 | * events on the Disco event bus. It is important to keep this class minimal since we add different handlers 18 | * to the listener based on the environment it's consumed in. 19 | */ 20 | public class XRayListenerFactory implements ListenerFactory { 21 | private static final String AWS_ORIGIN = "AWSv1"; 22 | private static final String AWS_V2_ORIGIN = "AWSv2"; 23 | private static final String APACHE_HTTP_CLIENT_ORIGIN = "ApacheHttpClient"; 24 | private static final String HTTP_SERVLET_ORIGIN = "httpServlet"; 25 | private static final String SQL_ORIGIN = "SQL"; 26 | private static final String SQL_PREPARE_ORIGIN = "SqlPrepare"; 27 | 28 | private static URL manifest; 29 | private static int configVersion; 30 | 31 | /** 32 | * Creates a Disco Event Bus listener with upstream and downstream event dispatchers that have handlers 33 | * for each event type that the X-Ray Agent supports. 34 | * 35 | * @return An X-Ray Agent listener 36 | */ 37 | @Override 38 | public Listener generateListener() { 39 | manifest = XRaySDKConfiguration.getInstance().getAwsServiceHandlerManifest(); 40 | configVersion = XRaySDKConfiguration.getInstance().getAwsSdkVersion(); 41 | 42 | EventDispatcher upstreamEventDispatcher = new EventDispatcher(); 43 | 44 | if (XRaySDKConfiguration.getInstance().isTraceIncomingRequests()) { 45 | upstreamEventDispatcher.addHandler(HTTP_SERVLET_ORIGIN, new ServletHandler()); 46 | } 47 | 48 | EventDispatcher downstreamEventDispatcher = new EventDispatcher(); 49 | downstreamEventDispatcher.addHandler(APACHE_HTTP_CLIENT_ORIGIN, new HttpClientHandler()); 50 | downstreamEventDispatcher.addHandler(SQL_ORIGIN, new SqlHandler()); 51 | downstreamEventDispatcher.addHandler(SQL_PREPARE_ORIGIN, new SqlPrepareHandler()); 52 | 53 | if (configVersion == 1 && manifest != null) { 54 | downstreamEventDispatcher.addHandler(AWS_ORIGIN, new AWSHandler(manifest)); 55 | } else { 56 | downstreamEventDispatcher.addHandler(AWS_ORIGIN, new AWSHandler()); 57 | } 58 | 59 | if (configVersion == 2 && manifest != null) { 60 | downstreamEventDispatcher.addHandler(AWS_V2_ORIGIN, new AWSV2Handler(manifest)); 61 | } else { 62 | downstreamEventDispatcher.addHandler(AWS_V2_ORIGIN, new AWSV2Handler()); 63 | } 64 | 65 | return new XRayListener(upstreamEventDispatcher, downstreamEventDispatcher); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/models/XRayTransactionContext.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.models; 2 | 3 | import com.amazonaws.xray.AWSXRayRecorder; 4 | import com.amazonaws.xray.contexts.SegmentContext; 5 | import com.amazonaws.xray.entities.Entity; 6 | import com.amazonaws.xray.entities.Segment; 7 | import com.amazonaws.xray.entities.Subsegment; 8 | import com.amazonaws.xray.entities.SubsegmentImpl; 9 | import com.amazonaws.xray.exceptions.SegmentNotFoundException; 10 | import com.amazonaws.xray.exceptions.SubsegmentNotFoundException; 11 | import com.amazonaws.xray.listeners.SegmentListener; 12 | import org.apache.commons.logging.Log; 13 | import org.apache.commons.logging.LogFactory; 14 | import org.checkerframework.checker.nullness.qual.Nullable; 15 | import software.amazon.disco.agent.concurrent.TransactionContext; 16 | 17 | /** 18 | * X-Ray-friendly context that utilizes the TransactionContext object to propagate across thread boundaries. This context 19 | * is used by the global recorder to maintain segments and subsegments. 20 | */ 21 | public class XRayTransactionContext implements SegmentContext { 22 | private static final String XRAY_ENTITY_KEY = "DiscoXRayEntity"; 23 | private static final Log log = LogFactory.getLog(XRayTransactionContext.class); 24 | 25 | // Transaction Context approach. 26 | @Nullable 27 | public Entity getTraceEntity() { 28 | return (Entity) TransactionContext.getMetadata(XRAY_ENTITY_KEY); 29 | } 30 | 31 | public void setTraceEntity(@Nullable Entity entity) { 32 | if (entity != null && entity.getCreator() != null) { 33 | for (SegmentListener l : entity.getCreator().getSegmentListeners()) { 34 | if (l != null) { 35 | l.onSetEntity((Entity) TransactionContext.getMetadata(XRAY_ENTITY_KEY), entity); 36 | } 37 | } 38 | } 39 | 40 | TransactionContext.putMetadata(XRAY_ENTITY_KEY, entity); 41 | } 42 | 43 | public void clearTraceEntity() { 44 | Entity oldEntity = (Entity) TransactionContext.getMetadata(XRAY_ENTITY_KEY); 45 | if (oldEntity != null && oldEntity.getCreator() != null) { 46 | for (SegmentListener l : oldEntity.getCreator().getSegmentListeners()) { 47 | if (l != null) { 48 | l.onClearEntity(oldEntity); 49 | } 50 | } 51 | } 52 | 53 | TransactionContext.putMetadata(XRAY_ENTITY_KEY, null); 54 | } 55 | 56 | @Override 57 | public Subsegment beginSubsegment(AWSXRayRecorder recorder, String name) { 58 | Entity current = getTraceEntity(); 59 | if (null == current) { 60 | recorder.getContextMissingStrategy().contextMissing("Failed to begin subsegment named '" + name + "': segment cannot be found.", SegmentNotFoundException.class); 61 | return Subsegment.noOp(recorder); 62 | } 63 | if (log.isDebugEnabled()) { 64 | log.debug("Beginning subsegment named: " + name); 65 | } 66 | Segment parentSegment = getTraceEntity().getParentSegment(); 67 | Subsegment subsegment = new SubsegmentImpl(recorder, name, parentSegment); 68 | subsegment.setParent(current); 69 | current.addSubsegment(subsegment); 70 | setTraceEntity(subsegment); 71 | return subsegment; 72 | } 73 | 74 | @Override 75 | public void endSubsegment(AWSXRayRecorder recorder) { 76 | Entity current = getTraceEntity(); 77 | if (current instanceof Subsegment) { 78 | if (log.isDebugEnabled()) { 79 | log.debug("Ending subsegment named: " + current.getName()); 80 | } 81 | Subsegment currentSubsegment = (Subsegment) current; 82 | if (currentSubsegment.end()) { 83 | recorder.sendSegment(currentSubsegment.getParentSegment()); 84 | } else { 85 | if (recorder.getStreamingStrategy().requiresStreaming(currentSubsegment.getParentSegment())) { 86 | recorder.getStreamingStrategy().streamSome(currentSubsegment.getParentSegment(), recorder.getEmitter()); 87 | } 88 | setTraceEntity(current.getParent()); 89 | } 90 | } else { 91 | recorder.getContextMissingStrategy().contextMissing("Failed to end subsegment: subsegment cannot be found.", SubsegmentNotFoundException.class); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/models/XRayTransactionContextResolver.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.models; 2 | 3 | import com.amazonaws.xray.contexts.SegmentContext; 4 | import com.amazonaws.xray.contexts.SegmentContextResolver; 5 | 6 | public class XRayTransactionContextResolver implements SegmentContextResolver { 7 | 8 | @Override 9 | public SegmentContext resolve() { 10 | return new XRayTransactionContext(); 11 | } 12 | } -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/models/XRayTransactionState.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.models; 2 | 3 | import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap; 4 | import org.checkerframework.checker.nullness.qual.Nullable; 5 | 6 | import java.sql.PreparedStatement; 7 | 8 | /** 9 | * Contains state information for each logical request/response transaction event. 10 | * 11 | * Events that are captured should capture the relevant information and store it here. 12 | */ 13 | public class XRayTransactionState { 14 | private String host; 15 | private String url; 16 | private String userAgent; 17 | private String clientIP; 18 | private String method; 19 | private String serviceType; // Type of AWS resource running application. 20 | private String traceHeader; 21 | private String origin; 22 | 23 | private static String serviceName; 24 | private static final WeakConcurrentMap preparedStatementMap 25 | = new WeakConcurrentMap.WithInlinedExpunction<>(); 26 | 27 | public XRayTransactionState withHost(String host) { 28 | this.host = host; 29 | return this; 30 | } 31 | 32 | public XRayTransactionState withUrl(String url) { 33 | this.url = url; 34 | return this; 35 | } 36 | 37 | public XRayTransactionState withUserAgent(String userAgent) { 38 | this.userAgent = userAgent; 39 | return this; 40 | } 41 | 42 | public XRayTransactionState withClientIP(String clientIP) { 43 | this.clientIP = clientIP; 44 | return this; 45 | } 46 | 47 | public XRayTransactionState withMethod(String method) { 48 | this.method = method; 49 | return this; 50 | } 51 | 52 | public XRayTransactionState withServiceType(String serviceType) { 53 | this.serviceType = serviceType; 54 | return this; 55 | } 56 | 57 | public XRayTransactionState withTraceheaderString(@Nullable String traceHeaderString) { 58 | this.traceHeader = traceHeaderString; 59 | return this; 60 | } 61 | 62 | public XRayTransactionState withOrigin(@Nullable String origin) { 63 | this.origin = origin; 64 | return this; 65 | } 66 | 67 | public String getHost() { 68 | return this.host; 69 | } 70 | 71 | public String getURL() { 72 | return this.url; 73 | } 74 | 75 | public String getUserAgent() { 76 | return this.userAgent; 77 | } 78 | 79 | public String getClientIP() { 80 | return this.clientIP; 81 | } 82 | 83 | public String getMethod() { 84 | return this.method; 85 | } 86 | 87 | public String getServiceType() { 88 | return this.serviceType; 89 | } 90 | 91 | @Nullable 92 | public String getTraceHeader() { 93 | return this.traceHeader; 94 | } 95 | 96 | @Nullable 97 | public String getOrigin() { 98 | return this.origin; 99 | } 100 | 101 | public static void setServiceName(String inServiceName) { 102 | serviceName = inServiceName; 103 | } 104 | 105 | public static String getServiceName() { 106 | return serviceName; 107 | } 108 | 109 | public static void putPreparedQuery(PreparedStatement ps, String query) { 110 | preparedStatementMap.put(ps, query); 111 | } 112 | 113 | public static String getPreparedQuery(PreparedStatement ps) { 114 | return preparedStatementMap.get(ps); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /aws-xray-agent/src/main/java/com/amazonaws/xray/agent/runtime/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes used for initializing the X-Ray Recorder used by the agent and handling events at runtime. 3 | */ 4 | package com.amazonaws.xray.agent.runtime; -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/AgentRuntimeLoaderTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.AWSXRayRecorderBuilder; 5 | import com.amazonaws.xray.agent.runtime.config.XRaySDKConfiguration; 6 | import com.amazonaws.xray.agent.runtime.listeners.ListenerFactory; 7 | import com.amazonaws.xray.agent.runtime.listeners.XRayListener; 8 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 9 | import org.apache.commons.io.FilenameUtils; 10 | import org.junit.After; 11 | import org.junit.Assert; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | import org.mockito.Mock; 15 | import org.mockito.MockitoAnnotations; 16 | import software.amazon.disco.agent.event.EventBus; 17 | 18 | import java.io.File; 19 | import java.net.URL; 20 | 21 | import static org.mockito.Mockito.when; 22 | 23 | public class AgentRuntimeLoaderTest { 24 | private final String serviceName = "TestService"; 25 | private static final String CONFIG_FILE_SYS_PROPERTY = "com.amazonaws.xray.configFile"; 26 | private static final String CONFIG_FILE_DEFAULT_NAME = "xray-agent.json"; 27 | 28 | @Mock 29 | private XRayListener listenerMock; 30 | 31 | @Mock 32 | private ListenerFactory factoryMock; 33 | 34 | private XRaySDKConfiguration config; 35 | 36 | @Before 37 | public void setup() { 38 | MockitoAnnotations.initMocks(this); 39 | when(factoryMock.generateListener()).thenReturn(listenerMock); 40 | AgentRuntimeLoader.setListenerFactory(factoryMock); 41 | 42 | System.clearProperty(CONFIG_FILE_SYS_PROPERTY); 43 | config = XRaySDKConfiguration.getInstance(); 44 | config.init(null); // resets any static config properties 45 | } 46 | 47 | @After 48 | public void cleanup() { 49 | EventBus.removeAllListeners(); 50 | AWSXRay.setGlobalRecorder(AWSXRayRecorderBuilder.defaultRecorder()); // Refresh this. 51 | } 52 | 53 | @Test 54 | public void testCommandLineNameSet() { 55 | AgentRuntimeLoader.init(serviceName); 56 | 57 | Assert.assertEquals(XRayTransactionState.getServiceName(), serviceName); 58 | } 59 | 60 | @Test 61 | public void testListenerAddedToEventBus() { 62 | AgentRuntimeLoader.init(null); 63 | 64 | Assert.assertTrue(EventBus.isListenerPresent(listenerMock)); 65 | } 66 | 67 | @Test 68 | public void testGetDefaultConfigFile() { 69 | URL configFile = AgentRuntimeLoader.getConfigFile(); 70 | 71 | Assert.assertEquals(CONFIG_FILE_DEFAULT_NAME, FilenameUtils.getName(configFile.getPath())); 72 | } 73 | 74 | @Test 75 | public void testGetCustomConfigFileFromFileSystem() { 76 | String fileName = "emptyAgentConfig.json"; 77 | System.setProperty(CONFIG_FILE_SYS_PROPERTY, 78 | AgentRuntimeLoaderTest.class.getResource("/com/amazonaws/xray/agent/" + fileName).getPath()); 79 | 80 | URL configFile = AgentRuntimeLoader.getConfigFile(); 81 | 82 | Assert.assertEquals(fileName, FilenameUtils.getName(configFile.getPath())); 83 | } 84 | 85 | @Test 86 | public void testGetCustomConfigFileFromClassPath() { 87 | String fileName = "emptyAgentConfig.json"; 88 | System.setProperty(CONFIG_FILE_SYS_PROPERTY, "/com/amazonaws/xray/agent/" + fileName); 89 | 90 | URL configFile = AgentRuntimeLoader.getConfigFile(); 91 | 92 | // Make sure it's not using the file system 93 | Assert.assertFalse(new File("/com/amazonaws/xray/agent/" + fileName).exists()); 94 | Assert.assertEquals(fileName, FilenameUtils.getName(configFile.getPath())); 95 | } 96 | 97 | @Test 98 | public void testNonExistentCustomConfigFile() { 99 | System.setProperty(CONFIG_FILE_SYS_PROPERTY, "/some/totally/fake/file"); 100 | 101 | URL configFile = AgentRuntimeLoader.getConfigFile(); 102 | 103 | Assert.assertNull(configFile); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/config/AgentConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.config; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import java.util.HashMap; 7 | 8 | public class AgentConfigurationTest { 9 | @Test 10 | public void testEmptyMapUsesDefaults() { 11 | AgentConfiguration defaultConfig = new AgentConfiguration(); 12 | AgentConfiguration mapConfig = new AgentConfiguration(new HashMap<>()); 13 | 14 | Assert.assertEquals(defaultConfig, mapConfig); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/dispatcher/EventDispatcherTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.dispatcher; 2 | 3 | import com.amazonaws.xray.agent.runtime.handlers.XRayHandlerInterface; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.mockito.Mock; 8 | import org.powermock.modules.junit4.PowerMockRunner; 9 | import software.amazon.disco.agent.event.ServiceActivityRequestEvent; 10 | import software.amazon.disco.agent.event.ServiceActivityResponseEvent; 11 | import software.amazon.disco.agent.event.ServiceRequestEvent; 12 | 13 | import static org.mockito.Mockito.mock; 14 | import static org.mockito.Mockito.times; 15 | import static org.mockito.Mockito.verify; 16 | 17 | @RunWith(PowerMockRunner.class) 18 | public class EventDispatcherTest { 19 | private final String ORIGIN = "testOrigin"; 20 | private final String SERVICE = "testService"; 21 | private final String OPERATION = "testOperation"; 22 | 23 | @Mock 24 | private XRayHandlerInterface mockHandler; 25 | 26 | private EventDispatcher eventDispatcher; 27 | 28 | @Before 29 | public void setup() { 30 | eventDispatcher = new EventDispatcher(); 31 | eventDispatcher.addHandler(ORIGIN, mockHandler); 32 | } 33 | 34 | @Test 35 | public void testAddHandler() { 36 | String testOrigin = "SOMEORIGIN"; 37 | ServiceRequestEvent serviceRequestEvent = new ServiceActivityRequestEvent(testOrigin, SERVICE, OPERATION); 38 | 39 | eventDispatcher.dispatchRequestEvent(serviceRequestEvent); 40 | verify(mockHandler, times(0)).handleRequest(serviceRequestEvent); 41 | 42 | eventDispatcher.addHandler(testOrigin, mockHandler); 43 | 44 | eventDispatcher.dispatchRequestEvent(serviceRequestEvent); 45 | verify(mockHandler, times(1)).handleRequest(serviceRequestEvent); 46 | } 47 | 48 | @Test 49 | public void testDispatchRequest() { 50 | ServiceActivityRequestEvent serviceRequestEvent = new ServiceActivityRequestEvent(ORIGIN, SERVICE, OPERATION); 51 | eventDispatcher.dispatchRequestEvent(serviceRequestEvent); 52 | verify(mockHandler, times(1)).handleRequest(serviceRequestEvent); 53 | } 54 | 55 | @Test 56 | public void testDispatchResponse() { 57 | ServiceActivityRequestEvent serviceRequestEvent = mock(ServiceActivityRequestEvent.class); 58 | ServiceActivityResponseEvent serviceResponseEvent = new ServiceActivityResponseEvent(ORIGIN, SERVICE, OPERATION, serviceRequestEvent); 59 | eventDispatcher.dispatchResponseEvent(serviceResponseEvent); 60 | verify(mockHandler, times(1)).handleResponse(serviceResponseEvent); 61 | } 62 | 63 | @Test 64 | public void testDispatchNoHandler() { 65 | ServiceActivityRequestEvent serviceRequestEvent = new ServiceActivityRequestEvent("NotUsedOrigin", null, null); 66 | eventDispatcher.dispatchRequestEvent(serviceRequestEvent); 67 | verify(mockHandler, times(0)).handleRequest(serviceRequestEvent); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/handlers/XRayHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.AWSXRayRecorderBuilder; 5 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 6 | import com.amazonaws.xray.entities.TraceHeader; 7 | import com.amazonaws.xray.strategy.sampling.SamplingResponse; 8 | import com.amazonaws.xray.strategy.sampling.SamplingStrategy; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.mockito.Mock; 12 | import org.mockito.MockitoAnnotations; 13 | import software.amazon.disco.agent.event.Event; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | import static org.mockito.ArgumentMatchers.any; 17 | import static org.mockito.Mockito.never; 18 | import static org.mockito.Mockito.times; 19 | import static org.mockito.Mockito.verify; 20 | import static org.mockito.Mockito.when; 21 | 22 | public class XRayHandlerTest { 23 | private FakeHandler fakeHandler; 24 | 25 | @Mock 26 | private SamplingStrategy mockSamplingStrategy; 27 | 28 | @Before 29 | public void setup() { 30 | MockitoAnnotations.initMocks(this); 31 | when(mockSamplingStrategy.shouldTrace(any())).thenReturn(new SamplingResponse()); 32 | fakeHandler = new FakeHandler(); 33 | 34 | AWSXRay.setGlobalRecorder(AWSXRayRecorderBuilder.standard() 35 | .withSamplingStrategy(mockSamplingStrategy) 36 | .build() 37 | ); 38 | 39 | AWSXRay.clearTraceEntity(); 40 | } 41 | 42 | @Test 43 | public void testRespectUpstreamSamplingDecision() { 44 | XRayTransactionState state = new XRayTransactionState(); 45 | TraceHeader header = new TraceHeader(null, null, TraceHeader.SampleDecision.SAMPLED); 46 | state.withTraceheaderString(header.toString()); 47 | boolean decision = fakeHandler.getSamplingDecision(state); 48 | 49 | assertThat(decision).isTrue(); 50 | verify(mockSamplingStrategy, never()).shouldTrace(any()); 51 | } 52 | 53 | @Test 54 | public void testComputeSamplingDecisionForUnknown() { 55 | XRayTransactionState state = new XRayTransactionState(); 56 | fakeHandler.getSamplingDecision(state); 57 | 58 | assertThat(state.getTraceHeader()).isNull(); 59 | verify(mockSamplingStrategy, times((1))).shouldTrace(any()); 60 | } 61 | 62 | private static class FakeHandler extends XRayHandler { 63 | 64 | @Override 65 | public void handleRequest(Event event) { 66 | } 67 | 68 | @Override 69 | public void handleResponse(Event event) { 70 | } 71 | } 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/HttpClientHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.entities.Namespace; 5 | import com.amazonaws.xray.entities.Segment; 6 | import com.amazonaws.xray.entities.Subsegment; 7 | import com.amazonaws.xray.entities.TraceHeader; 8 | import com.amazonaws.xray.entities.TraceID; 9 | import org.junit.After; 10 | import org.junit.Assert; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.powermock.core.classloader.annotations.PowerMockIgnore; 15 | import org.powermock.modules.junit4.PowerMockRunner; 16 | import software.amazon.disco.agent.event.HttpServiceDownstreamRequestEvent; 17 | import software.amazon.disco.agent.event.HttpServiceDownstreamResponseEvent; 18 | 19 | import java.net.URI; 20 | import java.util.Map; 21 | 22 | import static org.mockito.Mockito.spy; 23 | import static org.mockito.Mockito.verify; 24 | 25 | @RunWith(PowerMockRunner.class) 26 | @PowerMockIgnore("javax.net.ssl.*") 27 | public class HttpClientHandlerTest { 28 | private final String ORIGIN = "ApacheHttpClient"; 29 | private final String SERVICE = "https://amazon.com"; 30 | private final String OPERATION = "GET"; 31 | private final int STATUS_CODE = 200; 32 | private final int CONTENT_LENGTH = 48343; 33 | 34 | private HttpClientHandler httpClientHandler; 35 | private Segment parentSegment; 36 | private HttpServiceDownstreamRequestEvent httpClientRequestEvent; 37 | private HttpServiceDownstreamResponseEvent httpClientResponseEvent; 38 | 39 | @Before 40 | public void setup() { 41 | parentSegment = AWSXRay.beginSegment("HttpClientTestSegment"); 42 | httpClientHandler = new HttpClientHandler(); 43 | 44 | httpClientRequestEvent = new HttpServiceDownstreamRequestEvent(ORIGIN, SERVICE, OPERATION); 45 | httpClientRequestEvent.withMethod(OPERATION); 46 | httpClientRequestEvent.withUri(SERVICE); 47 | 48 | httpClientResponseEvent = new HttpServiceDownstreamResponseEvent(ORIGIN, SERVICE, OPERATION, httpClientRequestEvent); 49 | httpClientResponseEvent.withStatusCode(STATUS_CODE); 50 | httpClientResponseEvent.withContentLength(CONTENT_LENGTH); 51 | 52 | } 53 | 54 | @After 55 | public void clean() { 56 | AWSXRay.clearTraceEntity(); 57 | } 58 | 59 | @Test 60 | public void testHandleGetRequest() throws Exception { 61 | HttpServiceDownstreamRequestEvent requestEventSpy = spy(httpClientRequestEvent); 62 | httpClientHandler.handleRequest(requestEventSpy); 63 | 64 | Subsegment httpClientSubsegment = AWSXRay.getCurrentSubsegment(); 65 | Assert.assertEquals(Namespace.REMOTE.toString(), httpClientSubsegment.getNamespace()); 66 | Assert.assertEquals(new URI(SERVICE).getHost(), httpClientSubsegment.getName()); 67 | Assert.assertTrue(httpClientSubsegment.isInProgress()); 68 | 69 | Map requestMap = (Map) httpClientSubsegment.getHttp().get("request"); 70 | Assert.assertEquals(OPERATION, requestMap.get("method")); 71 | 72 | // Trace header check 73 | TraceID traceID = httpClientSubsegment.getParentSegment().getTraceId(); 74 | String parentID = httpClientSubsegment.getId(); 75 | TraceHeader.SampleDecision sampleDecision = parentSegment.isSampled() ? TraceHeader.SampleDecision.SAMPLED : TraceHeader.SampleDecision.NOT_SAMPLED; 76 | TraceHeader theTraceHeader = new TraceHeader(traceID, parentID, sampleDecision); 77 | verify(requestEventSpy).replaceHeader(TraceHeader.HEADER_KEY, theTraceHeader.toString()); 78 | 79 | Assert.assertEquals(parentSegment, httpClientSubsegment.getParentSegment()); 80 | Assert.assertEquals(1, parentSegment.getSubsegments().size()); 81 | } 82 | 83 | @Test 84 | public void testHandleGetResponse() { 85 | Subsegment httpClientSubsegment = AWSXRay.beginSubsegment("responseSubsegment"); 86 | httpClientHandler.handleResponse(httpClientResponseEvent); 87 | 88 | Map responseMap = (Map) httpClientSubsegment.getHttp().get("response"); 89 | Assert.assertFalse(httpClientSubsegment.isInProgress()); 90 | Assert.assertEquals(200,responseMap.get("status")); 91 | Assert.assertEquals(1, parentSegment.getSubsegments().size()); 92 | } 93 | 94 | @Test 95 | public void testHandleInvalidRequest() { 96 | HttpServiceDownstreamResponseEvent failedResponseEvent = new HttpServiceDownstreamResponseEvent(ORIGIN, SERVICE, OPERATION, httpClientRequestEvent); 97 | failedResponseEvent.withStatusCode(500); 98 | failedResponseEvent.withContentLength(1000); 99 | Throwable ourThrowable = new IllegalArgumentException("Some illegal exception"); 100 | failedResponseEvent.withThrown(ourThrowable); 101 | Subsegment httpClientSubsegment = AWSXRay.beginSubsegment("failedResponseSubsegment"); 102 | 103 | httpClientHandler.handleResponse(failedResponseEvent); 104 | Assert.assertTrue(httpClientSubsegment.isFault()); 105 | Assert.assertEquals(1, httpClientSubsegment.getCause().getExceptions().size()); 106 | Assert.assertEquals(ourThrowable, httpClientSubsegment.getCause().getExceptions().get(0).getThrowable()); 107 | } 108 | 109 | @Test 110 | public void testHandle4xxStatusCode() { 111 | httpClientResponseEvent.withStatusCode(400); 112 | Subsegment httpClientSubsegment = AWSXRay.beginSubsegment("failedResponseSubsegment"); 113 | 114 | httpClientHandler.handleResponse(httpClientResponseEvent); 115 | Assert.assertTrue(httpClientSubsegment.isError()); 116 | Assert.assertFalse(httpClientSubsegment.isFault()); 117 | Assert.assertFalse(httpClientSubsegment.isThrottle()); 118 | 119 | Map httpResponseMap = (Map) httpClientSubsegment.getHttp().get("response"); 120 | Assert.assertEquals(400, (int) httpResponseMap.get("status")); 121 | } 122 | 123 | @Test 124 | public void testHandleThrottlingStatusCode() { 125 | httpClientResponseEvent.withStatusCode(429); 126 | Subsegment httpClientSubsegment = AWSXRay.beginSubsegment("failedResponseSubsegment"); 127 | 128 | httpClientHandler.handleResponse(httpClientResponseEvent); 129 | Assert.assertTrue(httpClientSubsegment.isError()); 130 | Assert.assertFalse(httpClientSubsegment.isFault()); 131 | Assert.assertTrue(httpClientSubsegment.isThrottle()); 132 | 133 | Map httpResponseMap = (Map) httpClientSubsegment.getHttp().get("response"); 134 | Assert.assertEquals(429, (int) httpResponseMap.get("status")); 135 | } 136 | 137 | @Test 138 | public void testHandle5xxStatusCode() { 139 | httpClientResponseEvent.withStatusCode(500); 140 | Subsegment httpClientSubsegment = AWSXRay.beginSubsegment("failedResponseSubsegment"); 141 | 142 | httpClientHandler.handleResponse(httpClientResponseEvent); 143 | Assert.assertTrue(httpClientSubsegment.isFault()); 144 | Assert.assertFalse(httpClientSubsegment.isError()); 145 | Assert.assertFalse(httpClientSubsegment.isThrottle()); 146 | 147 | Map httpResponseMap = (Map) httpClientSubsegment.getHttp().get("response"); 148 | Assert.assertEquals(500, (int) httpResponseMap.get("status")); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/SqlHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.AWSXRay; 4 | import com.amazonaws.xray.agent.runtime.config.XRaySDKConfiguration; 5 | import com.amazonaws.xray.entities.Namespace; 6 | import com.amazonaws.xray.entities.Segment; 7 | import com.amazonaws.xray.entities.Subsegment; 8 | import com.amazonaws.xray.sql.SqlSubsegments; 9 | import org.junit.After; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.mockito.Mock; 13 | import org.mockito.MockitoAnnotations; 14 | import software.amazon.disco.agent.concurrent.TransactionContext; 15 | import software.amazon.disco.agent.event.ServiceDownstreamRequestEvent; 16 | import software.amazon.disco.agent.event.ServiceDownstreamResponseEvent; 17 | 18 | import java.net.URL; 19 | import java.sql.Connection; 20 | import java.sql.DatabaseMetaData; 21 | import java.sql.SQLException; 22 | import java.sql.Statement; 23 | 24 | import static org.assertj.core.api.Assertions.assertThat; 25 | import static org.mockito.Mockito.when; 26 | 27 | /** 28 | * Tests for the X-Ray Agent's handler of Disco SQL events. 29 | * See unit tests for {@link com.amazonaws.xray.sql.SqlSubsegments} for more on expected contents of a SQL subsegment. 30 | */ 31 | public class SqlHandlerTest { 32 | private static final String DB = "myDB"; 33 | private static final String QUERY = "SQL"; 34 | private static final String DB_URL = "http://example.com"; 35 | 36 | private SqlHandler handler; 37 | private ServiceDownstreamRequestEvent requestEvent; 38 | private ServiceDownstreamResponseEvent responseEvent; 39 | 40 | @Mock 41 | Statement mockStatement; 42 | 43 | @Mock 44 | Connection mockConnection; 45 | 46 | @Mock 47 | DatabaseMetaData mockMetaData; 48 | 49 | @Before 50 | public void setup() throws SQLException { 51 | MockitoAnnotations.initMocks(this); 52 | 53 | when(mockStatement.getConnection()).thenReturn(mockConnection); 54 | when(mockConnection.getCatalog()).thenReturn(DB); 55 | when(mockConnection.getMetaData()).thenReturn(mockMetaData); 56 | when(mockMetaData.getURL()).thenReturn(DB_URL); 57 | when(mockMetaData.getUserName()).thenReturn("USER"); 58 | when(mockMetaData.getDriverVersion()).thenReturn("DRIVER_VERSION"); 59 | when(mockMetaData.getDatabaseProductName()).thenReturn("DB_TYPE"); 60 | when(mockMetaData.getDatabaseProductVersion()).thenReturn("DB_VERSION"); 61 | 62 | handler = new SqlHandler(); 63 | TransactionContext.clear(); 64 | 65 | requestEvent = (ServiceDownstreamRequestEvent) new ServiceDownstreamRequestEvent("SQL", DB, QUERY) 66 | .withRequest(mockStatement); 67 | responseEvent = (ServiceDownstreamResponseEvent) new ServiceDownstreamResponseEvent("SQL", DB, QUERY, requestEvent) 68 | .withThrown(new SQLException()); 69 | } 70 | 71 | @After 72 | public void cleanup() { 73 | AWSXRay.clearTraceEntity(); 74 | } 75 | 76 | @Test 77 | public void testSubsegmentCreatedWithoutSql() { 78 | XRaySDKConfiguration.getInstance().init(); 79 | AWSXRay.beginSegment("test"); // must be after config init 80 | 81 | handler.handleRequest(requestEvent); 82 | 83 | Subsegment sqlSub = AWSXRay.getCurrentSubsegment(); 84 | assertThat(sqlSub.isInProgress()).isTrue(); 85 | assertThat(sqlSub.getName()).isEqualTo(DB + "@example.com"); 86 | assertThat(sqlSub.getNamespace()).isEqualTo(Namespace.REMOTE.toString()); 87 | assertThat(sqlSub.getSql()).doesNotContainKey(SqlSubsegments.SANITIZED_QUERY); 88 | } 89 | 90 | @Test 91 | public void testSubsegmentCreatedWithSql() { 92 | URL configFile = SqlHandlerTest.class.getResource("/com/amazonaws/xray/agent/collectSqlConfig.json"); 93 | XRaySDKConfiguration.getInstance().init(configFile); 94 | AWSXRay.beginSegment("test"); // must be after config init 95 | 96 | handler.handleRequest(requestEvent); 97 | 98 | Subsegment sqlSub = AWSXRay.getCurrentSubsegment(); 99 | assertThat(sqlSub.isInProgress()).isTrue(); 100 | assertThat(sqlSub.getName()).isEqualTo(DB + "@example.com"); 101 | assertThat(sqlSub.getNamespace()).isEqualTo(Namespace.REMOTE.toString()); 102 | assertThat(sqlSub.getSql()).containsEntry(SqlSubsegments.SANITIZED_QUERY, QUERY); 103 | } 104 | 105 | @Test 106 | public void testSubsegmentCreatedDespiteException() throws SQLException { 107 | when(mockStatement.getConnection()).thenThrow(new SQLException()); 108 | XRaySDKConfiguration.getInstance().init(); 109 | AWSXRay.beginSegment("test"); // must be after config init 110 | 111 | handler.handleRequest(requestEvent); 112 | 113 | Subsegment sqlSub = AWSXRay.getCurrentSubsegment(); 114 | assertThat(sqlSub.isInProgress()).isTrue(); 115 | assertThat(sqlSub.getName()).isEqualTo(SqlSubsegments.DEFAULT_DATABASE_NAME); 116 | } 117 | 118 | @Test 119 | public void testSubsegmentEndedWithThrowable() { 120 | XRaySDKConfiguration.getInstance().init(); 121 | Segment seg = AWSXRay.beginSegment("test"); // must be after config init 122 | Subsegment sub = AWSXRay.beginSubsegment("FakeSqlSub"); 123 | TransactionContext.putMetadata(SqlHandler.SQL_SUBSEGMENT_COUNT_KEY, 1); 124 | 125 | handler.handleResponse(responseEvent); 126 | 127 | assertThat(seg.getSubsegments().size()).isEqualTo(1); 128 | assertThat(sub.isInProgress()).isFalse(); 129 | assertThat(sub.getCause().getExceptions().size()).isEqualTo(1); 130 | assertThat(sub.isFault()).isTrue(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/handlers/downstream/SqlPrepareHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.handlers.downstream; 2 | 3 | import com.amazonaws.xray.agent.runtime.models.XRayTransactionState; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.mockito.Mock; 7 | import org.mockito.MockitoAnnotations; 8 | import software.amazon.disco.agent.event.ServiceDownstreamRequestEvent; 9 | import software.amazon.disco.agent.event.ServiceDownstreamResponseEvent; 10 | 11 | import java.sql.PreparedStatement; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | public class SqlPrepareHandlerTest { 16 | private SqlPrepareHandler handler; 17 | 18 | @Mock 19 | private PreparedStatement preparedStatementMock; 20 | 21 | @Before 22 | public void setup() { 23 | MockitoAnnotations.initMocks(this); 24 | handler = new SqlPrepareHandler(); 25 | } 26 | 27 | @Test 28 | public void testPreparedStatementMapInsertion() { 29 | String sql = "SELECT * FROM my_table"; 30 | 31 | ServiceDownstreamRequestEvent requestEvent = new ServiceDownstreamRequestEvent("origin", "service", sql); 32 | ServiceDownstreamResponseEvent responseEvent = new ServiceDownstreamResponseEvent("origin", "service", sql, requestEvent); 33 | responseEvent.withResponse(preparedStatementMock); 34 | 35 | handler.handleResponse(responseEvent); 36 | assertThat(XRayTransactionState.getPreparedQuery(preparedStatementMock)).isEqualTo(sql); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/java/com/amazonaws/xray/agent/runtime/listeners/XRayListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.xray.agent.runtime.listeners; 2 | 3 | import com.amazonaws.xray.agent.runtime.dispatcher.EventDispatcher; 4 | import org.junit.Assert; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.Mock; 9 | import org.powermock.modules.junit4.PowerMockRunner; 10 | import software.amazon.disco.agent.event.HttpServletNetworkRequestEvent; 11 | import software.amazon.disco.agent.event.HttpServletNetworkResponseEvent; 12 | import software.amazon.disco.agent.event.ServiceActivityRequestEvent; 13 | import software.amazon.disco.agent.event.ServiceActivityResponseEvent; 14 | import software.amazon.disco.agent.event.ServiceDownstreamRequestEvent; 15 | import software.amazon.disco.agent.event.ServiceDownstreamResponseEvent; 16 | import software.amazon.disco.agent.event.TransactionBeginEvent; 17 | import software.amazon.disco.agent.event.TransactionEvent; 18 | 19 | import static org.mockito.ArgumentMatchers.any; 20 | import static org.mockito.Mockito.doThrow; 21 | import static org.mockito.Mockito.times; 22 | import static org.mockito.Mockito.verify; 23 | 24 | @RunWith(PowerMockRunner.class) 25 | public class XRayListenerTest { 26 | private final String ORIGIN = "TestOrigin"; 27 | private final String SERVICE = "TestService"; 28 | private final String OPERATION = "TestOperation"; 29 | 30 | @Mock 31 | private EventDispatcher upstreamDispatcher; 32 | 33 | @Mock 34 | private EventDispatcher downstreamDispatcher; 35 | 36 | private XRayListener xRayListener; 37 | 38 | @Before 39 | public void setup() { 40 | xRayListener = new XRayListener(upstreamDispatcher, downstreamDispatcher); 41 | } 42 | 43 | @Test 44 | public void testGetPriority() { 45 | Assert.assertEquals(0, xRayListener.getPriority()); 46 | } 47 | 48 | @Test 49 | public void testListenUpstream() { 50 | ServiceActivityRequestEvent upstreamRequestEvent = new ServiceActivityRequestEvent(ORIGIN, SERVICE, OPERATION); 51 | ServiceActivityResponseEvent upstreamResponseEvent = new ServiceActivityResponseEvent(ORIGIN, SERVICE, OPERATION, upstreamRequestEvent); 52 | 53 | xRayListener.listen(upstreamRequestEvent); 54 | verify(upstreamDispatcher, times(1)).dispatchRequestEvent(upstreamRequestEvent); 55 | verify(upstreamDispatcher, times(0)).dispatchResponseEvent(upstreamResponseEvent); 56 | 57 | xRayListener.listen(upstreamResponseEvent); 58 | verify(upstreamDispatcher, times(1)).dispatchRequestEvent(upstreamRequestEvent); 59 | verify(upstreamDispatcher, times(1)).dispatchResponseEvent(upstreamResponseEvent); 60 | 61 | verify(downstreamDispatcher, times(0)).dispatchResponseEvent(upstreamRequestEvent); 62 | verify(downstreamDispatcher, times(0)).dispatchResponseEvent(upstreamResponseEvent); 63 | } 64 | 65 | @Test 66 | public void testListenDownstream() { 67 | ServiceDownstreamRequestEvent downstreamRequestEvent = new ServiceDownstreamRequestEvent(ORIGIN, SERVICE, OPERATION); 68 | ServiceDownstreamResponseEvent downstreamResponseEvent = new ServiceDownstreamResponseEvent(ORIGIN, SERVICE, OPERATION, downstreamRequestEvent); 69 | 70 | xRayListener.listen(downstreamRequestEvent); 71 | verify(downstreamDispatcher, times(1)).dispatchRequestEvent(downstreamRequestEvent); 72 | verify(downstreamDispatcher, times(0)).dispatchResponseEvent(downstreamResponseEvent); 73 | 74 | xRayListener.listen(downstreamResponseEvent); 75 | verify(downstreamDispatcher, times(1)).dispatchRequestEvent(downstreamRequestEvent); 76 | verify(downstreamDispatcher, times(1)).dispatchResponseEvent(downstreamResponseEvent); 77 | 78 | verify(upstreamDispatcher, times(0)).dispatchResponseEvent(downstreamRequestEvent); 79 | verify(upstreamDispatcher, times(0)).dispatchResponseEvent(downstreamResponseEvent); 80 | } 81 | 82 | @Test 83 | public void testValidEvents() { 84 | ServiceActivityRequestEvent serviceRequestEvent = new ServiceActivityRequestEvent(ORIGIN, SERVICE, OPERATION); 85 | xRayListener.listen(serviceRequestEvent); 86 | verify(upstreamDispatcher, times(1)).dispatchRequestEvent(serviceRequestEvent); 87 | 88 | ServiceActivityResponseEvent serviceResponseEvent = new ServiceActivityResponseEvent(ORIGIN, SERVICE, OPERATION, serviceRequestEvent); 89 | xRayListener.listen(serviceResponseEvent); 90 | verify(upstreamDispatcher, times(1)).dispatchResponseEvent(serviceResponseEvent); 91 | 92 | HttpServletNetworkRequestEvent httpRequestEvent = new HttpServletNetworkRequestEvent(ORIGIN, 0, 0 ,"", ""); 93 | xRayListener.listen(httpRequestEvent); 94 | verify(upstreamDispatcher, times(1)).dispatchRequestEvent(httpRequestEvent); 95 | 96 | HttpServletNetworkResponseEvent httpResponseEvent = new HttpServletNetworkResponseEvent(ORIGIN, httpRequestEvent); 97 | xRayListener.listen(httpResponseEvent); 98 | verify(upstreamDispatcher, times(1)).dispatchResponseEvent(httpResponseEvent); 99 | 100 | ServiceDownstreamRequestEvent downstreamRequestEvent = new ServiceDownstreamRequestEvent(ORIGIN, SERVICE, OPERATION); 101 | xRayListener.listen(downstreamRequestEvent); 102 | verify(downstreamDispatcher, times(1)).dispatchRequestEvent(downstreamRequestEvent); 103 | 104 | ServiceDownstreamResponseEvent downstreamResponseEvent = new ServiceDownstreamResponseEvent(ORIGIN, SERVICE, OPERATION, downstreamRequestEvent); 105 | xRayListener.listen(downstreamResponseEvent); 106 | verify(downstreamDispatcher, times(1)).dispatchResponseEvent(downstreamResponseEvent); 107 | 108 | } 109 | 110 | @Test 111 | public void testInvalidEvent() { 112 | TransactionEvent invalidEvent = new TransactionBeginEvent(ORIGIN); 113 | 114 | xRayListener.listen(invalidEvent); 115 | 116 | verify(downstreamDispatcher, times(0)).dispatchResponseEvent(any()); 117 | verify(downstreamDispatcher, times(0)).dispatchResponseEvent(any()); 118 | verify(upstreamDispatcher, times(0)).dispatchResponseEvent(any()); 119 | verify(upstreamDispatcher, times(0)).dispatchResponseEvent(any()); 120 | } 121 | 122 | @Test 123 | public void testDispatcherException() { 124 | // We expect the listener to be a catch-all for any exception, 125 | // so ultimately, it shouldn't throw exceptions and mess up application code. 126 | doThrow(new RuntimeException("Test Exception")).when(downstreamDispatcher).dispatchRequestEvent(any()); 127 | ServiceDownstreamRequestEvent downstreamRequestEvent = new ServiceDownstreamRequestEvent(ORIGIN, SERVICE, OPERATION); 128 | 129 | verify(downstreamDispatcher, times(0)).dispatchRequestEvent(any()); 130 | xRayListener.listen(downstreamRequestEvent); 131 | verify(downstreamDispatcher, times(1)).dispatchRequestEvent(any()); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/com/amazonaws/xray/agent/awsV1AgentConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "awsServiceHandlerManifest": "/path/to/manifest", 3 | "awsSdkVersion": 1 4 | } 5 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/com/amazonaws/xray/agent/awsV2AgentConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "awsServiceHandlerManifest": "/path/to/manifest", 3 | "awsSdkVersion": 2 4 | } 5 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/com/amazonaws/xray/agent/collectSqlConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectSqlQueries": "true" 3 | } -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/com/amazonaws/xray/agent/emptyAgentConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/com/amazonaws/xray/agent/malformedAgentConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxStackTraceLength": "NotANumber" 3 | } 4 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/com/amazonaws/xray/agent/validAgentConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "serviceName": "myServiceName", 3 | "contextMissingStrategy": "myTestContext", 4 | "daemonAddress": "myTestAddress", 5 | "samplingStrategy": "myTestSampling", 6 | "samplingRulesManifest": "myTestManifest", 7 | "traceIdInjection": "Log4J", 8 | "traceIdInjectionPrefix": "prefix", 9 | "maxStackTraceLength": 20, 10 | "streamingThreshold": 10, 11 | "awsSdkVersion": 1, 12 | "awsServiceHandlerManifest": "myTestHandler", 13 | "pluginsEnabled": false, 14 | "tracingEnabled": false, 15 | "collectSqlQueries": true, 16 | "contextPropagation": false, 17 | "traceIncomingRequests": false 18 | } 19 | -------------------------------------------------------------------------------- /aws-xray-agent/src/test/resources/xray-agent.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-xray-java-agent/aa90f56b72f9e244cf1e57e196fbab827bad6ed4/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /images/xray-agent-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-xray-java-agent/aa90f56b72f9e244cf1e57e196fbab827bad6ed4/images/xray-agent-sample.png -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "com.amazonaws.xray.agent" 2 | 3 | pluginManagement { 4 | plugins { 5 | id("com.github.johnrengelman.shadow") version "8.1.1" 6 | id("nebula.release") version "18.0.6" 7 | id("io.github.gradle-nexus.publish-plugin") version "1.0.0" 8 | id("com.github.ben-manes.versions") version "0.38.0" 9 | } 10 | } 11 | 12 | include("aws-xray-agent") 13 | include("aws-xray-agent-plugin") 14 | include("aws-xray-agent-benchmark") 15 | --------------------------------------------------------------------------------