├── .github ├── CODEOWNERS └── workflows │ ├── continuous-monitoring.yml │ ├── pr-build.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── THIRD-PARTY ├── buildtools └── local-development.snk └── src ├── AWSXRayRecorder.AutoInstrumentation.sln ├── profiler └── src │ ├── ClassFactory.cpp │ ├── ClassFactory.h │ ├── ClrProfiler.def │ ├── ClrProfiler.vcxproj │ ├── CorProfiler.cpp │ ├── CorProfiler.h │ ├── FunctionInfo.cpp │ ├── FunctionInfo.h │ ├── ILWriter.cpp │ ├── ILWriter.h │ ├── dllmain.cpp │ └── stdafx.h ├── sdk ├── AWSXRayRecorder.AutoInstrumentation.csproj ├── AspNet │ └── AspNetAutoInstrumentationModule.cs ├── AspNetCore │ └── AspNetCoreDiagnosticListener.cs ├── AwsSdk │ └── AWSSDKRequestRegister.cs ├── Configuration │ ├── XRayAutoInstrumentationOptions.cs │ ├── XRayConfiguration.Net45.cs │ └── XRayConfiguration.Netstandard.cs ├── Diagnostic │ ├── DiagnosticListenerBase.cs │ └── DiagnosticListenerObserver.cs ├── EntityFramework │ ├── EntityFrameworkCoreDiagnosticListener.cs │ └── EntityFrameworkHandler.cs ├── Http │ ├── HttpOutDiagnosticListenerNetframework.cs │ └── HttpOutDiagnosticListenerNetstandard.cs ├── Initialization │ ├── AspNetCoreTracingHandlers.cs │ └── AspNetTracingHandlers.cs ├── Initialize.cs ├── Sql │ ├── SqlDiagnosticListener.cs │ └── SqlEventListener.cs └── Utils │ ├── AgentUtil.cs │ ├── AspNetCoreRequestUtil.cs │ ├── AspNetRequestUtil.cs │ ├── HttpRequestUtil.cs │ └── SqlRequestUtil.cs └── test ├── AWSXRayRecorder.AutoInstrumentation.Unittests.csproj ├── EntityFrameworkCoreDiagnosticListenerTest.cs ├── EntityFrameworkWithSqlDiagnosticListenerTest.cs ├── HttpOutDiagnosticListenerTest.cs ├── JSONs └── appsettings.json ├── TestBase.cs ├── Tools ├── MockAWSXRayRecorder.cs └── MockEntityFrameworkCoreDbContext.cs ├── UtilTest.cs ├── XRayAutoInstrumentationOptionsTest.cs ├── XRayConfigurationNetstandardTest.cs └── XRayConfigurationTest.cs /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # https://help.github.com/articles/about-codeowners/ 2 | 3 | * @edyin @lupengamzn 4 | -------------------------------------------------------------------------------- /.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 .NET agent from github release 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Configure AWS Credentials 17 | uses: aws-actions/configure-aws-credentials@v4 18 | with: 19 | role-to-assume: ${{ secrets.AWS_INTEG_TEST_ROLE_ARN }} 20 | aws-region: us-east-1 21 | 22 | - name: Pull X-Ray .NET agent from github release 23 | id: distribution-availability-github 24 | run: | 25 | (echo "===== Attempt: 1 ====" && wget https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X64.msi && wget https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X86.msi) || \ 26 | (echo "===== Attempt: 2 ====" && wget https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X64.msi && wget https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X86.msi) || \ 27 | (echo "===== Attempt: 3 ====" && wget https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X64.msi && wget https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X86.msi) || \ 28 | (echo "===== No more retries. Failed! ====" && exit 1) 29 | 30 | - name: Publish metric on X-Ray .NET agent distribution availability (Github) 31 | if: ${{ always() }} 32 | run: | 33 | if [[ "${{ steps.distribution-availability-github.outcome }}" == "failure" ]]; then 34 | aws cloudwatch put-metric-data --metric-name XRayDotnetAgentGithubDistributionUnavailability --dimensions failure=rate --namespace MonitorAgent --value 1 --timestamp $(date +%s) 35 | else 36 | aws cloudwatch put-metric-data --metric-name XRayDotnetAgentGithubDistributionUnavailability --dimensions failure=rate --namespace MonitorAgent --value 0 --timestamp $(date +%s) 37 | fi 38 | -------------------------------------------------------------------------------- /.github/workflows/pr-build.yml: -------------------------------------------------------------------------------- 1 | name: X-Ray .NET Agent PR build workflow 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | name: build 11 | runs-on: windows-latest 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | version: [net452,netcoreapp2.0] 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v2 21 | 22 | - name: Clean solution 23 | run: dotnet clean src/AWSXRayRecorder.AutoInstrumentation.sln --configuration Release && dotnet nuget locals all --clear 24 | 25 | - name: Install dependencies 26 | run: dotnet restore src/AWSXRayRecorder.AutoInstrumentation.sln --locked-mode 27 | 28 | - name: Build solution 29 | run: dotnet build src/AWSXRayRecorder.AutoInstrumentation.sln --configuration Release --no-restore 30 | 31 | - name: Run tests 32 | run: dotnet test src/test/bin/Release/${{matrix.version}}/AWSXRayRecorder.AutoInstrumentation.UnitTests.dll 33 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release X-Ray .NET Agent 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: The version to tag the release with, e.g., 1.2.0, 1.3.0 8 | required: true 9 | 10 | jobs: 11 | release: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout main branch 15 | uses: actions/checkout@v2 16 | 17 | - name: Create Release 18 | id: create_release 19 | uses: actions/create-release@v1 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | with: 23 | tag_name: 'v${{ github.event.inputs.version }}' 24 | release_name: 'Release ${{ github.event.inputs.version }}' 25 | body: 'Please refer [change-log](https://github.com/aws/aws-xray-dotnet-agent/blob/master/CHANGELOG.md) for more details' 26 | draft: true 27 | prerelease: false 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*.json 146 | coverage*.xml 147 | coverage*.info 148 | 149 | # Visual Studio code coverage results 150 | *.coverage 151 | *.coveragexml 152 | 153 | # NCrunch 154 | _NCrunch_* 155 | .*crunch*.local.xml 156 | nCrunchTemp_* 157 | 158 | # MightyMoose 159 | *.mm.* 160 | AutoTest.Net/ 161 | 162 | # Web workbench (sass) 163 | .sass-cache/ 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # Note: Comment the next line if you want to checkin your web deploy settings, 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # NuGet Symbol Packages 197 | *.snupkg 198 | # The packages folder can be ignored because of Package Restore 199 | **/[Pp]ackages/* 200 | # except build/, which is used as an MSBuild target. 201 | !**/[Pp]ackages/build/ 202 | # Uncomment if necessary however generally it will be regenerated when needed 203 | #!**/[Pp]ackages/repositories.config 204 | # NuGet v3's project.json files produces more ignorable files 205 | *.nuget.props 206 | *.nuget.targets 207 | 208 | # Microsoft Azure Build Output 209 | csx/ 210 | *.build.csdef 211 | 212 | # Microsoft Azure Emulator 213 | ecf/ 214 | rcf/ 215 | 216 | # Windows Store app package directories and files 217 | AppPackages/ 218 | BundleArtifacts/ 219 | Package.StoreAssociation.xml 220 | _pkginfo.txt 221 | *.appx 222 | *.appxbundle 223 | *.appxupload 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !?*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | orleans.codegen.cs 241 | 242 | # Including strong name files can present a security risk 243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 244 | #*.snk 245 | 246 | # Since there are multiple workflows, uncomment next line to ignore bower_components 247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 248 | #bower_components/ 249 | 250 | # RIA/Silverlight projects 251 | Generated_Code/ 252 | 253 | # Backup & report files from converting an old project file 254 | # to a newer Visual Studio version. Backup files are not needed, 255 | # because we have git ;-) 256 | _UpgradeReport_Files/ 257 | Backup*/ 258 | UpgradeLog*.XML 259 | UpgradeLog*.htm 260 | ServiceFabricBackup/ 261 | *.rptproj.bak 262 | 263 | # SQL Server files 264 | *.mdf 265 | *.ldf 266 | *.ndf 267 | 268 | # Business Intelligence projects 269 | *.rdl.data 270 | *.bim.layout 271 | *.bim_*.settings 272 | *.rptproj.rsuser 273 | *- [Bb]ackup.rdl 274 | *- [Bb]ackup ([0-9]).rdl 275 | *- [Bb]ackup ([0-9][0-9]).rdl 276 | 277 | # Microsoft Fakes 278 | FakesAssemblies/ 279 | 280 | # GhostDoc plugin setting file 281 | *.GhostDoc.xml 282 | 283 | # Node.js Tools for Visual Studio 284 | .ntvs_analysis.dat 285 | node_modules/ 286 | 287 | # Visual Studio 6 build log 288 | *.plg 289 | 290 | # Visual Studio 6 workspace options file 291 | *.opt 292 | 293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 294 | *.vbw 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # BeatPulse healthcheck temp database 353 | healthchecksdb 354 | 355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 356 | MigrationBackup/ 357 | 358 | # Ionide (cross platform F# VS Code tools) working folder 359 | .ionide/ 360 | 361 | # Fody - auto-generated XML schema 362 | FodyWeavers.xsd 363 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## 2.10.0-beta.1 (2021-05-07) 5 | - Changed XRay attribute block to ConcurrentDictionary [PR#33](https://github.com/aws/aws-xray-dotnet-agent/pull/33) 6 | - Bumped AWSXRayRecorder.Handler.AwsSdk version [PR#30](https://github.com/aws/aws-xray-dotnet-agent/pull/30) 7 | - Fixed limitation when using AspNetAutoInstrumentationModule [PR#23](https://github.com/aws/aws-xray-dotnet-agent/pull/23) -------------------------------------------------------------------------------- /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 *master* 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | AWS X-Ray SDK .NET Agent 2 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AWS X-Ray .NET Agent 2 | 3 | The AWS X-Ray .NET Agent is a drop-in solution that enables the propagation of X-Ray traces within your web applications. This includes automatic tracing for AWS X-Ray SDK supported frameworks and libraries. The agent enables you to use the X-Ray SDK out of box, and requires no code changes to enable the basic propagation of traces. See the compatibility chart below for the current feature parity between the AWS X-Ray .NET SDK and the AWS X-Ray .NET Agent. 4 | 5 | See the [Sample App](https://github.com/aws-samples/aws-xray-dotnet-webapp) for a demonstration on how to use the agent. 6 | 7 | ## Compatibility Chart 8 | 9 | | **Feature** | **X-Ray SDK(.NET)** | **X-Ray SDK(.NET Core)** | **X-Ray Agent(.NET)** | **X-Ray Agent(.NET Core)**| 10 | | ----------- | ----------- | ----------- | ----------- | ----------- | 11 | | [AWS](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-sdkclients.html) | ✔ | ✔ | ✔ | ✔ | 12 | | [Incoming Http](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-messagehandler.html) | ✔ | ✔ | ✔ | ✔ | 13 | | [HttpClient](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-httpclients.html) | ✔ | ✔ | ✔ | ✔ | 14 | | [HttpWebRequest](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-httpclients.html) | ✔ | ✔ | ✔ | ✔ | 15 | | [System.Data.SqlClient](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-sqlqueries.html) | ✔ | ✔ | ✔ | ✔ | 16 | | [Microsoft.Data.SqlClient](https://docs.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient) | ❌ | ❌ | ❌ | ✔ | 17 | | [EntityFramework](https://docs.microsoft.com/en-us/ef/) | ❌ |✔ (EF Core)| ✔ (EF 6)| ✔ (EF Core)| 18 | | [Local Sampling](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-configuration.html#xray-sdk-dotnet-configuration-sampling) | ✔ | ✔ | ✔ | ✔ | 19 | | [Dynamic Sampling](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-configuration.html#xray-sdk-dotnet-configuration-sampling) | ✔ | ✔ | ✔ | ✔ | 20 | | [Multithreaded Execution](https://github.com/aws/aws-xray-sdk-dotnet/tree/master#multithreaded-execution-net-and-net-core--nuget) | ✔ | ✔ | ✔ | ✔ | 21 | | [Plugins](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-configuration.html#xray-sdk-dotnet-configuration-plugins) | ✔ | ✔ | ✔ | ✔ | 22 | | [Custom Subsegment](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet-subsegments.html) | ✔ | ✔ | ✔ | ✔ | 23 | 24 | ## Prerequisites 25 | 26 | If you're running an Asp.Net Core application, you need to install the latest version of [Visual C++ Redistributable ](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) 27 | 28 | ## Configuration 29 | 30 | AWS X-Ray .Net Agent will register the [configuration items](https://github.com/aws/aws-xray-sdk-dotnet/tree/master#configuration) as AWS X-Ray .NET SDK. 31 | 32 | Besides, AWS X-Ray .Net Agent will register the following configuration items. 33 | ``` 34 | { 35 | "ServiceName" : "DefaultService", 36 | "DaemonAddress" : "127.0.0.1:2000", 37 | "TraceHttpRequests" : "true", 38 | "TraceAWSRequests" : "true", 39 | "TraceSqlRequests" : "true", 40 | "TraceEFRequests" : "true" 41 | } 42 | ``` 43 | You can customize the service name of your application, the daemon address and specify which request to trace through `appsettings.json` file (Asp.Net Core) or `web.config` file (Asp.Net). 44 | 45 | If you don't provide these configuration items, the default values shown above will be applied by AWS X-Ray .NET Agent. 46 | 47 | Note: 48 | 49 | * .Net Agent doesn't provide configuration item to disable tracing incoming Http request. If you want to disable tracing incoming request, you may set `DisableXRayTracing` as `true`. 50 | 51 | * AWS request will trigger Http outgoing handler, so if you want to disable tracing AWS request, you have to disable both AWS handler and Http outgoing handler. 52 | 53 | * Similiar situation happens to Entity Framework request, which triggers both Entity Framework handler and Sql handler, therefore, if you want to disable tracing Entity Framework request, remember to disable Sql handler as well. 54 | 55 | ## Installation 56 | 57 | ### Minimum Requirements 58 | 59 | For building `AWSXRayRecorder.AutoInstrumentation` package, you need to install **Visual Studio 2019**. 60 | 61 | For building profiler, you need to have workloads **.NET desktop development** and **Desktop development with C++** installed within **Visual Studio 2019**. 62 | 63 | ### Development 64 | 65 | Note: 66 | 67 | DotNet Coreclr Lib is required to build the profiler project in this repo. You can find it at this [repo](https://github.com/dotnet/runtime/tree/master/src/coreclr). Put coreclr folder under `aws-xray-dotnet-agent\src\profiler`, then you are good to go. 68 | 69 | ### Automatic Instrumentation 70 | 71 | #### Internet Information Services (IIS) 72 | 73 | ##### Asp.Net Core & Asp.Net 74 | 75 | 1. Git clone this repo and import `AWSXRayRecorder.AutoInstrumentation` package into your project and **rebuild**. 76 | 2. Download and run AWS X-Ray .NET Agent Installer ([x64](https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X64.msi) and [x86](https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X86.msi)). 77 | 3. Restart IIS and launch your application. 78 | ``` 79 | iisreset 80 | ``` 81 | 82 | #### Others (Not IIS) 83 | 84 | ##### Asp.Net Core 85 | 86 | 1. Git clone this repo and import `AWSXRayRecorder.AutoInstrumentation` package into your project and **rebuild**. 87 | 2. Download and run AWS X-Ray .NET Agent Installer ([x64](https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X64.msi) and [x86](https://github.com/aws/aws-xray-dotnet-agent/releases/download/v2.10.0-beta.1/aws-xray-dotnet-agent-installer-beta-X86.msi)). 88 | 3. Launch your application as follows. 89 | ``` 90 | SET CORECLR_PROFILER={AE47A175-390A-4F13-84CB-7169CEBF064A} 91 | SET CORECLR_ENABLE_PROFILING=1 92 | 93 | dotnet YourApplication.dll 94 | ``` 95 | Note: 96 | 97 | * **Do not set environment variables globally into the system variables as profiler will try to instrument all .NET processes running on the instance with AWS X-Ray tracing SDK.** 98 | 99 | ##### Asp.Net 100 | 101 | 1. Import `AWSXRayRecorder.AutoInstrumentation` package into your project and **rebuild**. 102 | 2. Add the following snippet into the `web.config` file. 103 | ``` 104 | 105 | 106 | 107 | 108 | 109 | ``` 110 | 3. Launch your application 111 | 112 | ### Manual Instrumentation 113 | 114 | #### Asp.Net Core 115 | 116 | Instead of using profiler, you may choose to manually instrument AWS X-Ray SDK into your Asp.Net Core application. 117 | 118 | 1. Import `AWSXRayRecorder.AutoInstrumentation` package into your project. 119 | 120 | 2. Add the following method into any method in `startup.cs` or `program.cs` file 121 | ``` 122 | Amazon.XRay.Recorder.AutoInstrumentation.Initialize.AddXRay(); 123 | ``` 124 | 125 | ## Getting Help 126 | 127 | Please use these community resources for getting help. 128 | 129 | * If you think you may have found a bug or need assistance, please open an [issue](https://github.com/aws/aws-xray-dotnet-agent/issues/new). 130 | * Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html). 131 | * Ask a question in the [AWS X-Ray Forum](https://forums.aws.amazon.com/forum.jspa?forumID=241&start=0). 132 | * For contributing guidelines refer to [CONTRIBUTING.md](https://github.com/aws/aws-xray-dotnet-agent/blob/master/CONTRIBUTING.md). 133 | 134 | ## Documentation 135 | 136 | The [developer guide](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet.html) provides guidance on using the AWS X-Ray DotNet Agent. Please refer to the [Sample App](https://github.com/aws-samples/aws-xray-dotnet-webapp) for an example. 137 | 138 | ## License 139 | 140 | The AWS X-Ray SDK DotNet Agent is licensed under the Apache 2.0 License. See LICENSE for more information. 141 | -------------------------------------------------------------------------------- /buildtools/local-development.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-xray-dotnet-agent/d3920d4f0b5b8d91623876615f8f9feb6d60d252/buildtools/local-development.snk -------------------------------------------------------------------------------- /src/AWSXRayRecorder.AutoInstrumentation.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30204.135 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWSXRayRecorder.AutoInstrumentation", "sdk\AWSXRayRecorder.AutoInstrumentation.csproj", "{579F41A1-F0B1-475D-98E0-3B237411DEE5}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWSXRayRecorder.AutoInstrumentation.Unittests", "test\AWSXRayRecorder.AutoInstrumentation.Unittests.csproj", "{D95AB7C9-4384-45BB-9A38-BCA3B86435BE}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ClrProfiler", "profiler\src\ClrProfiler.vcxproj", "{69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Debug|x64.ActiveCfg = Debug|Any CPU 25 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Debug|x64.Build.0 = Debug|Any CPU 26 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Debug|x86.ActiveCfg = Debug|Any CPU 27 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Debug|x86.Build.0 = Debug|Any CPU 28 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Release|x64.ActiveCfg = Release|Any CPU 31 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Release|x64.Build.0 = Release|Any CPU 32 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Release|x86.ActiveCfg = Release|Any CPU 33 | {579F41A1-F0B1-475D-98E0-3B237411DEE5}.Release|x86.Build.0 = Release|Any CPU 34 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Debug|x64.ActiveCfg = Debug|Any CPU 37 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Debug|x64.Build.0 = Debug|Any CPU 38 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Debug|x86.ActiveCfg = Debug|Any CPU 39 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Debug|x86.Build.0 = Debug|Any CPU 40 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Release|x64.ActiveCfg = Release|Any CPU 43 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Release|x64.Build.0 = Release|Any CPU 44 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Release|x86.ActiveCfg = Release|Any CPU 45 | {D95AB7C9-4384-45BB-9A38-BCA3B86435BE}.Release|x86.Build.0 = Release|Any CPU 46 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Debug|Any CPU.ActiveCfg = Debug|Win32 47 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Debug|Any CPU.Build.0 = Debug|Win32 48 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Debug|x64.ActiveCfg = Debug|x64 49 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Debug|x64.Build.0 = Debug|x64 50 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Debug|x86.ActiveCfg = Debug|Win32 51 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Debug|x86.Build.0 = Debug|Win32 52 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Release|Any CPU.ActiveCfg = Release|Win32 53 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Release|x64.ActiveCfg = Release|x64 54 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Release|x64.Build.0 = Release|x64 55 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Release|x86.ActiveCfg = Release|Win32 56 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB}.Release|x86.Build.0 = Release|Win32 57 | EndGlobalSection 58 | GlobalSection(SolutionProperties) = preSolution 59 | HideSolutionNode = FALSE 60 | EndGlobalSection 61 | GlobalSection(ExtensibilityGlobals) = postSolution 62 | SolutionGuid = {D2D53B22-B7B3-4E9F-A71B-3FB02CD80043} 63 | EndGlobalSection 64 | EndGlobal 65 | -------------------------------------------------------------------------------- /src/profiler/src/ClassFactory.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "ClassFactory.h" 5 | #include "CorProfiler.h" 6 | #include "assert.h" 7 | 8 | ClassFactory::ClassFactory() : refCount(1) 9 | { 10 | } 11 | 12 | ClassFactory::~ClassFactory() 13 | { 14 | } 15 | 16 | HRESULT STDMETHODCALLTYPE ClassFactory::QueryInterface(REFIID riid, void **ppvObject) 17 | { 18 | if (riid == IID_IUnknown || riid == IID_IClassFactory) 19 | { 20 | *ppvObject = this; 21 | this->AddRef(); 22 | 23 | return S_OK; 24 | } 25 | 26 | *ppvObject = NULL; 27 | return E_NOINTERFACE; 28 | } 29 | 30 | ULONG STDMETHODCALLTYPE ClassFactory::AddRef() 31 | { 32 | return ++this->refCount; 33 | } 34 | 35 | ULONG STDMETHODCALLTYPE ClassFactory::Release() 36 | { 37 | int count = --this->refCount; 38 | if (count <= 0) 39 | { 40 | delete this; 41 | } 42 | 43 | return count; 44 | } 45 | 46 | HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) 47 | { 48 | if (pUnkOuter != nullptr) 49 | { 50 | *ppvObject = nullptr; 51 | return CLASS_E_NOAGGREGATION; 52 | } 53 | 54 | CorProfiler* profiler = new CorProfiler(); 55 | if (profiler == nullptr) 56 | { 57 | return E_FAIL; 58 | } 59 | 60 | assert(riid == __uuidof(ICorProfilerCallback8) || 61 | riid == __uuidof(ICorProfilerCallback7) || 62 | riid == __uuidof(ICorProfilerCallback6) || 63 | riid == __uuidof(ICorProfilerCallback5) || 64 | riid == __uuidof(ICorProfilerCallback4) || 65 | riid == __uuidof(ICorProfilerCallback3) || 66 | riid == __uuidof(ICorProfilerCallback2) || 67 | riid == __uuidof(ICorProfilerCallback) || 68 | riid == IID_IUnknown); 69 | 70 | return profiler->QueryInterface(riid, ppvObject); 71 | } 72 | 73 | HRESULT STDMETHODCALLTYPE ClassFactory::LockServer(BOOL fLock) 74 | { 75 | return S_OK; 76 | } 77 | -------------------------------------------------------------------------------- /src/profiler/src/ClassFactory.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma once 5 | 6 | #include 7 | #include "unknwn.h" 8 | 9 | class ClassFactory : public IClassFactory 10 | { 11 | private: 12 | std::atomic refCount; 13 | public: 14 | ClassFactory(); 15 | virtual ~ClassFactory(); 16 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override; 17 | ULONG STDMETHODCALLTYPE AddRef(void) override; 18 | ULONG STDMETHODCALLTYPE Release(void) override; 19 | HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) override; 20 | HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) override; 21 | }; 22 | -------------------------------------------------------------------------------- /src/profiler/src/ClrProfiler.def: -------------------------------------------------------------------------------- 1 | LIBRARY "ClrProfiler.Dll" 2 | 3 | EXPORTS 4 | DllCanUnloadNow PRIVATE 5 | DllGetClassObject PRIVATE 6 | -------------------------------------------------------------------------------- /src/profiler/src/ClrProfiler.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {69E3D8F7-CDE4-4B7E-8D7B-0FF09FEB23DB} 24 | Win32Proj 25 | ClrProfiler 26 | ..\coreclr 27 | 10.0 28 | 29 | 30 | 31 | 32 | 33 | 34 | DynamicLibrary 35 | true 36 | v142 37 | Unicode 38 | 39 | 40 | DynamicLibrary 41 | false 42 | v142 43 | true 44 | Unicode 45 | 46 | 47 | DynamicLibrary 48 | true 49 | v142 50 | Unicode 51 | 52 | 53 | DynamicLibrary 54 | false 55 | v142 56 | true 57 | Unicode 58 | 59 | 60 | 61 | true 62 | $(VC_IncludePath);$(CORECLR_PATH)\src\pal\prebuilt\inc;$(CORECLR_PATH)\src\inc;$(WindowsSDK_IncludePath); 63 | $(SolutionDir)\profiler\src\$(Configuration) 64 | 65 | 66 | true 67 | $(VC_IncludePath);$(CORECLR_PATH)\src\pal\prebuilt\inc;$(CORECLR_PATH)\src\inc;$(WindowsSDK_IncludePath); 68 | $(SolutionDir)\profiler\src\$(Configuration) 69 | 70 | 71 | false 72 | $(VC_IncludePath);$(CORECLR_PATH)\src\pal\prebuilt\inc;$(CORECLR_PATH)\src\inc;$(WindowsSDK_IncludePath); 73 | $(SolutionDir)\profiler\src\$(Configuration) 74 | 75 | 76 | false 77 | $(VC_IncludePath);$(CORECLR_PATH)\src\pal\prebuilt\inc;$(CORECLR_PATH)\src\inc;$(WindowsSDK_IncludePath); 78 | $(SolutionDir)\profiler\src\$(Configuration) 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 85 | true 86 | 87 | 88 | Windows 89 | true 90 | .\ClrProfiler.def 91 | 92 | 93 | 94 | 95 | Level3 96 | Disabled 97 | WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 98 | true 99 | 100 | 101 | Windows 102 | true 103 | .\ClrProfiler.def 104 | 105 | 106 | 107 | 108 | Level3 109 | MaxSpeed 110 | true 111 | true 112 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 113 | true 114 | 115 | 116 | Windows 117 | true 118 | true 119 | true 120 | .\ClrProfiler.def 121 | 122 | 123 | 124 | 125 | Level3 126 | MaxSpeed 127 | true 128 | true 129 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 130 | true 131 | 132 | 133 | Windows 134 | true 135 | true 136 | true 137 | .\ClrProfiler.def 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /src/profiler/src/CorProfiler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma once 5 | 6 | #include 7 | #include "cor.h" 8 | #include "corhdr.h" 9 | #include "corprof.h" 10 | #include "FunctionInfo.h" 11 | #include "ILWriter.h" 12 | 13 | #define DefaultLength 1024 14 | 15 | class CorProfiler : public ICorProfilerCallback8 16 | { 17 | private: 18 | std::atomic refCount; 19 | ICorProfilerInfo8* corProfilerInfo; 20 | bool hasInserted; 21 | public: 22 | CorProfiler(); 23 | virtual ~CorProfiler(); 24 | FunctionInfo* GetFunctionInfoFromId(ICorProfilerInfo* corProfilerInfo, FunctionID functionID); 25 | HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk) override; 26 | HRESULT STDMETHODCALLTYPE Shutdown() override; 27 | HRESULT STDMETHODCALLTYPE AppDomainCreationStarted(AppDomainID appDomainId) override; 28 | HRESULT STDMETHODCALLTYPE AppDomainCreationFinished(AppDomainID appDomainId, HRESULT hrStatus) override; 29 | HRESULT STDMETHODCALLTYPE AppDomainShutdownStarted(AppDomainID appDomainId) override; 30 | HRESULT STDMETHODCALLTYPE AppDomainShutdownFinished(AppDomainID appDomainId, HRESULT hrStatus) override; 31 | HRESULT STDMETHODCALLTYPE AssemblyLoadStarted(AssemblyID assemblyId) override; 32 | HRESULT STDMETHODCALLTYPE AssemblyLoadFinished(AssemblyID assemblyId, HRESULT hrStatus) override; 33 | HRESULT STDMETHODCALLTYPE AssemblyUnloadStarted(AssemblyID assemblyId) override; 34 | HRESULT STDMETHODCALLTYPE AssemblyUnloadFinished(AssemblyID assemblyId, HRESULT hrStatus) override; 35 | HRESULT STDMETHODCALLTYPE ModuleLoadStarted(ModuleID moduleId) override; 36 | HRESULT STDMETHODCALLTYPE ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus) override; 37 | HRESULT STDMETHODCALLTYPE ModuleUnloadStarted(ModuleID moduleId) override; 38 | HRESULT STDMETHODCALLTYPE ModuleUnloadFinished(ModuleID moduleId, HRESULT hrStatus) override; 39 | HRESULT STDMETHODCALLTYPE ModuleAttachedToAssembly(ModuleID moduleId, AssemblyID AssemblyId) override; 40 | HRESULT STDMETHODCALLTYPE ClassLoadStarted(ClassID classId) override; 41 | HRESULT STDMETHODCALLTYPE ClassLoadFinished(ClassID classId, HRESULT hrStatus) override; 42 | HRESULT STDMETHODCALLTYPE ClassUnloadStarted(ClassID classId) override; 43 | HRESULT STDMETHODCALLTYPE ClassUnloadFinished(ClassID classId, HRESULT hrStatus) override; 44 | HRESULT STDMETHODCALLTYPE FunctionUnloadStarted(FunctionID functionId) override; 45 | HRESULT STDMETHODCALLTYPE JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock) override; 46 | HRESULT STDMETHODCALLTYPE JITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) override; 47 | HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchStarted(FunctionID functionId, BOOL* pbUseCachedFunction) override; 48 | HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result) override; 49 | HRESULT STDMETHODCALLTYPE JITFunctionPitched(FunctionID functionId) override; 50 | HRESULT STDMETHODCALLTYPE JITInlining(FunctionID callerId, FunctionID calleeId, BOOL* pfShouldInline) override; 51 | HRESULT STDMETHODCALLTYPE ThreadCreated(ThreadID threadId) override; 52 | HRESULT STDMETHODCALLTYPE ThreadDestroyed(ThreadID threadId) override; 53 | HRESULT STDMETHODCALLTYPE ThreadAssignedToOSThread(ThreadID managedThreadId, DWORD osThreadId) override; 54 | HRESULT STDMETHODCALLTYPE RemotingClientInvocationStarted() override; 55 | HRESULT STDMETHODCALLTYPE RemotingClientSendingMessage(GUID* pCookie, BOOL fIsAsync) override; 56 | HRESULT STDMETHODCALLTYPE RemotingClientReceivingReply(GUID* pCookie, BOOL fIsAsync) override; 57 | HRESULT STDMETHODCALLTYPE RemotingClientInvocationFinished() override; 58 | HRESULT STDMETHODCALLTYPE RemotingServerReceivingMessage(GUID* pCookie, BOOL fIsAsync) override; 59 | HRESULT STDMETHODCALLTYPE RemotingServerInvocationStarted() override; 60 | HRESULT STDMETHODCALLTYPE RemotingServerInvocationReturned() override; 61 | HRESULT STDMETHODCALLTYPE RemotingServerSendingReply(GUID* pCookie, BOOL fIsAsync) override; 62 | HRESULT STDMETHODCALLTYPE UnmanagedToManagedTransition(FunctionID functionId, COR_PRF_TRANSITION_REASON reason) override; 63 | HRESULT STDMETHODCALLTYPE ManagedToUnmanagedTransition(FunctionID functionId, COR_PRF_TRANSITION_REASON reason) override; 64 | HRESULT STDMETHODCALLTYPE RuntimeSuspendStarted(COR_PRF_SUSPEND_REASON suspendReason) override; 65 | HRESULT STDMETHODCALLTYPE RuntimeSuspendFinished() override; 66 | HRESULT STDMETHODCALLTYPE RuntimeSuspendAborted() override; 67 | HRESULT STDMETHODCALLTYPE RuntimeResumeStarted() override; 68 | HRESULT STDMETHODCALLTYPE RuntimeResumeFinished() override; 69 | HRESULT STDMETHODCALLTYPE RuntimeThreadSuspended(ThreadID threadId) override; 70 | HRESULT STDMETHODCALLTYPE RuntimeThreadResumed(ThreadID threadId) override; 71 | HRESULT STDMETHODCALLTYPE MovedReferences(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], ULONG cObjectIDRangeLength[]) override; 72 | HRESULT STDMETHODCALLTYPE ObjectAllocated(ObjectID objectId, ClassID classId) override; 73 | HRESULT STDMETHODCALLTYPE ObjectsAllocatedByClass(ULONG cClassCount, ClassID classIds[], ULONG cObjects[]) override; 74 | HRESULT STDMETHODCALLTYPE ObjectReferences(ObjectID objectId, ClassID classId, ULONG cObjectRefs, ObjectID objectRefIds[]) override; 75 | HRESULT STDMETHODCALLTYPE RootReferences(ULONG cRootRefs, ObjectID rootRefIds[]) override; 76 | HRESULT STDMETHODCALLTYPE ExceptionThrown(ObjectID thrownObjectId) override; 77 | HRESULT STDMETHODCALLTYPE ExceptionSearchFunctionEnter(FunctionID functionId) override; 78 | HRESULT STDMETHODCALLTYPE ExceptionSearchFunctionLeave() override; 79 | HRESULT STDMETHODCALLTYPE ExceptionSearchFilterEnter(FunctionID functionId) override; 80 | HRESULT STDMETHODCALLTYPE ExceptionSearchFilterLeave() override; 81 | HRESULT STDMETHODCALLTYPE ExceptionSearchCatcherFound(FunctionID functionId) override; 82 | HRESULT STDMETHODCALLTYPE ExceptionOSHandlerEnter(UINT_PTR __unused) override; 83 | HRESULT STDMETHODCALLTYPE ExceptionOSHandlerLeave(UINT_PTR __unused) override; 84 | HRESULT STDMETHODCALLTYPE ExceptionUnwindFunctionEnter(FunctionID functionId) override; 85 | HRESULT STDMETHODCALLTYPE ExceptionUnwindFunctionLeave() override; 86 | HRESULT STDMETHODCALLTYPE ExceptionUnwindFinallyEnter(FunctionID functionId) override; 87 | HRESULT STDMETHODCALLTYPE ExceptionUnwindFinallyLeave() override; 88 | HRESULT STDMETHODCALLTYPE ExceptionCatcherEnter(FunctionID functionId, ObjectID objectId) override; 89 | HRESULT STDMETHODCALLTYPE ExceptionCatcherLeave() override; 90 | HRESULT STDMETHODCALLTYPE COMClassicVTableCreated(ClassID wrappedClassId, REFGUID implementedIID, void* pVTable, ULONG cSlots) override; 91 | HRESULT STDMETHODCALLTYPE COMClassicVTableDestroyed(ClassID wrappedClassId, REFGUID implementedIID, void* pVTable) override; 92 | HRESULT STDMETHODCALLTYPE ExceptionCLRCatcherFound() override; 93 | HRESULT STDMETHODCALLTYPE ExceptionCLRCatcherExecute() override; 94 | HRESULT STDMETHODCALLTYPE ThreadNameChanged(ThreadID threadId, ULONG cchName, WCHAR name[]) override; 95 | HRESULT STDMETHODCALLTYPE GarbageCollectionStarted(int cGenerations, BOOL generationCollected[], COR_PRF_GC_REASON reason) override; 96 | HRESULT STDMETHODCALLTYPE SurvivingReferences(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], ULONG cObjectIDRangeLength[]) override; 97 | HRESULT STDMETHODCALLTYPE GarbageCollectionFinished() override; 98 | HRESULT STDMETHODCALLTYPE FinalizeableObjectQueued(DWORD finalizerFlags, ObjectID objectID) override; 99 | HRESULT STDMETHODCALLTYPE RootReferences2(ULONG cRootRefs, ObjectID rootRefIds[], COR_PRF_GC_ROOT_KIND rootKinds[], COR_PRF_GC_ROOT_FLAGS rootFlags[], UINT_PTR rootIds[]) override; 100 | HRESULT STDMETHODCALLTYPE HandleCreated(GCHandleID handleId, ObjectID initialObjectId) override; 101 | HRESULT STDMETHODCALLTYPE HandleDestroyed(GCHandleID handleId) override; 102 | HRESULT STDMETHODCALLTYPE InitializeForAttach(IUnknown* pCorProfilerInfoUnk, void* pvClientData, UINT cbClientData) override; 103 | HRESULT STDMETHODCALLTYPE ProfilerAttachComplete() override; 104 | HRESULT STDMETHODCALLTYPE ProfilerDetachSucceeded() override; 105 | HRESULT STDMETHODCALLTYPE ReJITCompilationStarted(FunctionID functionId, ReJITID rejitId, BOOL fIsSafeToBlock) override; 106 | HRESULT STDMETHODCALLTYPE GetReJITParameters(ModuleID moduleId, mdMethodDef methodId, ICorProfilerFunctionControl* pFunctionControl) override; 107 | HRESULT STDMETHODCALLTYPE ReJITCompilationFinished(FunctionID functionId, ReJITID rejitId, HRESULT hrStatus, BOOL fIsSafeToBlock) override; 108 | HRESULT STDMETHODCALLTYPE ReJITError(ModuleID moduleId, mdMethodDef methodId, FunctionID functionId, HRESULT hrStatus) override; 109 | HRESULT STDMETHODCALLTYPE MovedReferences2(ULONG cMovedObjectIDRanges, ObjectID oldObjectIDRangeStart[], ObjectID newObjectIDRangeStart[], SIZE_T cObjectIDRangeLength[]) override; 110 | HRESULT STDMETHODCALLTYPE SurvivingReferences2(ULONG cSurvivingObjectIDRanges, ObjectID objectIDRangeStart[], SIZE_T cObjectIDRangeLength[]) override; 111 | HRESULT STDMETHODCALLTYPE ConditionalWeakTableElementReferences(ULONG cRootRefs, ObjectID keyRefIds[], ObjectID valueRefIds[], GCHandleID rootIds[]) override; 112 | HRESULT STDMETHODCALLTYPE GetAssemblyReferences(const WCHAR* wszAssemblyPath, ICorProfilerAssemblyReferenceProvider* pAsmRefProvider) override; 113 | HRESULT STDMETHODCALLTYPE ModuleInMemorySymbolsUpdated(ModuleID moduleId) override; 114 | 115 | HRESULT STDMETHODCALLTYPE DynamicMethodJITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock, LPCBYTE ilHeader, ULONG cbILHeader) override; 116 | HRESULT STDMETHODCALLTYPE DynamicMethodJITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) override; 117 | 118 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override 119 | { 120 | if (riid == __uuidof(ICorProfilerCallback8) || 121 | riid == __uuidof(ICorProfilerCallback7) || 122 | riid == __uuidof(ICorProfilerCallback6) || 123 | riid == __uuidof(ICorProfilerCallback5) || 124 | riid == __uuidof(ICorProfilerCallback4) || 125 | riid == __uuidof(ICorProfilerCallback3) || 126 | riid == __uuidof(ICorProfilerCallback2) || 127 | riid == __uuidof(ICorProfilerCallback) || 128 | riid == IID_IUnknown) 129 | { 130 | *ppvObject = this; 131 | this->AddRef(); 132 | return S_OK; 133 | } 134 | 135 | *ppvObject = nullptr; 136 | return E_NOINTERFACE; 137 | } 138 | 139 | ULONG STDMETHODCALLTYPE AddRef(void) override 140 | { 141 | return ++this->refCount; 142 | } 143 | 144 | ULONG STDMETHODCALLTYPE Release(void) override 145 | { 146 | int count = --this->refCount; 147 | 148 | if (count <= 0) 149 | { 150 | delete this; 151 | } 152 | 153 | return count; 154 | } 155 | }; 156 | -------------------------------------------------------------------------------- /src/profiler/src/FunctionInfo.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "stdafx.h" 5 | #include "FunctionInfo.h" 6 | 7 | FunctionInfo::FunctionInfo(FunctionID functionID, ClassID classID, ModuleID moduleID, mdToken token, LPWSTR functionName, LPWSTR className, LPWSTR assemblyName) 8 | { 9 | this->functionID = functionID; 10 | this->classID = classID; 11 | this->moduleID = moduleID; 12 | this->token = token; 13 | this->assemblyName = assemblyName; 14 | this->functionName = functionName; 15 | this->className = className; 16 | } 17 | 18 | FunctionInfo::~FunctionInfo() 19 | { 20 | } 21 | 22 | FunctionID FunctionInfo::GetFunctionID() 23 | { 24 | return functionID; 25 | } 26 | 27 | ClassID FunctionInfo::GetClassID() 28 | { 29 | return classID; 30 | } 31 | 32 | ModuleID FunctionInfo::GetModuleID() 33 | { 34 | return moduleID; 35 | } 36 | 37 | mdToken FunctionInfo::GetToken() 38 | { 39 | return token; 40 | } 41 | 42 | LPWSTR FunctionInfo::GetClassName() 43 | { 44 | return className; 45 | } 46 | 47 | LPWSTR FunctionInfo::GetFunctionName() 48 | { 49 | return functionName; 50 | } 51 | 52 | LPWSTR FunctionInfo::GetAssemblyName() 53 | { 54 | return assemblyName; 55 | } 56 | -------------------------------------------------------------------------------- /src/profiler/src/FunctionInfo.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma once 5 | #include "corprof.h" 6 | #include "CorHdr.h" 7 | #include "cor.h" 8 | 9 | class FunctionInfo 10 | { 11 | public: 12 | FunctionInfo(FunctionID functionID, ClassID classID, ModuleID moduleID, mdToken token, LPWSTR functionName, LPWSTR className, LPWSTR assemblyName); 13 | ~FunctionInfo(); 14 | 15 | FunctionID GetFunctionID(); 16 | ClassID GetClassID(); 17 | ModuleID GetModuleID(); 18 | mdToken GetToken(); 19 | LPWSTR GetClassName(); 20 | LPWSTR GetFunctionName(); 21 | LPWSTR GetAssemblyName(); 22 | 23 | private: 24 | FunctionID functionID; 25 | ClassID classID; 26 | ModuleID moduleID; 27 | mdToken token; 28 | LPWSTR className; 29 | LPWSTR functionName; 30 | LPWSTR assemblyName; 31 | }; 32 | -------------------------------------------------------------------------------- /src/profiler/src/ILWriter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "stdafx.h" 5 | #include "ILWriter.h" 6 | #include 7 | 8 | ILWriter::ILWriter(ICorProfilerInfo* profilerInfo, FunctionInfo* functionInfo) 9 | { 10 | ModuleID moduleID = functionInfo->GetModuleID(); 11 | mdToken mdtoken = functionInfo->GetToken(); 12 | LPCBYTE methodHeader; 13 | ULONG methodSize; 14 | 15 | HRESULT hr = profilerInfo->GetILFunctionBody(moduleID, mdtoken, &methodHeader, &methodSize); 16 | 17 | if (FAILED(hr)) 18 | { 19 | return; 20 | } 21 | 22 | if (!((COR_ILMETHOD_TINY*)methodHeader)->IsTiny()) 23 | { 24 | this->identifier = FatMethod; 25 | } 26 | else 27 | { 28 | if (methodSize <= (MaximumSize - InjectedCodeSize)) 29 | { 30 | this->identifier = TinyMethod; 31 | } 32 | else 33 | { 34 | this->identifier = OtherMethod; 35 | } 36 | } 37 | 38 | this->profilerInfo = profilerInfo; 39 | this->functionInfo = functionInfo; 40 | this->methodHeader = methodHeader; 41 | this->methodSize = methodSize; 42 | } 43 | 44 | ILWriter::~ILWriter() 45 | { 46 | } 47 | 48 | BOOL ILWriter::Write() 49 | { 50 | ModuleID moduleID = functionInfo->GetModuleID(); 51 | mdToken functionToken = functionInfo->GetToken(); 52 | LPCBYTE newILHeader = (LPCBYTE)GetNewILHeader(); 53 | 54 | HRESULT hr = profilerInfo->SetILFunctionBody(moduleID, functionToken, newILHeader); 55 | 56 | if (FAILED(hr)) 57 | { 58 | return FALSE; 59 | } 60 | 61 | return TRUE; 62 | } 63 | 64 | ULONG ILWriter::GetNewMethodTotalSize() 65 | { 66 | if (identifier == FatMethod) 67 | { 68 | return methodSize + InjectedCodeSize + GetOffset(); 69 | } 70 | else 71 | { 72 | return methodSize + InjectedCodeSize; 73 | } 74 | } 75 | 76 | ULONG ILWriter::GetOffset() 77 | { 78 | if (!(((COR_ILMETHOD_FAT*)methodHeader)->GetFlags() & CorILMethod_MoreSects)) 79 | { 80 | return 0; 81 | } 82 | else 83 | { 84 | ULONG oldMethodSize = FatMethodHeader + ((COR_ILMETHOD_FAT*)methodHeader)->GetCodeSize(); 85 | ULONG newMethodSize = FatMethodHeader + ((COR_ILMETHOD_FAT*)methodHeader)->GetCodeSize() + InjectedCodeSize; 86 | ULONG oldOffset = (int)((BYTE*)((COR_ILMETHOD_FAT*)methodHeader)->GetSect() - (BYTE*)((BYTE*)methodHeader + oldMethodSize)); 87 | ULONG mod = sizeof(DWORD); 88 | ULONG remainder = newMethodSize % mod; 89 | 90 | ULONG newOffset = 0; 91 | if (remainder != 0) 92 | { 93 | newOffset = mod - remainder; 94 | } 95 | 96 | return newOffset - oldOffset; 97 | } 98 | } 99 | 100 | void* ILWriter::GetNewILHeader() 101 | { 102 | ModuleID moduleId = functionInfo->GetModuleID(); 103 | IMethodMalloc* allocator = NULL; 104 | HRESULT hr = profilerInfo->GetILFunctionBodyAllocator(moduleId, &allocator); 105 | if (FAILED(hr) || allocator == NULL) 106 | { 107 | return NULL; 108 | } 109 | 110 | IMetaDataEmit* iMetaDataEmit = NULL; 111 | DWORD OpenFlags = ofRead | ofWrite; 112 | hr = profilerInfo->GetModuleMetaData(moduleId, OpenFlags, IID_IMetaDataEmit, (IUnknown**)&iMetaDataEmit); 113 | if (FAILED(hr) || iMetaDataEmit == NULL) 114 | { 115 | return NULL; 116 | } 117 | 118 | ULONG newMethodTotalSize = GetNewMethodTotalSize(); 119 | BYTE* codeBuffer = (BYTE*)allocator->Alloc(newMethodTotalSize); 120 | if (codeBuffer == NULL) 121 | { 122 | return NULL; 123 | } 124 | 125 | allocator->Release(); 126 | 127 | IMetaDataAssemblyEmit* iMetaDataAssemblyEmit = NULL; 128 | hr = iMetaDataEmit->QueryInterface(IID_IMetaDataAssemblyEmit, (void**)&iMetaDataAssemblyEmit); 129 | if (FAILED(hr) || iMetaDataAssemblyEmit == NULL) 130 | { 131 | return NULL; 132 | } 133 | 134 | const BYTE publicKey[] = { 0xd4, 0x27, 0x00, 0x1f, 0x96, 0xb0, 0xd0, 0xb6 }; // d427001f96b0d0b6 135 | LPCWSTR autoInstrumentationAssemblyName = L"AWSXRayRecorder.AutoInstrumentation"; 136 | ASSEMBLYMETADATA autoInstrumentationAssemblyMetaData = {0}; 137 | mdModuleRef autoInstrumentationAssemblyToken; 138 | hr = iMetaDataAssemblyEmit->DefineAssemblyRef(publicKey, sizeof(publicKey), autoInstrumentationAssemblyName, &autoInstrumentationAssemblyMetaData, NULL, 0, 0, &autoInstrumentationAssemblyToken); 139 | if (FAILED(hr)) 140 | { 141 | return NULL; 142 | } 143 | 144 | iMetaDataAssemblyEmit->Release(); 145 | 146 | LPCWSTR autoInstrumentationClassName = L"Amazon.XRay.Recorder.AutoInstrumentation.Initialize"; 147 | mdTypeRef autoInstrumentationClassToken; 148 | hr = iMetaDataEmit->DefineTypeRefByName(autoInstrumentationAssemblyToken, autoInstrumentationClassName, &autoInstrumentationClassToken); 149 | if (FAILED(hr)) 150 | { 151 | return NULL; 152 | } 153 | 154 | LPCWSTR autoInstrumentationMethodName = L"AddXRay"; 155 | const BYTE autoInstrumentationMethodSignature[] = { IMAGE_CEE_CS_CALLCONV_DEFAULT, 0, ELEMENT_TYPE_VOID }; //0 arg, void 156 | mdMemberRef autoInstrumentationMethodToken; 157 | hr = iMetaDataEmit->DefineMemberRef(autoInstrumentationClassToken, autoInstrumentationMethodName, autoInstrumentationMethodSignature, sizeof(autoInstrumentationMethodSignature), &autoInstrumentationMethodToken); 158 | if (FAILED(hr)) 159 | { 160 | return NULL; 161 | } 162 | 163 | iMetaDataEmit->Release(); 164 | 165 | InjectedCode* injectedCode = new InjectedCode(); 166 | injectedCode->nop = 0x00; 167 | injectedCode->call = 0x28; 168 | 169 | if (identifier == FatMethod) 170 | { 171 | memcpy_s( 172 | codeBuffer, 173 | newMethodTotalSize, 174 | methodHeader, 175 | FatMethodHeader); 176 | 177 | WORD maxStack = (WORD)((COR_ILMETHOD_FAT*)methodHeader)->MaxStack + InjectedCodeSize / 2; 178 | memcpy_s( 179 | codeBuffer + sizeof(WORD), 180 | newMethodTotalSize - sizeof(WORD), 181 | &maxStack, 182 | sizeof(WORD)); 183 | 184 | DWORD newMethodBodySize = ((COR_ILMETHOD_FAT*)methodHeader)->GetCodeSize() + InjectedCodeSize; 185 | memcpy_s( 186 | codeBuffer + sizeof(DWORD), 187 | newMethodTotalSize - sizeof(DWORD), 188 | &newMethodBodySize, 189 | sizeof(DWORD)); 190 | 191 | memcpy_s( 192 | injectedCode->token, 193 | sizeof(injectedCode->token), 194 | (void*)&autoInstrumentationMethodToken, 195 | sizeof(autoInstrumentationMethodToken)); 196 | 197 | memcpy_s( 198 | codeBuffer + FatMethodHeader, 199 | newMethodTotalSize - FatMethodHeader, 200 | injectedCode, 201 | InjectedCodeSize); 202 | 203 | ULONG oldMethodBodySize = ((COR_ILMETHOD_FAT*)methodHeader)->GetCodeSize(); 204 | 205 | memcpy_s( 206 | codeBuffer + FatMethodHeader + InjectedCodeSize, 207 | newMethodTotalSize - FatMethodHeader - InjectedCodeSize, 208 | (BYTE*)methodHeader + FatMethodHeader, 209 | oldMethodBodySize); 210 | 211 | ULONG oldMethodSize = FatMethodHeader + ((COR_ILMETHOD_FAT*)methodHeader)->GetCodeSize(); 212 | ULONG extraSectionSize = methodSize - oldMethodSize; 213 | memcpy_s( 214 | codeBuffer + FatMethodHeader + InjectedCodeSize + oldMethodBodySize, 215 | newMethodTotalSize - FatMethodHeader - InjectedCodeSize - oldMethodBodySize + GetOffset(), 216 | (BYTE*)methodHeader + (methodSize - extraSectionSize - GetOffset()), 217 | extraSectionSize); 218 | 219 | if (((COR_ILMETHOD_FAT*)methodHeader)->GetFlags() & CorILMethod_MoreSects) 220 | { 221 | FixSEHSections(codeBuffer, InjectedCodeSize); 222 | } 223 | } 224 | else if (identifier == TinyMethod) 225 | { 226 | ULONG newMethodBodySize = ((COR_ILMETHOD_TINY*)methodHeader)->GetCodeSize() + InjectedCodeSize; 227 | 228 | BYTE newBodySize = (BYTE)(CorILMethod_TinyFormat | (newMethodBodySize << 2)); 229 | memcpy_s( 230 | codeBuffer, 231 | newMethodTotalSize, 232 | &newBodySize, 233 | TinyMethodHeader); 234 | memcpy_s( 235 | injectedCode->token, 236 | sizeof(injectedCode->token), 237 | (void*)&autoInstrumentationMethodToken, 238 | sizeof(autoInstrumentationMethodToken)); 239 | memcpy_s( 240 | codeBuffer + TinyMethodHeader, 241 | newMethodTotalSize - TinyMethodHeader, 242 | injectedCode, 243 | InjectedCodeSize); 244 | 245 | ULONG oldMethodBodySize = ((COR_ILMETHOD_TINY*)methodHeader)->GetCodeSize(); 246 | 247 | memcpy_s( 248 | codeBuffer + TinyMethodHeader + InjectedCodeSize, 249 | newMethodTotalSize - TinyMethodHeader - InjectedCodeSize, 250 | (BYTE*)methodHeader + TinyMethodHeader, 251 | oldMethodBodySize); 252 | 253 | } 254 | else if (identifier == OtherMethod) 255 | { 256 | BYTE flags[] = { 0x03, 0x30, }; 257 | memcpy_s( 258 | codeBuffer, 259 | newMethodTotalSize, 260 | &flags, 261 | sizeof(WORD)); 262 | 263 | WORD maxStack = 1 + (InjectedCodeSize / 2); 264 | memcpy_s( 265 | codeBuffer + sizeof(WORD), 266 | newMethodTotalSize - sizeof(WORD), 267 | &maxStack, 268 | sizeof(WORD)); 269 | 270 | DWORD newMethodBodySize = ((COR_ILMETHOD_TINY*)methodHeader)->GetCodeSize() + InjectedCodeSize; 271 | memcpy_s( 272 | codeBuffer + sizeof(DWORD), 273 | newMethodTotalSize - sizeof(DWORD), 274 | &newMethodBodySize, 275 | sizeof(DWORD)); 276 | memcpy_s( 277 | injectedCode->token, 278 | sizeof(injectedCode->token), 279 | (void*)&autoInstrumentationMethodToken, 280 | sizeof(autoInstrumentationMethodToken)); 281 | memcpy_s( 282 | codeBuffer + FatMethodHeader, 283 | newMethodTotalSize - FatMethodHeader, 284 | injectedCode, 285 | InjectedCodeSize); 286 | 287 | ULONG oldMethodBodySize = ((COR_ILMETHOD_TINY*)methodHeader)->GetCodeSize(); 288 | 289 | memcpy_s( 290 | codeBuffer + FatMethodHeader + InjectedCodeSize, 291 | newMethodTotalSize - FatMethodHeader - InjectedCodeSize, 292 | (BYTE*)methodHeader + TinyMethodHeader, 293 | oldMethodBodySize); 294 | } 295 | 296 | return codeBuffer; 297 | } 298 | 299 | void ILWriter::FixSEHSections(BYTE* codeBuffer, ULONG offset) 300 | { 301 | COR_ILMETHOD_FAT* fatMethod = (COR_ILMETHOD_FAT*)codeBuffer; 302 | 303 | const COR_ILMETHOD_SECT* sections = fatMethod->GetSect(); 304 | 305 | while (sections) 306 | { 307 | if (sections->Kind() == CorILMethod_Sect_EHTable) 308 | { 309 | COR_ILMETHOD_SECT_EH* eh = (COR_ILMETHOD_SECT_EH*)sections; 310 | 311 | if (eh->IsFat()) 312 | { 313 | COR_ILMETHOD_SECT_EH_FAT* EHFat = (COR_ILMETHOD_SECT_EH_FAT*)eh; 314 | 315 | for (UINT i = 0; i < eh->EHCount(); i++) 316 | { 317 | IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clause = &EHFat->Clauses[i]; 318 | 319 | if (clause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) 320 | { 321 | clause->FilterOffset += offset; 322 | } 323 | 324 | clause->TryOffset += offset; 325 | clause->HandlerOffset += offset; 326 | } 327 | } 328 | else 329 | { 330 | COR_ILMETHOD_SECT_EH_SMALL* EHSmall = (COR_ILMETHOD_SECT_EH_SMALL*)eh; 331 | 332 | for (UINT i = 0; i < eh->EHCount(); i++) 333 | { 334 | IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* clause = &EHSmall->Clauses[i]; 335 | 336 | if (clause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) 337 | { 338 | clause->FilterOffset += offset; 339 | } 340 | 341 | clause->TryOffset += offset; 342 | clause->HandlerOffset += offset; 343 | } 344 | } 345 | } 346 | 347 | sections = sections->Next(); 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /src/profiler/src/ILWriter.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma once 5 | #include "FunctionInfo.h" 6 | 7 | #define FatMethod 1 8 | #define TinyMethod 2 9 | #define OtherMethod 3 10 | #define MaximumSize 64 11 | 12 | #define FatMethodHeader sizeof(WORD) + sizeof(WORD) + sizeof(DWORD) + sizeof(DWORD) // 12 bytes 13 | #define TinyMethodHeader sizeof(BYTE) 14 | #define InjectedCodeSize sizeof(InjectedCode) 15 | 16 | typedef struct 17 | { 18 | BYTE nop; 19 | BYTE call; 20 | BYTE token[4]; 21 | } InjectedCode; 22 | 23 | 24 | class ILWriter 25 | { 26 | public: 27 | ILWriter(ICorProfilerInfo* profilerInfo, FunctionInfo* functionInfo); 28 | 29 | ~ILWriter(); 30 | 31 | ULONG GetNewMethodTotalSize(); 32 | 33 | BOOL Write(); 34 | void* GetNewILHeader(); 35 | 36 | ULONG GetOffset(); 37 | void FixSEHSections(BYTE* methodBytes, ULONG newILSize); 38 | 39 | private: 40 | 41 | ULONG identifier = 0; 42 | ICorProfilerInfo* profilerInfo = NULL; 43 | FunctionInfo* functionInfo = NULL; 44 | LPCBYTE methodHeader = NULL; 45 | ULONG methodSize = 0; 46 | }; 47 | -------------------------------------------------------------------------------- /src/profiler/src/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "ClassFactory.h" 5 | #include "assert.h" 6 | 7 | BOOL STDMETHODCALLTYPE DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 8 | { 9 | return TRUE; 10 | } 11 | 12 | extern "C" HRESULT STDMETHODCALLTYPE DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) 13 | { 14 | // {AE47A175-390A-4F13-84CB-7169CEBF064A} 15 | const GUID CLSID_CorProfiler = { 0xAE47A175, 0x390A, 0x4F13, { 0x84, 0xCB, 0x71, 0x69, 0xCE, 0xBF, 0x06, 0x4A } }; 16 | 17 | if (ppv == nullptr || rclsid != CLSID_CorProfiler) 18 | { 19 | return E_FAIL; 20 | } 21 | 22 | auto factory = new ClassFactory(); 23 | if (factory == nullptr) 24 | { 25 | return E_FAIL; 26 | } 27 | 28 | assert(riid == IID_IUnknown || riid == IID_IClassFactory); 29 | 30 | return factory->QueryInterface(riid, ppv); 31 | } 32 | 33 | extern "C" HRESULT STDMETHODCALLTYPE DllCanUnloadNow() 34 | { 35 | return S_OK; 36 | } 37 | -------------------------------------------------------------------------------- /src/profiler/src/stdafx.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma once 5 | 6 | #include "cor.h" 7 | #include "corprof.h" 8 | #include "corhlpr.h" 9 | -------------------------------------------------------------------------------- /src/sdk/AWSXRayRecorder.AutoInstrumentation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net45;netstandard2.0 5 | Amazon.com, Inc 6 | Amazon Web Service X-Ray Recorder 7 | Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 8 | 2.10.0.0 9 | 2.10.0.0 10 | 2.10.0-beta.1 11 | Amazon.XRay.Recorder.AutoInstrumentation 12 | true 13 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml 14 | ..\..\buildtools\local-development.snk 15 | http://aws.amazon.com/apache2.0/ 16 | https://aws.amazon.com/documentation/xray/ 17 | https://sdk-for-net.amazonwebservices.com/images/AWSLogo128x128.png 18 | This package contains libraries for Auto-Instrumentation of Asp.Net Core and Asp.Net web applications. 19 | AWS Amazon cloud AWSXRay XRay 20 | Amazon Web Services 21 | https://github.com/aws/aws-xray-dotnet-agent 22 | 23 | 24 | 25 | 1591 26 | 27 | 28 | 29 | 1591 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/sdk/AspNet/AspNetAutoInstrumentationModule.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 20 | using System.Collections.Concurrent; 21 | using System.Web; 22 | 23 | namespace Amazon.XRay.Recorder.AutoInstrumentation 24 | { 25 | /// 26 | /// This class aims to intercept Http incoming request for ASP.NET Framework. 27 | /// 28 | public class AspNetAutoInstrumentationModule : IHttpModule 29 | { 30 | private HttpApplication currentHttpApplication; 31 | 32 | private static readonly ConcurrentDictionary ActiveHttpApplications = new ConcurrentDictionary(); 33 | 34 | static AspNetAutoInstrumentationModule() 35 | { 36 | AspNetRequestUtil.InitializeAspNet(); 37 | } 38 | 39 | public void Init(HttpApplication httpApplication) 40 | { 41 | if (ActiveHttpApplications.TryAdd(httpApplication, 0)) 42 | { 43 | currentHttpApplication = httpApplication; 44 | currentHttpApplication.BeginRequest += AspNetRequestUtil.ProcessHTTPRequest; 45 | currentHttpApplication.EndRequest += AspNetRequestUtil.ProcessHTTPResponse; 46 | currentHttpApplication.Error += AspNetRequestUtil.ProcessHTTPError; 47 | } 48 | } 49 | 50 | public void Dispose() 51 | { 52 | if (currentHttpApplication != null) 53 | { 54 | ActiveHttpApplications.TryRemove(currentHttpApplication, out _); 55 | currentHttpApplication = null; 56 | } 57 | } 58 | } 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /src/sdk/AspNetCore/AspNetCoreDiagnosticListener.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core; 21 | using Amazon.XRay.Recorder.Core.Strategies; 22 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 23 | using Microsoft.AspNetCore.Http; 24 | using System; 25 | using System.Collections.Generic; 26 | 27 | namespace Amazon.XRay.Recorder.AutoInstrumentation 28 | { 29 | /// 30 | /// Diagnostic listener for processing Asp.Net Core incoming request 31 | /// 32 | public class AspNetCoreDiagnosticListener : DiagnosticListenerBase 33 | { 34 | private static readonly Logger _logger = Logger.GetLogger(typeof(AspNetCoreDiagnosticListener)); 35 | 36 | internal override string Name => "Microsoft.AspNetCore"; 37 | 38 | internal AspNetCoreDiagnosticListener(string serviceName) 39 | { 40 | AspNetCoreRequestUtil.SetAWSXRayRecorder(AWSXRayRecorder.Instance); 41 | AspNetCoreRequestUtil.SetSegmentNamingStrategy(new FixedSegmentNamingStrategy(serviceName)); 42 | } 43 | 44 | protected override void OnEvent(KeyValuePair value) 45 | { 46 | try 47 | { 48 | switch (value.Key) 49 | { 50 | case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start": 51 | { 52 | OnEventStart(value.Value); 53 | } 54 | break; 55 | case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop": 56 | { 57 | OnEventStop(value.Value); 58 | } 59 | break; 60 | case "Microsoft.AspNetCore.Diagnostics.UnhandledException": 61 | { 62 | OnEventException(value.Value); 63 | } 64 | break; 65 | } 66 | } 67 | catch (Exception e) 68 | { 69 | _logger.Error(e, "Invalid diagnostic source key ({0})", value.Key); 70 | } 71 | } 72 | 73 | private void OnEventStart(object value) 74 | { 75 | var context = AgentUtil.FetchPropertyUsingReflection(value, "HttpContext"); 76 | if (context is HttpContext httpContext) 77 | { 78 | AspNetCoreRequestUtil.ProcessRequest(httpContext); 79 | } 80 | } 81 | 82 | private void OnEventStop(object value) 83 | { 84 | var context = AgentUtil.FetchPropertyUsingReflection(value, "HttpContext"); 85 | if (context is HttpContext httpContext) 86 | { 87 | AspNetCoreRequestUtil.ProcessResponse(httpContext); 88 | } 89 | } 90 | 91 | private void OnEventException(object value) 92 | { 93 | // The value passed in is not castable, use fetch from reflection. 94 | var exc = AgentUtil.FetchPropertyUsingReflection(value, "Exception"); 95 | if (exc is Exception exception) 96 | { 97 | AspNetCoreRequestUtil.ProcessException(exception); 98 | } 99 | } 100 | } 101 | } 102 | #endif 103 | -------------------------------------------------------------------------------- /src/sdk/AwsSdk/AWSSDKRequestRegister.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using Amazon.XRay.Recorder.Handlers.AwsSdk; 19 | 20 | namespace Amazon.XRay.Recorder.AutoInstrumentation 21 | { 22 | /// 23 | /// Register XRay for AWS services 24 | /// 25 | public class AWSSDKRequestRegister 26 | { 27 | public static void Register() 28 | { 29 | AWSSDKHandler.RegisterXRayForAllServices(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/sdk/Configuration/XRayAutoInstrumentationOptions.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | namespace Amazon.XRay.Recorder.AutoInstrumentation 19 | { 20 | /// 21 | /// This is a class for storing Auto-Instrumentation related configurations from IConfiguration instance. 22 | /// For other X-Ray .Net SDK configurations, take reference to https://github.com/aws/aws-xray-sdk-dotnet/tree/master#configuration 23 | /// 24 | public class XRayAutoInstrumentationOptions 25 | { 26 | /// 27 | /// Service name of instrumented Asp.Net or Asp.Net Core application 28 | /// 29 | public string ServiceName { get; } = "DefaultService"; 30 | 31 | /// 32 | /// Daemon address 33 | /// 34 | public string DaemonAddress { get; } = "127.0.0.1:2000"; 35 | 36 | /// 37 | /// Enable tracing Http request 38 | /// 39 | public bool TraceHttpRequests { get; } = true; 40 | 41 | /// 42 | /// Enable tracing AWS request 43 | /// 44 | public bool TraceAWSRequests { get; } = true; 45 | 46 | /// 47 | /// Enable tracing Sql request 48 | /// 49 | public bool TraceSqlRequests { get; } = true; 50 | 51 | /// 52 | /// Enable tracing Entity Framework request 53 | /// 54 | public bool TraceEFRequests { get; } = true; 55 | 56 | /// 57 | /// Default constructor 58 | /// 59 | public XRayAutoInstrumentationOptions() 60 | { 61 | } 62 | 63 | public XRayAutoInstrumentationOptions(string serviceName, string daemonAddress, bool traceHttpRequests, bool traceAWSRequests, bool traceSqlRequests, bool traceEFRequests) 64 | { 65 | ServiceName = serviceName; 66 | DaemonAddress = daemonAddress; 67 | TraceHttpRequests = traceHttpRequests; 68 | TraceAWSRequests = traceAWSRequests; 69 | TraceSqlRequests = traceSqlRequests; 70 | TraceEFRequests = traceEFRequests; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/sdk/Configuration/XRayConfiguration.Net45.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using System.Configuration; 20 | 21 | namespace Amazon.XRay.Recorder.AutoInstrumentation 22 | { 23 | /// 24 | /// Class for register Auto-Instrumentation SDK configurations for Asp.Net application 25 | /// 26 | public class XRayConfiguration 27 | { 28 | public static XRayAutoInstrumentationOptions Register() 29 | { 30 | var serviceName = GetSettingServiceName("ServiceName"); 31 | var daemonAddress = GetSettingDaemonAddress("DaemonAddress"); 32 | var traceHttpRequests = GetSettingBool("TraceHttpRequests"); 33 | var traceAWSRequests = GetSettingBool("TraceAWSRequests"); 34 | var traceSqlRequests = GetSettingBool("TraceSqlRequests"); 35 | var traceEFRequests = GetSettingBool("TraceEFRequests"); 36 | 37 | var xrayAutoInstrumentationOptions = new XRayAutoInstrumentationOptions(serviceName, daemonAddress, traceHttpRequests, traceAWSRequests, traceSqlRequests, traceEFRequests); 38 | 39 | return xrayAutoInstrumentationOptions; 40 | } 41 | 42 | private static string GetSetting(string key) 43 | { 44 | var appSettings = ConfigurationManager.AppSettings; 45 | if (appSettings == null) 46 | { 47 | return null; 48 | } 49 | 50 | string value = appSettings[key]; 51 | return value; 52 | } 53 | 54 | private static bool GetSettingBool(string key, bool defaultValue = true) 55 | { 56 | string value = GetSetting(key); 57 | if (bool.TryParse(value, out bool result)) 58 | { 59 | return result; 60 | } 61 | 62 | return defaultValue; 63 | } 64 | 65 | private static string GetSettingDaemonAddress(string key, string defaultValue = "127.0.0.1:2000") 66 | { 67 | string value = GetSetting(key); 68 | if (value == null) 69 | { 70 | return defaultValue; 71 | } 72 | 73 | return value; 74 | } 75 | 76 | private static string GetSettingServiceName(string key, string defaultValue = "DefaultService") 77 | { 78 | string value = GetSetting(key); 79 | if (value == null) 80 | { 81 | return defaultValue; 82 | } 83 | 84 | return value; 85 | } 86 | } 87 | } 88 | #endif 89 | -------------------------------------------------------------------------------- /src/sdk/Configuration/XRayConfiguration.Netstandard.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core; 21 | using Microsoft.Extensions.Configuration; 22 | using System; 23 | using System.IO; 24 | 25 | namespace Amazon.XRay.Recorder.AutoInstrumentation 26 | { 27 | /// 28 | /// Class for register X-Ray .Net SDK and Auto-Instrumentation SDK configurations 29 | /// 30 | public static class XRayConfiguration 31 | { 32 | 33 | private static readonly Logger _logger = Logger.GetLogger(typeof(XRayConfiguration)); 34 | 35 | /// 36 | /// Instrument tracing configurations, such as pluggins, sampling rules, service name, etc., from AspNet Core application. 37 | /// 38 | public static XRayAutoInstrumentationOptions Register() 39 | { 40 | IConfiguration configuration = null; 41 | try 42 | { 43 | // Get the json file 44 | configuration = new ConfigurationBuilder() 45 | .SetBasePath(Directory.GetCurrentDirectory()) 46 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 47 | .Build(); 48 | } 49 | catch (Exception e) 50 | { 51 | _logger.Error(e, "Can't fetch configuration from appsettings.json file."); 52 | } 53 | 54 | // Initialize a new instance of the AWSXRayRecorder with given instance of IConfiguration. 55 | // If configuration is null, default value will be set. 56 | AWSXRayRecorder.InitializeInstance(configuration); 57 | 58 | var xrayAutoInstrumentationOptions = GetXRayAutoInstrumentationOptions(configuration); 59 | 60 | // Set daemon address 61 | AWSXRayRecorder.Instance.SetDaemonAddress(xrayAutoInstrumentationOptions.DaemonAddress); 62 | 63 | return xrayAutoInstrumentationOptions; 64 | } 65 | 66 | /// 67 | /// Initialize Auto-Instrumentation configuration items from instance . 68 | /// 69 | public static XRayAutoInstrumentationOptions GetXRayAutoInstrumentationOptions(IConfiguration configuration) 70 | { 71 | 72 | IConfiguration xraySection = configuration?.GetSection("XRay"); 73 | 74 | if (xraySection == null) 75 | { 76 | return new XRayAutoInstrumentationOptions(); 77 | } 78 | 79 | // Get Auto-Instrumentation related configuration items from appsetting.json file 80 | var serviceName = GetSettingServiceName("ServiceName", xraySection); 81 | var daemonAddress = GetSettingDaemonAddress("DaemonAddress", xraySection); 82 | var traceHttpRequests = GetSettingBool("TraceHttpRequests", xraySection); 83 | var traceAWSRequests = GetSettingBool("TraceAWSRequests", xraySection); 84 | var traceSqlRequests = GetSettingBool("TraceSqlRequests", xraySection); 85 | var traceEFRequests = GetSettingBool("TraceEFRequests", xraySection); 86 | 87 | var xrayAutoInstrumentationOptions = new XRayAutoInstrumentationOptions(serviceName, daemonAddress, traceHttpRequests, traceAWSRequests, traceSqlRequests, traceEFRequests); 88 | 89 | return xrayAutoInstrumentationOptions; 90 | } 91 | 92 | private static string GetSettingServiceName(string key, IConfiguration section, string defaultValue = "DefaultService") 93 | { 94 | if (!string.IsNullOrEmpty(section[key])) 95 | { 96 | return section[key]; 97 | } 98 | 99 | return defaultValue; 100 | } 101 | 102 | private static string GetSettingDaemonAddress(string key, IConfiguration section, string defaultValue = "127.0.0.1:2000") 103 | { 104 | if (!string.IsNullOrEmpty(section[key])) 105 | { 106 | return section[key]; 107 | } 108 | 109 | return defaultValue; 110 | } 111 | 112 | private static bool GetSettingBool(string key, IConfiguration section, bool defaultValue = true) 113 | { 114 | string value = section[key]; 115 | if (bool.TryParse(value, out bool result)) 116 | { 117 | return result; 118 | } 119 | 120 | return defaultValue; 121 | } 122 | } 123 | } 124 | #endif 125 | -------------------------------------------------------------------------------- /src/sdk/Diagnostic/DiagnosticListenerBase.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace Amazon.XRay.Recorder.AutoInstrumentation 22 | { 23 | /// 24 | /// Base class of diagnostic listener for processing events 25 | /// 26 | public abstract class DiagnosticListenerBase : IObserver> 27 | { 28 | internal abstract string Name { get; } 29 | 30 | public void OnNext(KeyValuePair value) 31 | { 32 | OnEvent(value); 33 | } 34 | 35 | protected abstract void OnEvent(KeyValuePair value); 36 | 37 | public void OnError(Exception error) 38 | { 39 | } 40 | 41 | public void OnCompleted() 42 | { 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/sdk/Diagnostic/DiagnosticListenerObserver.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Diagnostics; 21 | 22 | namespace Amazon.XRay.Recorder.AutoInstrumentation 23 | { 24 | /// 25 | /// Class for diagnostic observer 26 | /// 27 | public class DiagnosticListenerObserver : IObserver, IDisposable 28 | { 29 | private readonly IList _diagnosticListeners; 30 | private readonly List _subscriptions = new List(); 31 | 32 | public DiagnosticListenerObserver(IList diagnosticListeners) 33 | { 34 | _diagnosticListeners = diagnosticListeners; 35 | } 36 | 37 | public void Dispose() 38 | { 39 | foreach (var sub in _subscriptions) 40 | { 41 | sub.Dispose(); 42 | } 43 | _subscriptions.Clear(); 44 | } 45 | 46 | /// 47 | /// Subscribe diagnostic lsitener as long as its name matches . 48 | /// 49 | public void OnNext(DiagnosticListener diagnosticListener) 50 | { 51 | foreach (var _diagnosticListener in _diagnosticListeners) 52 | { 53 | if (diagnosticListener.Name == _diagnosticListener.Name) 54 | { 55 | var subscription = diagnosticListener.Subscribe(_diagnosticListener); 56 | _subscriptions.Add(subscription); 57 | break; 58 | } 59 | } 60 | } 61 | 62 | public void OnCompleted() 63 | { 64 | Dispose(); 65 | } 66 | 67 | public void OnError(Exception error) 68 | { 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/sdk/EntityFramework/EntityFrameworkCoreDiagnosticListener.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 21 | using Microsoft.EntityFrameworkCore.Diagnostics; 22 | using System; 23 | using System.Collections.Generic; 24 | using System.Data.Common; 25 | 26 | namespace Amazon.XRay.Recorder.AutoInstrumentation 27 | { 28 | /// 29 | /// Diagnostic listener for processing EntityFramework Core request 30 | /// 31 | public class EntityFrameworkCoreDiagnosticListener : DiagnosticListenerBase 32 | { 33 | private static readonly Logger _logger = Logger.GetLogger(typeof(EntityFrameworkCoreDiagnosticListener)); 34 | 35 | internal override string Name => "Microsoft.EntityFrameworkCore"; 36 | 37 | protected override void OnEvent(KeyValuePair value) 38 | { 39 | 40 | try 41 | { 42 | switch (value.Key) 43 | { 44 | case "Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting": 45 | { 46 | OnEventStart(value.Value); 47 | } 48 | break; 49 | case "Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted": 50 | { 51 | OnEventStop(value.Value); 52 | } 53 | break; 54 | case "Microsoft.EntityFrameworkCore.Database.Command.CommandError": 55 | { 56 | OnEventException(value.Value); 57 | } 58 | break; 59 | } 60 | } 61 | catch (Exception e) 62 | { 63 | _logger.Error(e, "Invalid diagnostic source key ({0})", value.Key); 64 | } 65 | } 66 | 67 | private void OnEventStart(object value) 68 | { 69 | var command = ((CommandEventData)value).Command; 70 | if (command is DbCommand dbCommand) 71 | { 72 | SqlRequestUtil.BeginSubsegment(dbCommand); 73 | SqlRequestUtil.ProcessCommand(dbCommand); 74 | } 75 | } 76 | 77 | private void OnEventStop(object value) 78 | { 79 | var command = ((CommandExecutedEventData)value).Command; 80 | if (command is DbCommand dbCommand) 81 | { 82 | SqlRequestUtil.EndSubsegment(); 83 | } 84 | } 85 | 86 | private void OnEventException(object value) 87 | { 88 | var exc = ((CommandErrorEventData)value).Exception; 89 | if (exc is Exception exception) 90 | { 91 | SqlRequestUtil.ProcessException(exception); 92 | SqlRequestUtil.EndSubsegment(); 93 | } 94 | } 95 | } 96 | } 97 | #endif 98 | -------------------------------------------------------------------------------- /src/sdk/EntityFramework/EntityFrameworkHandler.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 20 | using System; 21 | using System.Data.Common; 22 | using System.Data.Entity.Infrastructure.Interception; 23 | 24 | namespace Amazon.XRay.Recorder.AutoInstrumentation 25 | { 26 | /// 27 | /// Entity Framework handler for tracing Sql query through EF 6 28 | /// 29 | public class EntityFrameworkHandler : IDbCommandInterceptor 30 | { 31 | 32 | /// 33 | /// Trace before executing non query command. 34 | /// 35 | /// An instance of . 36 | /// An instance of . 37 | public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 38 | { 39 | OnCommandStart(command); 40 | } 41 | 42 | /// 43 | /// Trace after executing non query command. 44 | /// 45 | /// An instance of . 46 | /// An instance of . 47 | public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext) 48 | { 49 | OnCommandStop(interceptionContext.Exception); 50 | } 51 | 52 | /// 53 | /// Trace before executing reader command. 54 | /// 55 | /// An instance of . 56 | /// An instance of . 57 | public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 58 | { 59 | OnCommandStart(command); 60 | } 61 | 62 | /// 63 | /// Trace after executing reader command. 64 | /// 65 | /// An instance of . 66 | /// An instance of . 67 | public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext) 68 | { 69 | OnCommandStop(interceptionContext.Exception); 70 | } 71 | 72 | /// 73 | /// Trace before executing scalar command. 74 | /// 75 | /// An instance of . 76 | /// An instance of . 77 | public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) 78 | { 79 | OnCommandStart(command); 80 | } 81 | 82 | /// 83 | /// Trace after executing scalar command. 84 | /// 85 | /// An instance of . 86 | /// An instance of . 87 | public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext) 88 | { 89 | OnCommandStop(interceptionContext.Exception); 90 | } 91 | 92 | private void OnCommandStart(DbCommand command) 93 | { 94 | SqlRequestUtil.BeginSubsegment(command); 95 | SqlRequestUtil.ProcessCommand(command); 96 | } 97 | 98 | private void OnCommandStop(Exception exception) 99 | { 100 | if (exception != null) 101 | { 102 | SqlRequestUtil.ProcessException(exception); 103 | } 104 | 105 | SqlRequestUtil.EndSubsegment(); 106 | } 107 | } 108 | } 109 | #endif 110 | -------------------------------------------------------------------------------- /src/sdk/Http/HttpOutDiagnosticListenerNetframework.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core; 21 | using Amazon.XRay.Recorder.Core.Exceptions; 22 | using Amazon.XRay.Recorder.Core.Internal.Entities; 23 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 24 | using System; 25 | using System.Collections.Concurrent; 26 | using System.Collections.Generic; 27 | using System.Net; 28 | 29 | namespace Amazon.XRay.Recorder.AutoInstrumentation 30 | { 31 | /// 32 | /// Diagnostic listener for processing Http outgoing request 33 | /// 34 | public class HttpOutDiagnosticListenerNetframework : DiagnosticListenerBase 35 | { 36 | private static readonly Logger _logger = Logger.GetLogger(typeof(HttpOutDiagnosticListenerNetframework)); 37 | 38 | private static readonly ConcurrentDictionary CurrentHttpWebRequests = new ConcurrentDictionary(); 39 | 40 | internal override string Name => "System.Net.Http.Desktop"; 41 | 42 | protected override void OnEvent(KeyValuePair value) 43 | { 44 | try 45 | { 46 | switch (value.Key) 47 | { 48 | case "System.Net.Http.Desktop.HttpRequestOut.Start": 49 | { 50 | OnEventStart(value.Value); 51 | } 52 | break; 53 | case "System.Net.Http.Desktop.HttpRequestOut.Stop": 54 | { 55 | OnEventStop(value.Value); 56 | } 57 | break; 58 | case "System.Net.Http.Desktop.HttpRequestOut.Ex.Stop": 59 | { 60 | OnEventException(value.Value); 61 | } 62 | break; 63 | } 64 | } 65 | catch (Exception e) 66 | { 67 | _logger.Error(e, "Invalid diagnostic source key ({0})", value.Key); 68 | } 69 | } 70 | 71 | /// 72 | /// Process http outgoing request 73 | /// 74 | private void OnEventStart(object value) 75 | { 76 | var request = AgentUtil.FetchPropertyUsingReflection(value, "Request"); 77 | if (request is HttpWebRequest webRequest) 78 | { 79 | // Skip AWS SDK Request since it is instrumented using the SDK 80 | if (HttpRequestUtil.IsTraceable(webRequest)) 81 | { 82 | HttpRequestUtil.ProcessRequest(webRequest); 83 | 84 | try 85 | { 86 | var currentSubsegment = AWSXRayRecorder.Instance.GetEntity() as Subsegment; 87 | if (currentSubsegment != null) 88 | { 89 | CurrentHttpWebRequests.TryAdd(webRequest, currentSubsegment); 90 | } 91 | } 92 | catch (EntityNotAvailableException e) 93 | { 94 | AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Subsegment is not available in trace context."); 95 | } 96 | } 97 | } 98 | } 99 | 100 | /// 101 | /// Process http response 102 | /// 103 | private void OnEventStop(object value) 104 | { 105 | var request = AgentUtil.FetchPropertyUsingReflection(value, "Request"); 106 | var response = AgentUtil.FetchPropertyUsingReflection(value, "Response"); 107 | if (request is HttpWebRequest webRequest && response is HttpWebResponse webResponse) 108 | { 109 | if (CurrentHttpWebRequests.TryRemove(webRequest, out var currentSubsegment)) 110 | { 111 | if (webResponse != null) 112 | { 113 | HttpRequestUtil.ProcessResponse(webResponse.StatusCode, webResponse.ContentLength, currentSubsegment); 114 | } 115 | HttpRequestUtil.EndSubsegment(currentSubsegment); 116 | } 117 | } 118 | } 119 | 120 | /// 121 | /// Process exception 122 | /// 123 | private void OnEventException(object value) 124 | { 125 | var request = AgentUtil.FetchPropertyUsingReflection(value, "Request"); 126 | var status = AgentUtil.FetchPropertyUsingReflection(value, "StatusCode"); 127 | if (request is HttpWebRequest webRequest && status is HttpStatusCode httpStatusCode) 128 | { 129 | if (CurrentHttpWebRequests.TryRemove(webRequest, out var currentSubsegment)) 130 | { 131 | HttpRequestUtil.HandleStatus(httpStatusCode, currentSubsegment); 132 | HttpRequestUtil.EndSubsegment(currentSubsegment); 133 | } 134 | } 135 | } 136 | } 137 | } 138 | #endif 139 | -------------------------------------------------------------------------------- /src/sdk/Http/HttpOutDiagnosticListenerNetstandard.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core.Internal.Entities; 21 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 22 | using System; 23 | using System.Collections.Concurrent; 24 | using System.Collections.Generic; 25 | using System.Net.Http; 26 | 27 | namespace Amazon.XRay.Recorder.AutoInstrumentation 28 | { 29 | /// 30 | /// Diagnostic listener for processing Http outgoing request 31 | /// 32 | public class HttpOutDiagnosticListenerNetstandard : DiagnosticListenerBase 33 | { 34 | private static readonly Logger _logger = Logger.GetLogger(typeof(HttpOutDiagnosticListenerNetstandard)); 35 | 36 | internal override string Name => "HttpHandlerDiagnosticListener"; 37 | 38 | private static readonly ConcurrentDictionary CurrentHttpRequestMessages = new ConcurrentDictionary(); 39 | 40 | protected override void OnEvent(KeyValuePair value) 41 | { 42 | try 43 | { 44 | switch (value.Key) 45 | { 46 | case "System.Net.Http.HttpRequestOut.Start": 47 | { 48 | OnEventStart(value.Value); 49 | } 50 | break; 51 | case "System.Net.Http.HttpRequestOut.Stop": 52 | { 53 | OnEventStop(value.Value); 54 | } 55 | break; 56 | case "System.Net.Http.Exception": 57 | { 58 | OnEventException(value.Value); 59 | } 60 | break; 61 | } 62 | } 63 | catch (Exception e) 64 | { 65 | _logger.Error(e, "Invalid diagnostic source key ({0})", value.Key); 66 | } 67 | } 68 | 69 | private void OnEventStart(object value) 70 | { 71 | // The value passed in is not castable, use fetch from reflection instead. 72 | var request = AgentUtil.FetchPropertyUsingReflection(value, "Request"); 73 | if (request is HttpRequestMessage httpRequestMessage) 74 | { 75 | // Skip AWS SDK Request since it is instrumented using the SDK 76 | if (HttpRequestUtil.IsTraceable(httpRequestMessage) && CurrentHttpRequestMessages.TryAdd(httpRequestMessage, null)) 77 | { 78 | HttpRequestUtil.ProcessRequest(httpRequestMessage); 79 | } 80 | } 81 | } 82 | 83 | private void OnEventStop(object value) 84 | { 85 | // The value passed in is not castable, use fetch from reflection instead. 86 | var request = AgentUtil.FetchPropertyUsingReflection(value, "Request"); 87 | var response = AgentUtil.FetchPropertyUsingReflection(value, "Response"); 88 | if (request is HttpRequestMessage httpRequestMessage && response is HttpResponseMessage httpResponseMessage) 89 | { 90 | if (CurrentHttpRequestMessages.TryRemove(httpRequestMessage, out _)) 91 | { 92 | HttpRequestUtil.ProcessResponse(httpResponseMessage); 93 | // End subsegment here 94 | HttpRequestUtil.EndSubsegment(); 95 | } 96 | } 97 | } 98 | 99 | private void OnEventException(object value) 100 | { 101 | // The value passed in is not castable, use fetch from reflection instead. 102 | var request = AgentUtil.FetchPropertyUsingReflection(value, "Request"); 103 | var exc = AgentUtil.FetchPropertyUsingReflection(value, "Exception"); 104 | if (request is HttpRequestMessage httpRequestMessage && exc is Exception exception) 105 | { 106 | if (CurrentHttpRequestMessages.TryRemove(httpRequestMessage, out _)) 107 | { 108 | HttpRequestUtil.ProcessException(exception); 109 | } 110 | } 111 | } 112 | } 113 | } 114 | #endif 115 | -------------------------------------------------------------------------------- /src/sdk/Initialization/AspNetCoreTracingHandlers.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using System.Collections.Generic; 20 | using System.Diagnostics; 21 | 22 | namespace Amazon.XRay.Recorder.AutoInstrumentation 23 | { 24 | /// 25 | /// Initialize the XRay tracing configurations and listeners for AspNet Core application 26 | /// 27 | public class AspNetCoreTracingHandlers 28 | { 29 | /// 30 | /// 1.Instrument configurations from appsettings.json 31 | /// 2.Subscribe AspNetCoreDiagnosticListener, HttpOutDiagnosticListener, SqlDiagnosticListener(SDS and MDS), 32 | /// EntityFrameworkCoreDiagnosticListener for tacing AspNetCore incoming request, Http outgpingrequest, and Sql request. 33 | /// 3.Register XRay for AWS services 34 | /// 35 | internal static void Initialize() 36 | { 37 | var xrayAutoInstrumentationOptions = XRayConfiguration.Register(); 38 | 39 | var serviceName = xrayAutoInstrumentationOptions.ServiceName; 40 | 41 | var subscriptions = new List(); 42 | 43 | // Subscribe diagnostic listener for tracing Asp.Net Core request 44 | subscriptions.Add(new AspNetCoreDiagnosticListener(serviceName)); 45 | 46 | // Subscribe diagnostic listener for tracing Http outgoing request 47 | if (xrayAutoInstrumentationOptions.TraceHttpRequests) 48 | { 49 | subscriptions.Add(new HttpOutDiagnosticListenerNetstandard()); 50 | } 51 | 52 | // Subscribe diagnostic listener for tracing Sql request 53 | if (xrayAutoInstrumentationOptions.TraceSqlRequests) 54 | { 55 | subscriptions.Add(new SqlDiagnosticListener()); 56 | } 57 | 58 | // Subscribe diagnostic listener for tracing EF Core request 59 | if (xrayAutoInstrumentationOptions.TraceEFRequests) 60 | { 61 | subscriptions.Add(new EntityFrameworkCoreDiagnosticListener()); 62 | } 63 | 64 | DiagnosticListener.AllListeners.Subscribe(new DiagnosticListenerObserver(subscriptions)); 65 | 66 | // Enable tracing for AWS request 67 | if (xrayAutoInstrumentationOptions.TraceAWSRequests) 68 | { 69 | AWSSDKRequestRegister.Register(); 70 | } 71 | } 72 | } 73 | } 74 | #endif 75 | -------------------------------------------------------------------------------- /src/sdk/Initialization/AspNetTracingHandlers.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using System.Collections.Generic; 20 | using System.Data.Entity.Infrastructure.Interception; 21 | using System.Diagnostics; 22 | 23 | namespace Amazon.XRay.Recorder.AutoInstrumentation 24 | { 25 | /// 26 | /// Initialize the XRay tracing handlers for Asp.Net application 27 | /// 28 | public class AspNetTracingHandlers 29 | { 30 | /// 31 | /// 1.Add HttpOutDiagnosticListenerNetframework, EntityFramework and Sql tracing handler for tracing Http outgping request and Sql query. 32 | /// 2.Register XRay for AWS services 33 | /// 34 | internal static void Initialize(XRayAutoInstrumentationOptions options) 35 | { 36 | if (options.TraceHttpRequests) 37 | { 38 | DiagnosticListenerBase[] subscriptions = { new HttpOutDiagnosticListenerNetframework() }; 39 | 40 | DiagnosticListener.AllListeners.Subscribe(new DiagnosticListenerObserver(subscriptions)); 41 | } 42 | 43 | if (options.TraceSqlRequests) 44 | { 45 | _ = new SqlEventListener(); 46 | } 47 | 48 | if (options.TraceEFRequests) 49 | { 50 | DbInterception.Add(new EntityFrameworkHandler()); 51 | } 52 | 53 | if (options.TraceAWSRequests) 54 | { 55 | AWSSDKRequestRegister.Register(); 56 | } 57 | } 58 | } 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /src/sdk/Initialize.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | namespace Amazon.XRay.Recorder.AutoInstrumentation 20 | { 21 | /// 22 | /// Initialize XRay tracing handlers and listeners for Asp.Net Core application 23 | /// 24 | public static class Initialize 25 | { 26 | public static void AddXRay() 27 | { 28 | AspNetCoreTracingHandlers.Initialize(); 29 | } 30 | } 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /src/sdk/Sql/SqlDiagnosticListener.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 21 | using Amazon.XRay.Recorder.Core.Internal.Entities; 22 | using System; 23 | using System.Collections.Concurrent; 24 | using System.Collections.Generic; 25 | using System.Data.Common; 26 | 27 | namespace Amazon.XRay.Recorder.AutoInstrumentation 28 | { 29 | /// 30 | /// Diagnostic listener for processing Sql query for System.Data.SqlClient and Microsoft.Data.SqlClient 31 | /// 32 | public class SqlDiagnosticListener : DiagnosticListenerBase 33 | { 34 | private static readonly Logger _logger = Logger.GetLogger(typeof(SqlDiagnosticListener)); 35 | 36 | internal override string Name => "SqlClientDiagnosticListener"; 37 | 38 | private static readonly ConcurrentDictionary CurrentDbCommands = new ConcurrentDictionary(); 39 | 40 | protected override void OnEvent(KeyValuePair value) 41 | { 42 | try 43 | { 44 | switch (value.Key) 45 | { 46 | case "Microsoft.Data.SqlClient.WriteCommandBefore": 47 | { 48 | OnEventStart(value.Value); 49 | } 50 | break; 51 | case "System.Data.SqlClient.WriteCommandBefore": 52 | { 53 | OnEventStart(value.Value); 54 | } 55 | break; 56 | case "Microsoft.Data.SqlClient.WriteCommandAfter": 57 | { 58 | OnEventStop(value.Value); 59 | } 60 | break; 61 | case "System.Data.SqlClient.WriteCommandAfter": 62 | { 63 | OnEventStop(value.Value); 64 | } 65 | break; 66 | case "Microsoft.Data.SqlClient.WriteCommandError": 67 | { 68 | OnEventException(value.Value); 69 | } 70 | break; 71 | case "System.Data.SqlClient.WriteCommandError": 72 | { 73 | OnEventException(value.Value); 74 | } 75 | break; 76 | } 77 | } 78 | catch (Exception e) 79 | { 80 | _logger.Error(e, "Invalid diagnostic source key ({0})", value.Key); 81 | } 82 | } 83 | 84 | private void OnEventStart(object value) 85 | { 86 | // This class serves for tracing Sql command from both System.Data.SqlClient and Microsoft.Data.SqlClient and using fetch property works 87 | // fot both of these two cases 88 | var command = AgentUtil.FetchPropertyUsingReflection(value, "Command"); 89 | if (command is DbCommand dbcommand) 90 | { 91 | // Skip processing EntityFramework Core request 92 | if (SqlRequestUtil.IsTraceable() && CurrentDbCommands.TryAdd(dbcommand, null)) 93 | { 94 | SqlRequestUtil.BeginSubsegment(dbcommand); 95 | SqlRequestUtil.ProcessCommand(dbcommand); 96 | } 97 | } 98 | } 99 | 100 | private void OnEventStop(object value) 101 | { 102 | // This class serves for tracing Sql command from both System.Data.SqlClient and Microsoft.Data.SqlClient and using fetch property works 103 | // fot both of these two cases 104 | var command = AgentUtil.FetchPropertyUsingReflection(value, "Command"); 105 | if (command is DbCommand dbcommand) 106 | { 107 | if (CurrentDbCommands.TryRemove(dbcommand, out _)) 108 | { 109 | SqlRequestUtil.EndSubsegment(); 110 | } 111 | } 112 | } 113 | 114 | private void OnEventException(object value) 115 | { 116 | // This class serves for tracing Sql command from both System.Data.SqlClient and Microsoft.Data.SqlClient and using fetch property works 117 | // fot both of these two cases 118 | var command = AgentUtil.FetchPropertyUsingReflection(value, "Command"); 119 | var exc = AgentUtil.FetchPropertyUsingReflection(value, "Exception"); 120 | if (command is DbCommand dbcommand && exc is Exception exception) 121 | { 122 | if (CurrentDbCommands.TryRemove(dbcommand, out _)) 123 | { 124 | SqlRequestUtil.ProcessException(exception); 125 | SqlRequestUtil.EndSubsegment(); 126 | } 127 | } 128 | } 129 | } 130 | } 131 | #endif 132 | -------------------------------------------------------------------------------- /src/sdk/Sql/SqlEventListener.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core; 21 | using Amazon.XRay.Recorder.Core.Exceptions; 22 | using Amazon.XRay.Recorder.Core.Internal.Entities; 23 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 24 | using System; 25 | using System.Collections.Concurrent; 26 | using System.Diagnostics.Tracing; 27 | using System.Globalization; 28 | 29 | namespace Amazon.XRay.Recorder.AutoInstrumentation 30 | { 31 | /// 32 | /// Sql event listener for tracing Sql query from System.Data.SqlClient 33 | /// 34 | public class SqlEventListener : EventListener 35 | { 36 | private const string SqlEventSourceName = "Microsoft-AdoNet-SystemData"; 37 | private const string EventSourceTypeName = "System.Data.SqlEventSource"; 38 | private const int SqlCommandExecutedBeforeId = 1; 39 | private const int SqlCommandExecutedAfterId = 2; 40 | 41 | private static readonly AWSXRayRecorder _recorder = AWSXRayRecorder.Instance; 42 | private static readonly Logger _logger = Logger.GetLogger(typeof(SqlEventListener)); 43 | 44 | private static readonly ConcurrentDictionary CurrentSqlEvents = new ConcurrentDictionary(); 45 | 46 | /// 47 | /// Enable receiving events 48 | /// 49 | protected override void OnEventSourceCreated(EventSource eventSource) 50 | { 51 | if (eventSource != null && eventSource.Name == SqlEventSourceName && eventSource.GetType().FullName == EventSourceTypeName) 52 | { 53 | EnableEvents(eventSource, EventLevel.Informational, (EventKeywords)1); 54 | } 55 | base.OnEventSourceCreated(eventSource); 56 | } 57 | 58 | /// 59 | /// Receive events 60 | /// 61 | protected override void OnEventWritten(EventWrittenEventArgs eventData) 62 | { 63 | if (eventData?.Payload == null) 64 | { 65 | return; 66 | } 67 | 68 | try 69 | { 70 | switch (eventData.EventId) 71 | { 72 | case SqlCommandExecutedBeforeId: 73 | { 74 | OnEventStart(eventData); 75 | } 76 | break; 77 | case SqlCommandExecutedAfterId: 78 | { 79 | OnEventStop(eventData); 80 | } 81 | break; 82 | } 83 | } 84 | catch (Exception e) 85 | { 86 | _logger.Error(e, "Invalid Event Id ({0})", eventData.EventId); 87 | } 88 | } 89 | 90 | /// 91 | /// Trace before executing Sql command 92 | /// 93 | private void OnEventStart(EventWrittenEventArgs sqlEventData) 94 | { 95 | if (sqlEventData.Payload.Count != 4) 96 | { 97 | return; 98 | } 99 | 100 | // Skip EF request 101 | if (SqlRequestUtil.IsTraceable()) 102 | { 103 | SqlRequestUtil.ProcessEventData(sqlEventData); 104 | 105 | try 106 | { 107 | var currentSubsegment = _recorder.GetEntity() as Subsegment; 108 | int id = Convert.ToInt32(sqlEventData.Payload[0], CultureInfo.InvariantCulture); 109 | if (currentSubsegment != null) 110 | { 111 | CurrentSqlEvents.TryAdd(id, currentSubsegment); 112 | } 113 | } 114 | catch (EntityNotAvailableException e) 115 | { 116 | AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Subsegment is not available in trace context."); 117 | } 118 | } 119 | } 120 | 121 | /// 122 | /// Trace after executing Sql command 123 | /// 124 | private void OnEventStop(EventWrittenEventArgs sqlEventData) 125 | { 126 | if (sqlEventData.Payload.Count != 3) 127 | { 128 | return; 129 | } 130 | 131 | int id = Convert.ToInt32(sqlEventData.Payload[0], CultureInfo.InvariantCulture); 132 | int state = Convert.ToInt32(sqlEventData.Payload[1], CultureInfo.InvariantCulture); 133 | int exceptionNumber = Convert.ToInt32(sqlEventData.Payload[2], CultureInfo.InvariantCulture); 134 | 135 | if (CurrentSqlEvents.TryRemove(id, out var currentSubsegment)) 136 | { 137 | if ((state & 2) == 2) 138 | { 139 | currentSubsegment.HasFault = true; 140 | } 141 | SqlRequestUtil.EndSubsegment(currentSubsegment); 142 | } 143 | } 144 | } 145 | } 146 | #endif 147 | -------------------------------------------------------------------------------- /src/sdk/Utils/AgentUtil.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using Amazon.Runtime.Internal.Util; 19 | using Amazon.XRay.Recorder.Core; 20 | using Amazon.XRay.Recorder.Core.Exceptions; 21 | using Amazon.XRay.Recorder.Core.Internal.Entities; 22 | using System.Collections.Concurrent; 23 | using System.Collections.Generic; 24 | using System.Data.Common; 25 | using System.Reflection; 26 | 27 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Utils 28 | { 29 | public static class AgentUtil 30 | { 31 | private static readonly Logger _logger = Logger.GetLogger(typeof(AgentUtil)); 32 | 33 | private static readonly string EntityFramework = "EntityFramework"; 34 | 35 | private static readonly string[] UserIdFormatOptions = { "user id", "username", "user", "userid" }; // case insensitive 36 | 37 | private static readonly string[] DatabaseTypes = { "sqlserver", "sqlite", "postgresql", "mysql", "firebirdsql", 38 | "inmemory" , "cosmosdb" , "oracle" , "filecontextcore" , 39 | "jet" , "teradata" , "openedge" , "ibm" , "mycat" , "vfp"}; 40 | 41 | private static readonly string SqlServerCompact35 = "sqlservercompact35"; 42 | private static readonly string SqlServerCompact40 = "sqlservercompact40"; 43 | private static readonly string SqlServer = "sqlserver"; 44 | 45 | /// 46 | /// Extract database_type from . 47 | /// 48 | public static string GetDataBaseType(DbCommand command) 49 | { 50 | var typeString = command?.Connection?.GetType()?.FullName?.ToLower(); 51 | 52 | // Won't be the case for Sql query through System.Data.SqlClient and Microsoft.Data.SqlClient 53 | // only for the edge case of sql query through Entity Framework and Entity Framework Core 54 | if (string.IsNullOrEmpty(typeString)) 55 | { 56 | return EntityFramework; 57 | } 58 | 59 | if (typeString.Contains("microsoft.data.sqlclient") || typeString.Contains("system.data.sqlclient")) 60 | { 61 | return SqlServer; 62 | } 63 | 64 | if (typeString.Contains(SqlServerCompact35)) 65 | { 66 | return SqlServerCompact35; 67 | } 68 | 69 | if (typeString.Contains(SqlServerCompact40)) 70 | { 71 | return SqlServerCompact40; 72 | } 73 | 74 | foreach (var databaseType in DatabaseTypes) 75 | { 76 | if (typeString.Contains(databaseType)) 77 | { 78 | return databaseType; 79 | } 80 | } 81 | 82 | return typeString; 83 | } 84 | 85 | /// 86 | /// Extract user id from . 87 | /// 88 | public static object GetUserId(DbConnectionStringBuilder builder) 89 | { 90 | object value = null; 91 | foreach (string key in UserIdFormatOptions) 92 | { 93 | if (builder.TryGetValue(key, out value)) 94 | { 95 | break; 96 | } 97 | } 98 | return value; 99 | } 100 | 101 | /// 102 | /// Fetch property from reflection 103 | /// 104 | public static object FetchPropertyUsingReflection(object value, string item) 105 | { 106 | return value.GetType().GetTypeInfo().GetDeclaredProperty(item)?.GetValue(value); 107 | } 108 | 109 | /// 110 | /// Add AutoInstrumentation mark on the Segment 111 | /// 112 | public static void AddAutoInstrumentationMark() 113 | { 114 | 115 | try 116 | { 117 | var segment = AWSXRayRecorder.Instance.GetEntity() as Segment; 118 | 119 | if (segment == null) 120 | { 121 | _logger.DebugFormat("Unable to retrieve Segment from trace context"); 122 | return; 123 | } 124 | 125 | IDictionary awsAttribute = segment.Aws; 126 | 127 | if (awsAttribute == null) 128 | { 129 | _logger.DebugFormat("Unable to retrieve AWS dictionary to set the auto instrumentation flag."); 130 | } 131 | else 132 | { 133 | ConcurrentDictionary xrayAttribute = (ConcurrentDictionary)awsAttribute["xray"]; 134 | 135 | if (xrayAttribute == null) 136 | { 137 | _logger.DebugFormat("Unable to retrieve X-Ray dictionary from AWS dictionary of segment."); 138 | } 139 | else 140 | { 141 | // Set attribute "auto_instrumentation":true in the "xray" section of the segment 142 | xrayAttribute["auto_instrumentation"] = true; 143 | } 144 | } 145 | } 146 | catch (EntityNotAvailableException e) 147 | { 148 | AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Failed to get entity since it is not available in trace context while processing ASPNET Core request."); 149 | } 150 | } 151 | 152 | /// 153 | /// Mark Segment/Subsegment from http status code 154 | /// 155 | /// 156 | public static void MarkEntityFromStatus(int statusCode) 157 | { 158 | if (statusCode >= 400 && statusCode <= 499) 159 | { 160 | AWSXRayRecorder.Instance.MarkError(); 161 | 162 | if (statusCode == 429) 163 | { 164 | AWSXRayRecorder.Instance.MarkThrottle(); 165 | } 166 | } 167 | else if (statusCode >= 500 && statusCode <= 599) 168 | { 169 | AWSXRayRecorder.Instance.MarkFault(); 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/sdk/Utils/AspNetCoreRequestUtil.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core; 21 | using Amazon.XRay.Recorder.Core.Internal.Entities; 22 | using Amazon.XRay.Recorder.Core.Sampling; 23 | using Amazon.XRay.Recorder.Core.Strategies; 24 | using Microsoft.AspNetCore.Http; 25 | using Microsoft.AspNetCore.HttpOverrides.Internal; 26 | using Microsoft.Extensions.Primitives; 27 | using Microsoft.Net.Http.Headers; 28 | using System; 29 | using System.Collections.Generic; 30 | using System.Net; 31 | using System.Text; 32 | 33 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Utils 34 | { 35 | /// 36 | /// This class provides methods to set up segment naming strategy, process Asp.Net Core incoming 37 | /// request, response and exception. 38 | /// 39 | public class AspNetCoreRequestUtil 40 | { 41 | private static AWSXRayRecorder _recorder; 42 | private static readonly Logger _logger = Logger.GetLogger(typeof(AspNetCoreRequestUtil)); 43 | private static readonly string SchemeDelimiter = "://"; 44 | private static readonly string X_FORWARDED_FOR = "X-Forwarded-For"; 45 | 46 | private static SegmentNamingStrategy SegmentNamingStrategy { get; set; } 47 | 48 | /// 49 | /// Set up segment naming strategy 50 | /// 51 | internal static void SetSegmentNamingStrategy(SegmentNamingStrategy segmentNamingStrategy) 52 | { 53 | SegmentNamingStrategy = segmentNamingStrategy ?? throw new ArgumentNullException("segmentNamingStrategy"); 54 | } 55 | 56 | internal static void SetAWSXRayRecorder(AWSXRayRecorder recorder) 57 | { 58 | _recorder = recorder ?? throw new ArgumentNullException("recorder"); 59 | } 60 | 61 | /// 62 | /// Process http request. 63 | /// 64 | internal static void ProcessRequest(HttpContext httpContext) 65 | { 66 | HttpRequest request = httpContext.Request; 67 | string headerString = null; 68 | 69 | if (request.Headers.TryGetValue(TraceHeader.HeaderKey, out StringValues headerValue)) 70 | { 71 | if (headerValue.Count >= 1) 72 | headerString = headerValue[0]; 73 | } 74 | 75 | if (!TraceHeader.TryParse(headerString, out TraceHeader traceHeader)) 76 | { 77 | _logger.DebugFormat("Trace header doesn't exist or not valid : ({0}). Injecting a new one.", headerString); 78 | traceHeader = new TraceHeader 79 | { 80 | RootTraceId = TraceId.NewId(), 81 | ParentId = null, 82 | Sampled = SampleDecision.Unknown 83 | }; 84 | } 85 | 86 | var segmentName = SegmentNamingStrategy.GetSegmentName(request); 87 | bool isSampleDecisionRequested = traceHeader.Sampled == SampleDecision.Requested; 88 | 89 | string ruleName = null; 90 | // Make sample decision 91 | if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) 92 | { 93 | string host = request.Host.Host; 94 | string url = request.Path; 95 | string method = request.Method; 96 | SamplingInput samplingInput = new SamplingInput(host, url, method, segmentName, _recorder.Origin); 97 | SamplingResponse sampleResponse = _recorder.SamplingStrategy.ShouldTrace(samplingInput); 98 | traceHeader.Sampled = sampleResponse.SampleDecision; 99 | ruleName = sampleResponse.RuleName; 100 | } 101 | 102 | if (AWSXRayRecorder.IsLambda()) 103 | { 104 | _recorder.BeginSubsegment(segmentName); 105 | } 106 | else 107 | { 108 | SamplingResponse samplingResponse = new SamplingResponse(ruleName, traceHeader.Sampled); // get final ruleName and SampleDecision 109 | _recorder.BeginSegment(SegmentNamingStrategy.GetSegmentName(request), traceHeader.RootTraceId, traceHeader.ParentId, samplingResponse); 110 | } 111 | 112 | if (!AWSXRayRecorder.Instance.IsTracingDisabled()) 113 | { 114 | var requestAttributes = PopulateRequestAttributes(request); 115 | _recorder.AddHttpInformation("request", requestAttributes); 116 | } 117 | 118 | // Mark the segment as auto-instrumented 119 | AgentUtil.AddAutoInstrumentationMark(); 120 | 121 | if (isSampleDecisionRequested) 122 | { 123 | httpContext.Response.Headers.Add(TraceHeader.HeaderKey, traceHeader.ToString()); // Its recommended not to modify response header after _next.Invoke() call 124 | } 125 | } 126 | 127 | private static Dictionary PopulateRequestAttributes(HttpRequest request) 128 | { 129 | var requestAttributes = new Dictionary(); 130 | 131 | requestAttributes["url"] = GetUrl(request); 132 | requestAttributes["method"] = request.Method; 133 | string xForwardedFor = GetXForwardedFor(request); 134 | 135 | if (xForwardedFor == null) 136 | { 137 | requestAttributes["client_ip"] = GetClientIpAddress(request); 138 | } 139 | else 140 | { 141 | requestAttributes["client_ip"] = xForwardedFor; 142 | // If it's outer Proxy, add "X-Forwarded-For: true" in the trace context. 143 | if (IsOuterProxy(request)) 144 | { 145 | requestAttributes["x_forwarded_for"] = true; 146 | } 147 | } 148 | 149 | if (request.Headers.ContainsKey(HeaderNames.UserAgent)) 150 | { 151 | requestAttributes["user_agent"] = request.Headers[HeaderNames.UserAgent].ToString(); 152 | } 153 | 154 | return requestAttributes; 155 | } 156 | 157 | private static bool IsOuterProxy(HttpRequest request) 158 | { 159 | if (request.HttpContext.Request.Headers.TryGetValue(X_FORWARDED_FOR, out StringValues headerValue)) 160 | { 161 | return headerValue.ToString().IndexOf(',') >= 0; 162 | } 163 | 164 | return false; 165 | } 166 | 167 | private static string GetClientIpAddress(HttpRequest request) 168 | { 169 | return request.HttpContext.Connection.RemoteIpAddress?.ToString(); 170 | } 171 | 172 | /// 173 | /// Get X-Forwarded-For header. 174 | /// 175 | private static string GetXForwardedFor(HttpRequest request) 176 | { 177 | String clientIp = null; 178 | 179 | if (request.HttpContext.Request.Headers.TryGetValue(X_FORWARDED_FOR, out StringValues headerValue)) 180 | { 181 | string[] ipEndPoints = headerValue.ToString().Split(','); 182 | 183 | // parse the IP address from "IP:port number" end point 184 | clientIp = ExtractIpAddress(ipEndPoints[0].Trim()); 185 | } 186 | 187 | return string.IsNullOrEmpty(clientIp) ? null : clientIp.Split(',')[0].Trim(); 188 | } 189 | 190 | /// 191 | /// IP end point format: "IP:Port number". 192 | /// IPV6 formats: [xx:xx:xx:xx:xx:xx:xx:xx]:port number, [xx:xx:xx:xx:xx:xx:xx:xx], xx:xx:xx:xx:xx:xx:xx:xx. 193 | /// IPV4 formats: x.x.x.x:port number, x.x.x.x. 194 | /// Extract IP address from "IP:Port number" end point format. 195 | /// 196 | private static string ExtractIpAddress(string endPoint) 197 | { 198 | IPAddress ipAddress = null; 199 | if (IPEndPointParser.TryParse(endPoint, out IPEndPoint ipEndPoint)) 200 | { 201 | ipAddress = ipEndPoint.Address; 202 | } 203 | 204 | return ipAddress?.ToString(); 205 | } 206 | 207 | private static string GetUrl(HttpRequest request) 208 | { 209 | if (request == null) 210 | { 211 | _logger.DebugFormat("HTTPRequest instance is null. Cannot get URL from the request, Setting url to null"); 212 | return null; 213 | } 214 | var scheme = request.Scheme ?? string.Empty; 215 | var host = request.Host.Value ?? string.Empty; 216 | var pathBase = request.PathBase.Value ?? string.Empty; 217 | var path = request.Path.Value ?? string.Empty; 218 | var queryString = request.QueryString.Value ?? string.Empty; 219 | 220 | // PERF: Calculate string length to allocate correct buffer size for StringBuilder. 221 | var length = scheme.Length + SchemeDelimiter.Length + host.Length 222 | + pathBase.Length + path.Length + queryString.Length; 223 | 224 | return new StringBuilder(length) 225 | .Append(scheme) 226 | .Append(SchemeDelimiter) 227 | .Append(host) 228 | .Append(pathBase) 229 | .Append(path) 230 | .Append(queryString) 231 | .ToString(); 232 | } 233 | 234 | /// 235 | /// Process http response. 236 | /// 237 | internal static void ProcessResponse(HttpContext httpContext) 238 | { 239 | HttpResponse response = httpContext.Response; 240 | 241 | if (!AWSXRayRecorder.Instance.IsTracingDisabled()) 242 | { 243 | var responseAttributes = PopulateResponseAttributes(response); 244 | _recorder.AddHttpInformation("response", responseAttributes); 245 | } 246 | 247 | if (AWSXRayRecorder.IsLambda()) 248 | { 249 | _recorder.EndSubsegment(); 250 | } 251 | else 252 | { 253 | _recorder.EndSegment(); 254 | } 255 | } 256 | 257 | private static Dictionary PopulateResponseAttributes(HttpResponse response) 258 | { 259 | var responseAttributes = new Dictionary(); 260 | 261 | int statusCode = (int)response.StatusCode; 262 | 263 | AgentUtil.MarkEntityFromStatus(statusCode); 264 | 265 | responseAttributes["status"] = statusCode; 266 | 267 | if (response.Headers.ContentLength != null) 268 | { 269 | responseAttributes["content_length"] = response.Headers.ContentLength; 270 | } 271 | 272 | return responseAttributes; 273 | } 274 | 275 | internal static void ProcessException(Exception exception) 276 | { 277 | _recorder.AddException(exception); 278 | } 279 | } 280 | } 281 | #endif 282 | -------------------------------------------------------------------------------- /src/sdk/Utils/AspNetRequestUtil.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if NET45 19 | using Amazon.Runtime.Internal.Util; 20 | using Amazon.XRay.Recorder.Core; 21 | using Amazon.XRay.Recorder.Core.Exceptions; 22 | using Amazon.XRay.Recorder.Core.Internal.Context; 23 | using Amazon.XRay.Recorder.Core.Internal.Entities; 24 | using Amazon.XRay.Recorder.Core.Sampling; 25 | using Amazon.XRay.Recorder.Core.Strategies; 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Web; 29 | 30 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Utils 31 | { 32 | /// 33 | /// This class provides methods to set up segment naming strategy, process Asp.Net incoming 34 | /// request, response and exception. 35 | /// 36 | public class AspNetRequestUtil 37 | { 38 | private static AWSXRayRecorder _recorder; 39 | private static SegmentNamingStrategy segmentNamingStrategy; 40 | private static readonly Logger _logger = Logger.GetLogger(typeof(AspNetRequestUtil)); 41 | 42 | /// 43 | /// Initialize AWSXRayRecorder instance, register configurations and tracing handlers 44 | /// 45 | internal static void InitializeAspNet() 46 | { 47 | if (!AWSXRayRecorder.IsCustomRecorder) // If custom recorder is not set 48 | { 49 | AWSXRayRecorder.Instance.SetTraceContext(new HybridContextContainer()); // configure Trace Context 50 | } 51 | 52 | _recorder = AWSXRayRecorder.Instance; 53 | 54 | // Register configurations 55 | var xrayAutoInstrumentationOptions = XRayConfiguration.Register(); 56 | 57 | _recorder.SetDaemonAddress(xrayAutoInstrumentationOptions.DaemonAddress); 58 | 59 | if (GetSegmentNamingStrategy() == null) // ensures only one time initialization among many HTTPApplication instances 60 | { 61 | var serviceName = xrayAutoInstrumentationOptions.ServiceName; 62 | InitializeAspNet(new FixedSegmentNamingStrategy(serviceName)); 63 | } 64 | 65 | // Initialize tracing handlers for Asp.Net platform 66 | AspNetTracingHandlers.Initialize(xrayAutoInstrumentationOptions); 67 | } 68 | 69 | private static SegmentNamingStrategy GetSegmentNamingStrategy() 70 | { 71 | return segmentNamingStrategy; 72 | } 73 | 74 | private static void InitializeAspNet(FixedSegmentNamingStrategy segmentNamingStrategy) 75 | { 76 | if (segmentNamingStrategy == null) 77 | { 78 | throw new ArgumentNullException("segmentNamingStrategy"); 79 | } 80 | 81 | if (GetSegmentNamingStrategy() == null) // ensures only one time initialization among many HTTPApplication instances 82 | { 83 | SetSegmentNamingStrategy(segmentNamingStrategy); 84 | } 85 | } 86 | 87 | private static void SetSegmentNamingStrategy(SegmentNamingStrategy value) 88 | { 89 | segmentNamingStrategy = value; 90 | } 91 | 92 | internal static void ProcessHTTPRequest(object sender, EventArgs e) 93 | { 94 | var context = ((HttpApplication)sender).Context; 95 | 96 | string ruleName = null; 97 | 98 | var request = context.Request; 99 | TraceHeader traceHeader = GetTraceHeader(context); 100 | 101 | var segmentName = GetSegmentNamingStrategy().GetSegmentName(request); 102 | // Make sample decision 103 | if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) 104 | { 105 | SamplingResponse response = MakeSamplingDecision(request, traceHeader, segmentName); 106 | ruleName = response.RuleName; 107 | } 108 | 109 | var timestamp = context.Timestamp.ToUniversalTime(); // Gets initial timestamp of current HTTP Request 110 | 111 | SamplingResponse samplingResponse = new SamplingResponse(ruleName, traceHeader.Sampled); // get final ruleName and SampleDecision 112 | _recorder.BeginSegment(segmentName, traceHeader.RootTraceId, traceHeader.ParentId, samplingResponse, timestamp); 113 | 114 | // Mark the segment as auto-instrumented 115 | AgentUtil.AddAutoInstrumentationMark(); 116 | 117 | if (!AWSXRayRecorder.Instance.IsTracingDisabled()) 118 | { 119 | var requestAttributes = ProcessRequestAttributes(request); 120 | _recorder.AddHttpInformation("request", requestAttributes); 121 | } 122 | } 123 | 124 | private static Dictionary ProcessRequestAttributes(HttpRequest request) 125 | { 126 | var requestAttributes = new Dictionary(); 127 | 128 | requestAttributes["url"] = request.Url.AbsoluteUri; 129 | requestAttributes["user_agent"] = request.UserAgent; 130 | requestAttributes["method"] = request.HttpMethod; 131 | string xForwardedFor = GetXForwardedFor(request); 132 | 133 | if (xForwardedFor == null) 134 | { 135 | requestAttributes["client_ip"] = GetClientIpAddress(request); 136 | } 137 | else 138 | { 139 | requestAttributes["client_ip"] = xForwardedFor; 140 | requestAttributes["x_forwarded_for"] = true; 141 | } 142 | 143 | return requestAttributes; 144 | } 145 | 146 | private static object GetClientIpAddress(HttpRequest request) 147 | { 148 | return request.UserHostAddress; 149 | } 150 | 151 | private static string GetXForwardedFor(HttpRequest request) 152 | { 153 | string clientIp = request.ServerVariables["HTTP_X_FORWARDED_FOR"]; 154 | return string.IsNullOrEmpty(clientIp) ? null : clientIp.Split(',')[0].Trim(); 155 | } 156 | 157 | private static SamplingResponse MakeSamplingDecision(HttpRequest request, TraceHeader traceHeader, string segmentName) 158 | { 159 | string host = request.Headers.Get("Host"); 160 | string url = request.Url.AbsolutePath; 161 | string method = request.HttpMethod; 162 | SamplingInput samplingInput = new SamplingInput(host, url, method, segmentName, _recorder.Origin); 163 | SamplingResponse sampleResponse = _recorder.SamplingStrategy.ShouldTrace(samplingInput); 164 | traceHeader.Sampled = sampleResponse.SampleDecision; 165 | return sampleResponse; 166 | } 167 | 168 | private static TraceHeader GetTraceHeader(HttpContext context) 169 | { 170 | var request = context.Request; 171 | string headerString = request.Headers.Get(TraceHeader.HeaderKey); 172 | 173 | // Trace header doesn't exist, which means this is the root node. Create a new traceId and inject the trace header. 174 | if (!TraceHeader.TryParse(headerString, out TraceHeader traceHeader)) 175 | { 176 | _logger.DebugFormat("Trace header doesn't exist or not valid : ({0}). Injecting a new one.", headerString); 177 | traceHeader = new TraceHeader 178 | { 179 | RootTraceId = TraceId.NewId(), 180 | ParentId = null, 181 | Sampled = SampleDecision.Unknown 182 | }; 183 | } 184 | 185 | return traceHeader; 186 | } 187 | 188 | internal static void ProcessHTTPResponse(object sender, EventArgs e) 189 | { 190 | var context = ((HttpApplication)sender).Context; 191 | var response = context.Response; 192 | 193 | if (!AWSXRayRecorder.Instance.IsTracingDisabled() && response != null) 194 | { 195 | var responseAttributes = ProcessResponseAttributes(response); 196 | _recorder.AddHttpInformation("response", responseAttributes); 197 | } 198 | 199 | Exception exc = context.Error; // Record exception, if any 200 | 201 | if (exc != null) 202 | { 203 | _recorder.AddException(exc); 204 | } 205 | 206 | TraceHeader traceHeader = GetTraceHeader(context); 207 | bool isSampleDecisionRequested = traceHeader.Sampled == SampleDecision.Requested; 208 | 209 | if (traceHeader.Sampled == SampleDecision.Unknown || traceHeader.Sampled == SampleDecision.Requested) 210 | { 211 | SetSamplingDecision(traceHeader); // extracts sampling decision from the available segment 212 | } 213 | 214 | _recorder.EndSegment(); 215 | // if the sample decision is requested, add the trace header to response 216 | if (isSampleDecisionRequested) 217 | { 218 | response.Headers.Add(TraceHeader.HeaderKey, traceHeader.ToString()); 219 | } 220 | } 221 | 222 | private static Dictionary ProcessResponseAttributes(HttpResponse response) 223 | { 224 | var responseAttributes = new Dictionary(); 225 | 226 | int statusCode = (int)response.StatusCode; 227 | responseAttributes["status"] = statusCode; 228 | 229 | AgentUtil.MarkEntityFromStatus(statusCode); 230 | 231 | return responseAttributes; 232 | } 233 | 234 | private static void SetSamplingDecision(TraceHeader traceHeader) 235 | { 236 | try 237 | { 238 | Segment segment = (Segment)AWSXRayRecorder.Instance.GetEntity(); 239 | traceHeader.Sampled = segment.Sampled; 240 | } 241 | 242 | catch (InvalidCastException e) 243 | { 244 | _logger.Error(new EntityNotAvailableException("Failed to cast the entity to Segment.", e), "Failed to get the segment from trace context for setting sampling decision in the response."); 245 | } 246 | 247 | catch (EntityNotAvailableException e) 248 | { 249 | AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Failed to get entity since it is not available in trace context while processing ASPNET request."); 250 | } 251 | } 252 | 253 | internal static void ProcessHTTPError(object sender, EventArgs e) 254 | { 255 | ProcessHTTPRequest(sender, e); 256 | } 257 | } 258 | } 259 | #endif 260 | -------------------------------------------------------------------------------- /src/sdk/Utils/HttpRequestUtil.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Net; 21 | using System.Net.Http; 22 | using Amazon.Runtime.Internal.Util; 23 | using Amazon.XRay.Recorder.Core; 24 | using Amazon.XRay.Recorder.Core.Exceptions; 25 | using Amazon.XRay.Recorder.Core.Internal.Entities; 26 | 27 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Utils 28 | { 29 | /// 30 | /// Utils for process http outgoing request and response. 31 | /// 32 | public static class HttpRequestUtil 33 | { 34 | private static readonly Logger _logger = Logger.GetLogger(typeof(HttpRequestUtil)); 35 | 36 | /// 37 | /// Collects information from and adds a tracing header to the request. 38 | /// 39 | internal static void ProcessRequest(WebRequest request) 40 | { 41 | ProcessRequest(request.RequestUri, request.Method, header => request.Headers.Add(TraceHeader.HeaderKey, header)); 42 | } 43 | 44 | /// 45 | /// Collects information from and adds a tracing header to the request. 46 | /// 47 | internal static void ProcessRequest(HttpRequestMessage request) 48 | { 49 | ProcessRequest(request.RequestUri, request.Method.Method, AddOrReplaceHeader); 50 | 51 | void AddOrReplaceHeader(string header) 52 | { 53 | request.Headers.Remove(TraceHeader.HeaderKey); 54 | request.Headers.Add(TraceHeader.HeaderKey, header); 55 | } 56 | } 57 | 58 | /// 59 | /// Collects information from the response and adds to instance. 60 | /// 61 | internal static void ProcessResponse(HttpWebResponse response) 62 | { 63 | if (response != null) 64 | { 65 | ProcessResponse(response.StatusCode, response.ContentLength); 66 | } 67 | } 68 | 69 | /// 70 | /// Collects information from the response and adds to instance. 71 | /// 72 | internal static void ProcessResponse(HttpResponseMessage response) 73 | { 74 | if (response != null) 75 | { 76 | ProcessResponse(response.StatusCode, response.Content.Headers.ContentLength); 77 | } 78 | } 79 | 80 | /// 81 | /// Process Request 82 | /// 83 | private static void ProcessRequest(Uri uri, string method, Action addHeaderAction) 84 | { 85 | if (AWSXRayRecorder.Instance.IsTracingDisabled()) 86 | { 87 | _logger.DebugFormat("Tracing is disabled. Not starting a subsegment on HTTP request."); 88 | return; 89 | } 90 | 91 | var recorder = AWSXRayRecorder.Instance; 92 | recorder.BeginSubsegment(uri.Host); 93 | recorder.SetNamespace("remote"); 94 | 95 | var requestInformation = new Dictionary 96 | { 97 | ["url"] = uri.AbsoluteUri, 98 | ["method"] = method 99 | }; 100 | recorder.AddHttpInformation("request", requestInformation); 101 | 102 | try 103 | { 104 | if (TraceHeader.TryParse(recorder.GetEntity(), out var header)) 105 | { 106 | addHeaderAction(header.ToString()); 107 | } 108 | } 109 | catch (EntityNotAvailableException e) 110 | { 111 | recorder.TraceContext.HandleEntityMissing(recorder, e, "Failed to get entity since it is not available in trace context while processing http request."); 112 | } 113 | } 114 | 115 | /// 116 | /// Process response 117 | /// 118 | private static void ProcessResponse(HttpStatusCode httpStatusCode, long? contentLength) 119 | { 120 | if (AWSXRayRecorder.Instance.IsTracingDisabled()) 121 | { 122 | _logger.DebugFormat("Tracing is disabled. Not ending a subsegment on HTTP response."); 123 | return; 124 | } 125 | 126 | var statusCode = (int)httpStatusCode; 127 | 128 | var responseInformation = new Dictionary { ["status"] = statusCode }; 129 | 130 | AgentUtil.MarkEntityFromStatus(statusCode); 131 | 132 | responseInformation["content_length"] = contentLength; 133 | AWSXRayRecorder.Instance.AddHttpInformation("response", responseInformation); 134 | } 135 | 136 | /// 137 | /// Process exception 138 | /// 139 | internal static void ProcessException(Exception exception) 140 | { 141 | AWSXRayRecorder.Instance.AddException(exception); 142 | } 143 | 144 | /// 145 | /// Process response 146 | /// 147 | internal static void ProcessResponse(HttpStatusCode httpStatusCode, long? contentLength, Subsegment subsegment) 148 | { 149 | AWSXRayRecorder.Instance.SetEntity(subsegment); 150 | ProcessResponse(httpStatusCode, contentLength); 151 | } 152 | 153 | /// 154 | /// Handles status code when an exception occurs 155 | /// 156 | internal static void HandleStatus(HttpStatusCode httpStatusCode, Subsegment subsegment) 157 | { 158 | ProcessResponse(httpStatusCode, null, subsegment); 159 | } 160 | 161 | /// 162 | /// End subsegment. 163 | /// 164 | internal static void EndSubsegment() 165 | { 166 | AWSXRayRecorder.Instance.EndSubsegment(); 167 | } 168 | 169 | /// 170 | /// End subsegment 171 | /// 172 | internal static void EndSubsegment(Subsegment subsegment) 173 | { 174 | AWSXRayRecorder.Instance.SetEntity(subsegment); 175 | AWSXRayRecorder.Instance.EndSubsegment(); 176 | } 177 | 178 | /// 179 | /// Check if Http out going request should be traced. 180 | /// Http out going request that is GetSamplingRules or GetSamplingTargets call will not be traced. 181 | /// Http out going request that is sent by AWS SDK will no be traced. 182 | /// 183 | internal static bool IsTraceable(HttpRequestMessage request) 184 | { 185 | if (request == null || request.RequestUri == null) 186 | { 187 | return false; 188 | } 189 | var url = request.RequestUri.ToString(); 190 | return !IsSamplingCall(url) && !IsAWSSDKRequest(); 191 | } 192 | 193 | internal static bool IsTraceable(HttpWebRequest request) 194 | { 195 | if (request == null || request.RequestUri == null) 196 | { 197 | return false; 198 | } 199 | var url = request.RequestUri.ToString(); 200 | return !IsSamplingCall(url) && !IsAWSSDKRequest(); 201 | } 202 | 203 | /// 204 | /// Check if it's a call for get sampling rules or sampling targets. 205 | /// 206 | private static bool IsSamplingCall(string url) 207 | { 208 | return url.Contains("GetSamplingRules") || url.Contains("SamplingTargets"); 209 | } 210 | 211 | /// 212 | /// Check if request is sent via AWS SDK handler. 213 | /// 214 | private static bool IsAWSSDKRequest() 215 | { 216 | try 217 | { 218 | var subsegment = AWSXRayRecorder.Instance.GetEntity() as Subsegment; 219 | if (subsegment == null || subsegment.Namespace == null) 220 | { 221 | return false; 222 | } 223 | return subsegment.Namespace.Equals("aws") && subsegment.IsInProgress; 224 | } 225 | catch (EntityNotAvailableException e) 226 | { 227 | AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Failed to get entity since it is not available in trace context."); 228 | } 229 | 230 | return false; 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/sdk/Utils/SqlRequestUtil.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using Amazon.XRay.Recorder.Core; 19 | using Amazon.XRay.Recorder.Core.Exceptions; 20 | using Amazon.XRay.Recorder.Core.Internal.Entities; 21 | #if NET45 22 | using Amazon.XRay.Recorder.Core.Internal.Utils; 23 | #endif 24 | using System; 25 | using System.Data.Common; 26 | using System.Diagnostics.Tracing; 27 | using System.Globalization; 28 | using System.Text.RegularExpressions; 29 | 30 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Utils 31 | { 32 | /// 33 | /// Utils for Sql request 34 | /// 35 | public static class SqlRequestUtil 36 | { 37 | 38 | private static readonly Regex _portNumberRegex = new Regex(@"[,|:]\d+$"); 39 | 40 | /// 41 | /// Removes the port number from data source. 42 | /// 43 | internal static string RemovePortNumberFromDataSource(string dataSource) 44 | { 45 | return _portNumberRegex.Replace(dataSource, string.Empty); 46 | } 47 | 48 | /// 49 | /// Begin subsegment and add name space. 50 | /// 51 | internal static void BeginSubsegment(DbCommand command) 52 | { 53 | AWSXRayRecorder.Instance.BeginSubsegment(BuildSubsegmentName(command)); 54 | AWSXRayRecorder.Instance.SetNamespace("remote"); 55 | } 56 | 57 | /// 58 | /// Process command. 59 | /// 60 | internal static void ProcessCommand(DbCommand command) 61 | { 62 | CollectSqlInformationDefault(command); 63 | } 64 | 65 | /// 66 | /// Process data from SqlEventListener 67 | /// 68 | internal static void ProcessEventData(EventWrittenEventArgs sqlEventData) 69 | { 70 | int id = Convert.ToInt32(sqlEventData.Payload[0], CultureInfo.InvariantCulture); 71 | string dataSource = Convert.ToString(sqlEventData.Payload[1], CultureInfo.InvariantCulture); 72 | string database = Convert.ToString(sqlEventData.Payload[2], CultureInfo.InvariantCulture); 73 | string commandText = Convert.ToString(sqlEventData.Payload[3], CultureInfo.InvariantCulture); 74 | 75 | if (string.IsNullOrEmpty(database) || string.IsNullOrEmpty(dataSource)) 76 | { 77 | return; 78 | } 79 | 80 | string subsegmentName = database + "@" + RemovePortNumberFromDataSource(dataSource); 81 | 82 | var recorder = AWSXRayRecorder.Instance; 83 | recorder.BeginSubsegment(subsegmentName); 84 | recorder.SetNamespace("remote"); 85 | recorder.AddSqlInformation("database_type", "sqlserver"); 86 | 87 | if (ShouldCollectSqlText()) 88 | { 89 | if (!string.IsNullOrEmpty(commandText)) 90 | { 91 | recorder.AddSqlInformation("sanitized_query", commandText); 92 | } 93 | } 94 | } 95 | 96 | /// 97 | /// Process exception. 98 | /// 99 | internal static void ProcessException(Exception exception) 100 | { 101 | AWSXRayRecorder.Instance.AddException(exception); 102 | } 103 | 104 | /// 105 | /// End subsegment. 106 | /// 107 | internal static void EndSubsegment() 108 | { 109 | AWSXRayRecorder.Instance.EndSubsegment(); 110 | } 111 | 112 | /// 113 | /// End subsegment and emit it to Daemon. 114 | /// 115 | internal static void EndSubsegment(Subsegment subsegment) 116 | { 117 | AWSXRayRecorder.Instance.SetEntity(subsegment); 118 | AWSXRayRecorder.Instance.EndSubsegment(); 119 | } 120 | 121 | /// 122 | /// Records the SQL information on the current subsegment. 123 | /// 124 | private static void CollectSqlInformationDefault(DbCommand command) 125 | { 126 | var recorder = AWSXRayRecorder.Instance; 127 | var databaseType = AgentUtil.GetDataBaseType(command); 128 | recorder.AddSqlInformation("database_type", databaseType); 129 | 130 | recorder.AddSqlInformation("database_version", command.Connection.ServerVersion); 131 | 132 | DbConnectionStringBuilder connectionStringBuilder = new DbConnectionStringBuilder 133 | { 134 | ConnectionString = command.Connection.ConnectionString 135 | }; 136 | 137 | // Remove sensitive information from connection string 138 | connectionStringBuilder.Remove("Password"); 139 | 140 | var userId = AgentUtil.GetUserId(connectionStringBuilder); 141 | // Do a pre-check for user ID since in the case of TrustedConnection, a user ID may not be available. 142 | if (userId != null) 143 | { 144 | recorder.AddSqlInformation("user", userId.ToString()); 145 | } 146 | 147 | recorder.AddSqlInformation("connection_string", connectionStringBuilder.ToString()); 148 | 149 | if (ShouldCollectSqlText()) 150 | { 151 | recorder.AddSqlInformation("sanitized_query", command.CommandText); 152 | } 153 | } 154 | 155 | /// 156 | /// Builds the name of the subsegment in the format database@datasource 157 | /// 158 | private static string BuildSubsegmentName(DbCommand command) 159 | => command.Connection.Database + "@" + RemovePortNumberFromDataSource(command.Connection.DataSource); 160 | 161 | /// 162 | /// Check if subsegment should collect Sql command text. 163 | /// 164 | #if !NET45 165 | internal static bool ShouldCollectSqlText() 166 | => AWSXRayRecorder.Instance.XRayOptions.CollectSqlQueries; 167 | #else 168 | internal static bool ShouldCollectSqlText() 169 | => AppSettings.CollectSqlQueries; 170 | #endif 171 | 172 | /// 173 | /// Check if it's within an ef core subsegment, if so, skip it 174 | /// 175 | internal static bool IsTraceable() 176 | { 177 | try 178 | { 179 | var subsegment = AWSXRayRecorder.Instance.GetEntity() as Subsegment; 180 | if (subsegment == null || subsegment.Sql == null) 181 | { 182 | return true; 183 | } 184 | if (subsegment.IsInProgress && subsegment.Sql.Count > 0) 185 | { 186 | return false; 187 | } 188 | } 189 | catch (EntityNotAvailableException e) 190 | { 191 | AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Failed to get entity since it is not available in trace context."); 192 | } 193 | 194 | return true; 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/test/AWSXRayRecorder.AutoInstrumentation.Unittests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net452;netcoreapp2.0 5 | Amazon.com, Inc 6 | Amazon Web Service X-Ray Recorder 7 | Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 8 | 1.0.0.0 9 | 1.0.0.0 10 | true 11 | ..\..\buildtools\local-development.snk 12 | Amazon.XRay.Recorder.AutoInstrumentation.Unittests 13 | 14 | 15 | 16 | NET45 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 2.0.0 32 | 33 | 34 | 2.0.0 35 | 36 | 37 | 38 | 39 | 40 | 41 | PreserveNewest 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/test/EntityFrameworkCoreDiagnosticListenerTest.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.XRay.Recorder.AutoInstrumentation.Unittests.Tools; 20 | using Amazon.XRay.Recorder.Core; 21 | using Amazon.XRay.Recorder.Core.Internal.Entities; 22 | using Microsoft.Data.Sqlite; 23 | using Microsoft.EntityFrameworkCore; 24 | using Microsoft.VisualStudio.TestTools.UnitTesting; 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Diagnostics; 28 | using System.Linq; 29 | 30 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests 31 | { 32 | [TestClass] 33 | public class EntityFrameworkCoreDiagnosticListenerTest : TestBase 34 | { 35 | private const string _connectionString = "datasource=:memory:"; 36 | private SqliteConnection connection = null; 37 | 38 | private static IDisposable _subscription; 39 | 40 | private static AWSXRayRecorder _recorder; 41 | 42 | 43 | [TestInitialize] 44 | public void TestInitialize() 45 | { 46 | _recorder = new AWSXRayRecorder(); 47 | AWSXRayRecorder.InitializeInstance(recorder: _recorder); 48 | 49 | var subscription = new List() 50 | { 51 | new EntityFrameworkCoreDiagnosticListener() 52 | }; 53 | 54 | _subscription = DiagnosticListener.AllListeners.Subscribe(new DiagnosticListenerObserver(subscription)); 55 | 56 | // In-memory database only exists while the connection is open 57 | connection = new SqliteConnection("DataSource=:memory:"); 58 | connection.Open(); 59 | } 60 | 61 | [TestCleanup] 62 | public new void TestCleanup() 63 | { 64 | connection.Close(); 65 | base.TestCleanup(); 66 | _recorder.Dispose(); 67 | _recorder = null; 68 | _subscription.Dispose(); 69 | } 70 | 71 | [TestMethod] 72 | public void Test_EFCore_successful_query() 73 | { 74 | AWSXRayRecorder.Instance.XRayOptions.CollectSqlQueries = true; 75 | 76 | AWSXRayRecorder.Instance.BeginSegment("TestSegment"); 77 | var context = GetTestEFContext(); 78 | 79 | var users = context.Users.Where(u => u.UserId == 1).ToList(); 80 | 81 | // Assert 82 | var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity(); 83 | Assert.AreEqual(4, segment.Subsegments.Count); 84 | var query_subsegment = segment.Subsegments[3]; 85 | AssertQueryCollected(query_subsegment); 86 | 87 | AWSXRayRecorder.Instance.EndSegment(); 88 | } 89 | 90 | [TestMethod] 91 | public void Test_EFCore_unsuccessful_query() 92 | { 93 | AWSXRayRecorder.Instance.XRayOptions.CollectSqlQueries = false; 94 | 95 | AWSXRayRecorder.Instance.BeginSegment("TestSegment"); 96 | var context = GetTestEFContext(); 97 | var users = context.Users.Where(u => u.UserId == 1).ToList(); 98 | 99 | var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity(); 100 | Assert.AreEqual(4, segment.Subsegments.Count); 101 | var query_subsegment = segment.Subsegments[3]; 102 | AssertQueryNotCollected(query_subsegment); 103 | AWSXRayRecorder.Instance.EndSegment(); 104 | } 105 | 106 | [TestMethod] 107 | public void Test_EFCore_query_with_exception() 108 | { 109 | AWSXRayRecorder.Instance.BeginSegment("TestSegment"); 110 | var context = GetTestEFContext(); 111 | 112 | try 113 | { 114 | context.Database.ExecuteSqlCommand("Select * From FakeTable"); // A false sql command which results in 'no such table: FakeTable' exception 115 | } 116 | catch 117 | { 118 | // ignore 119 | } 120 | 121 | var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity(); 122 | Assert.AreEqual(4, segment.Subsegments.Count); 123 | var subsegment = segment.Subsegments[3]; 124 | Assert.AreEqual(true, subsegment.HasFault); 125 | AWSXRayRecorder.Instance.EndSegment(); 126 | AWSXRayRecorder.Instance.Dispose(); 127 | } 128 | 129 | private void AssertQueryCollected(Subsegment subsegment) 130 | { 131 | AssertExpectedSqlInformation(subsegment); 132 | Assert.IsTrue(subsegment.Sql.ContainsKey("sanitized_query")); 133 | } 134 | 135 | private void AssertQueryNotCollected(Subsegment subsegment) 136 | { 137 | AssertExpectedSqlInformation(subsegment); 138 | Assert.IsFalse(subsegment.Sql.ContainsKey("sanitized_query")); 139 | } 140 | 141 | private void AssertExpectedSqlInformation(Subsegment subsegment) 142 | { 143 | Assert.IsNotNull(subsegment); 144 | Assert.IsNotNull(subsegment.Sql); 145 | Assert.AreEqual(_connectionString, subsegment.Sql["connection_string"]); 146 | Assert.AreEqual(connection.ServerVersion, subsegment.Sql["database_version"]); 147 | } 148 | 149 | private MockEntityFrameworkCoreDbContext GetTestEFContext() 150 | { 151 | var options = new DbContextOptionsBuilder() 152 | .UseSqlite(connection) 153 | .Options; 154 | var context = new MockEntityFrameworkCoreDbContext(options); 155 | context.Database.EnsureCreated(); 156 | 157 | return context; 158 | } 159 | } 160 | } 161 | #endif 162 | -------------------------------------------------------------------------------- /src/test/EntityFrameworkWithSqlDiagnosticListenerTest.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.XRay.Recorder.AutoInstrumentation.Unittests.Tools; 20 | using Amazon.XRay.Recorder.Core; 21 | using Microsoft.Data.Sqlite; 22 | using Microsoft.EntityFrameworkCore; 23 | using Microsoft.VisualStudio.TestTools.UnitTesting; 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Diagnostics; 27 | using System.Linq; 28 | 29 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests 30 | { 31 | [TestClass] 32 | public class EntityFrameworkWithSqlDiagnosticListenerTest : TestBase 33 | { 34 | private const string _connectionString = "datasource=:memory:"; 35 | 36 | private SqliteConnection connection = null; 37 | 38 | private static IDisposable _subscription; 39 | 40 | private static AWSXRayRecorder _recorder; 41 | 42 | [TestInitialize] 43 | public void TestInitialize() 44 | { 45 | _recorder = new AWSXRayRecorder(); 46 | AWSXRayRecorder.InitializeInstance(recorder: _recorder); 47 | 48 | // In-memory database only exists while the connection is open 49 | connection = new SqliteConnection("DataSource=:memory:"); 50 | connection.Open(); 51 | } 52 | 53 | [TestCleanup] 54 | public new void TestCleanup() 55 | { 56 | connection.Close(); 57 | base.TestCleanup(); 58 | _recorder.Dispose(); 59 | _recorder = null; 60 | _subscription.Dispose(); 61 | } 62 | 63 | [TestMethod] 64 | public void TestEFCoreRequestWithEntityFrameworkCoreAndSqlDiagnosticListener() 65 | { 66 | // EntityFramework request will first trigger EntityFrameworkCoreDiagnosticListener and then SqlDiagnosticListener, 67 | // With EntityFrameworkCoreDiagnosticListener, SqlDiagnosticListener will process EF Core request. 68 | var subscription = new List() 69 | { 70 | new EntityFrameworkCoreDiagnosticListener(), 71 | new SqlDiagnosticListener() 72 | }; 73 | 74 | _subscription = DiagnosticListener.AllListeners.Subscribe(new DiagnosticListenerObserver(subscription)); 75 | 76 | _recorder.BeginSegment("EFCoreRequestWithEntityFrameworkCoreAndSqlDiagnosticListener"); 77 | 78 | var context = GetTestEFContext(); 79 | 80 | var users = context.Users.Where(u => u.UserId == 1).ToList(); 81 | 82 | var segment = _recorder.TraceContext.GetEntity(); 83 | Assert.AreEqual(4, segment.Subsegments.Count); 84 | var subsegment = segment.Subsegments[3]; 85 | Assert.IsNotNull(subsegment); 86 | Assert.IsNotNull(subsegment.Sql); 87 | Assert.AreEqual(0, subsegment.Subsegments.Count); // No nested duplicate subsegment 88 | Assert.AreEqual("sqlite", subsegment.Sql["database_type"]); 89 | Assert.AreEqual(_connectionString, subsegment.Sql["connection_string"]); 90 | Assert.AreEqual(connection.ServerVersion, subsegment.Sql["database_version"]); 91 | _recorder.EndSegment(); 92 | } 93 | 94 | private MockEntityFrameworkCoreDbContext GetTestEFContext() 95 | { 96 | var options = new DbContextOptionsBuilder() 97 | .UseSqlite(connection) 98 | .Options; 99 | var context = new MockEntityFrameworkCoreDbContext(options); 100 | context.Database.EnsureCreated(); 101 | 102 | return context; 103 | } 104 | } 105 | } 106 | #endif 107 | -------------------------------------------------------------------------------- /src/test/JSONs/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "XRay": { 3 | "DisableXRayTracing": "false", 4 | "UseRuntimeErrors": "true", 5 | "CollectSqlQueries": "false", 6 | "ServiceName": "UnittestSample", 7 | "TraceHttpRequests": "true", 8 | "TraceEFRequests": "false", 9 | "TraceSqlRequests": "true", 10 | "TraceAWSRequests": "false", 11 | "DaemonAddress": "127.0.0.1:2000" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/TestBase.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using Amazon.XRay.Recorder.Core; 19 | using Microsoft.VisualStudio.TestTools.UnitTesting; 20 | 21 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests 22 | { 23 | public class TestBase 24 | { 25 | protected static readonly string TraceId = Core.Internal.Entities.TraceId.NewId(); 26 | 27 | [TestCleanup] 28 | public void TestCleanup() 29 | { 30 | AWSXRayRecorder.Instance.TraceContext.ClearEntity(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/Tools/MockAWSXRayRecorder.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using Amazon.XRay.Recorder.Core; 19 | 20 | namespace Amazon.XRay.Recorder.AutoInstrumentation.UnitTests.Tools 21 | { 22 | public class MockAWSXRayRecorder : AWSXRayRecorder 23 | { 24 | public bool IsTracingDisabledValue { get; set; } 25 | 26 | public override bool IsTracingDisabled() 27 | { 28 | return IsTracingDisabledValue; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/Tools/MockEntityFrameworkCoreDbContext.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Microsoft.EntityFrameworkCore; 20 | 21 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests.Tools 22 | { 23 | public class MockEntityFrameworkCoreDbContext : DbContext 24 | { 25 | public MockEntityFrameworkCoreDbContext(DbContextOptions options) : base(options) { } 26 | 27 | public DbSet Users { get; set; } 28 | } 29 | 30 | public class User 31 | { 32 | public int UserId { get; set; } 33 | } 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /src/test/UtilTest.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.XRay.Recorder.AutoInstrumentation.Utils; 20 | using Microsoft.VisualStudio.TestTools.UnitTesting; 21 | using System.Data.Common; 22 | 23 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests 24 | { 25 | [TestClass] 26 | public class UtilTest : TestBase 27 | { 28 | private string SqlServerConnectionString = "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;port=1234;"; 29 | private string MySqlConnectionString = "server=localhost;database=temp;user=root;pwd=1234abcD*;port=1234;"; 30 | private string SqliteConnectionString = "Data Source=/ex1.db;port=1234;"; 31 | private string PostgreSqlConnectionString = "Host=localhost;Database=postgres;Userid=postgres;password=1234abcD*;Port=1234;"; 32 | private string FirebirdSqlConnectionString = "Username=SYSDBA;Password=masterkey;Database=/firebird.fdb;DataSource=localhost;port=1234;"; 33 | 34 | [TestCleanup] 35 | public new void TestCleanup() 36 | { 37 | base.TestCleanup(); 38 | } 39 | 40 | [TestMethod] 41 | public void TestGetUserIdMySql() 42 | { 43 | DbConnectionStringBuilder builder = new DbConnectionStringBuilder() 44 | { 45 | ConnectionString = MySqlConnectionString 46 | }; 47 | object result = AgentUtil.GetUserId(builder); 48 | Assert.AreEqual("root", result.ToString()); 49 | } 50 | 51 | [TestMethod] 52 | public void TestGetUserIdSqlServer() 53 | { 54 | DbConnectionStringBuilder builder = new DbConnectionStringBuilder() 55 | { 56 | ConnectionString = SqlServerConnectionString 57 | }; 58 | object result = AgentUtil.GetUserId(builder); 59 | Assert.AreEqual("myUsername", result.ToString()); 60 | } 61 | 62 | [TestMethod] 63 | public void TestGetUserIdSqlite() 64 | { 65 | DbConnectionStringBuilder builder = new DbConnectionStringBuilder() 66 | { 67 | ConnectionString = SqliteConnectionString 68 | }; 69 | object result = AgentUtil.GetUserId(builder); 70 | Assert.IsNull(result); 71 | } 72 | 73 | [TestMethod] 74 | public void TestGetUserIdPostgreSql() 75 | { 76 | DbConnectionStringBuilder builder = new DbConnectionStringBuilder() 77 | { 78 | ConnectionString = PostgreSqlConnectionString 79 | }; 80 | object result = AgentUtil.GetUserId(builder); 81 | Assert.AreEqual("postgres", result.ToString()); 82 | } 83 | 84 | [TestMethod] 85 | public void TestGetUserIdFirebirdSql() 86 | { 87 | DbConnectionStringBuilder builder = new DbConnectionStringBuilder() 88 | { 89 | ConnectionString = FirebirdSqlConnectionString 90 | }; 91 | object result = AgentUtil.GetUserId(builder); 92 | Assert.AreEqual("SYSDBA", result.ToString()); 93 | } 94 | } 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /src/test/XRayAutoInstrumentationOptionsTest.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | using Microsoft.VisualStudio.TestTools.UnitTesting; 19 | 20 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests 21 | { 22 | [TestClass] 23 | public class XRayAutoInstrumentationOptionsTest : TestBase 24 | { 25 | private XRayAutoInstrumentationOptions _options; 26 | 27 | [TestCleanup] 28 | public new void TestCleanup() 29 | { 30 | base.TestCleanup(); 31 | _options = null; 32 | } 33 | 34 | [TestMethod] 35 | public void TestXRayAutoInstrumentationOptionsDefaultValue() 36 | { 37 | // Default values 38 | _options = new XRayAutoInstrumentationOptions(); 39 | 40 | Assert.AreEqual("DefaultService", _options.ServiceName); // Default Value: "DefaultService" 41 | Assert.AreEqual("127.0.0.1:2000", _options.DaemonAddress); // Default Value: "DaemonAddress" 42 | Assert.IsTrue(_options.TraceHttpRequests); // Default Value : true 43 | Assert.IsTrue(_options.TraceAWSRequests); // Default Value : true 44 | Assert.IsTrue(_options.TraceSqlRequests); // Default Value : true 45 | Assert.IsTrue(_options.TraceEFRequests); // Default Value : true 46 | } 47 | 48 | [TestMethod] 49 | public void TestXRayAutoInstrumentationOptionsCustomizedValue() 50 | { 51 | _options = new XRayAutoInstrumentationOptions("TestApplication", "127.0.0.0:2000", false, true, false, true); 52 | 53 | Assert.AreEqual("TestApplication", _options.ServiceName); 54 | Assert.AreEqual("127.0.0.0:2000", _options.DaemonAddress); 55 | Assert.IsFalse(_options.TraceHttpRequests); 56 | Assert.IsTrue(_options.TraceAWSRequests); 57 | Assert.IsFalse(_options.TraceSqlRequests); 58 | Assert.IsTrue(_options.TraceEFRequests); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/XRayConfigurationNetstandardTest.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"). 6 | // You may not use this file except in compliance with the License. 7 | // A copy of the License is located at 8 | // 9 | // http://aws.amazon.com/apache2.0 10 | // 11 | // or in the "license" file accompanying this file. This file is distributed 12 | // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | // express or implied. See the License for the specific language governing 14 | // permissions and limitations under the License. 15 | // 16 | //----------------------------------------------------------------------------- 17 | 18 | #if !NET45 19 | using Amazon.XRay.Recorder.Core; 20 | using Microsoft.VisualStudio.TestTools.UnitTesting; 21 | 22 | namespace Amazon.XRay.Recorder.AutoInstrumentation.Unittests 23 | { 24 | [TestClass] 25 | class XRayConfigurationNetstandardTest : TestBase 26 | { 27 | [TestMethod] 28 | public void TestXRayConfigureNetstandard() 29 | { 30 | // Register the configurations from appsettings.json file in the unittest folder 31 | // Register the following items, if provided, for AWS XRay .Net Core SDK 32 | // "DisableXRayTracing" : bool 33 | // "SamplingRuleManifest" : string 34 | // "AWSXRayPlugins" : string 35 | // "AwsServiceHandlerManifest" : string 36 | // "UseRuntimeErrors" : bool 37 | // "CollectSqlQueries" : bool 38 | // AND register the following items, if provided, for Auto-instrumentation SDK 39 | // "ServiceName" : string 40 | // "DaemonAddress" : string 41 | // "TraceHttpRequests" : bool 42 | // "TraceAWSRequests" : bool 43 | // "TraceSqlRequests" : bool 44 | // "TraceEFReqeusts" : bool 45 | var xrayAutoInstrumentationoptions = XRayConfiguration.Register(); 46 | 47 | var _recorder = AWSXRayRecorder.Instance; 48 | 49 | Assert.IsFalse(_recorder.XRayOptions.IsXRayTracingDisabled); 50 | Assert.IsTrue(_recorder.XRayOptions.UseRuntimeErrors); 51 | Assert.IsFalse(_recorder.XRayOptions.CollectSqlQueries); 52 | Assert.AreEqual("UnittestSample", xrayAutoInstrumentationoptions.ServiceName); 53 | Assert.AreEqual("127.0.0.1:2000", xrayAutoInstrumentationoptions.DaemonAddress); 54 | Assert.IsTrue(xrayAutoInstrumentationoptions.TraceHttpRequests); 55 | Assert.IsFalse(xrayAutoInstrumentationoptions.TraceAWSRequests); 56 | Assert.IsTrue(xrayAutoInstrumentationoptions.TraceSqlRequests); 57 | Assert.IsFalse(xrayAutoInstrumentationoptions.TraceEFRequests); 58 | } 59 | } 60 | } 61 | #endif 62 | --------------------------------------------------------------------------------